device: Combine two if statements with identical outcome
[framework/connectivity/connman.git] / src / timezone.c
index 9fa1444..173d658 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  Connection Manager
  *
- *  Copyright (C) 2007-2010  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
@@ -23,6 +23,8 @@
 #include <config.h>
 #endif
 
+#define _GNU_SOURCE
+#include <errno.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <unistd.h>
@@ -48,7 +50,7 @@ static char *read_key_file(const char *pathname, const char *key)
        off_t ptrlen, keylen;
        int fd;
 
-       fd = open(pathname, O_RDONLY);
+       fd = open(pathname, O_RDONLY | O_CLOEXEC);
        if (fd < 0)
                return NULL;
 
@@ -120,7 +122,7 @@ static int compare_file(void *src_map, struct stat *src_st,
        void *dst_map;
        int fd, result;
 
-       fd = open(pathname, O_RDONLY);
+       fd = open(pathname, O_RDONLY | O_CLOEXEC);
        if (fd < 0)
                return -1;
 
@@ -184,9 +186,10 @@ static char *find_origin(void *src_map, struct stat *src_st,
                                                        subpath, d->d_name);
 
                        if (compare_file(src_map, src_st, pathname) == 0) {
-                               closedir(dir);
-                               return g_strdup_printf("%s/%s",
+                               str = g_strdup_printf("%s/%s",
                                                        subpath, d->d_name);
+                               closedir(dir);
+                               return str;
                        }
                        break;
                case DT_DIR:
@@ -221,7 +224,7 @@ char *__connman_timezone_lookup(void)
 
        DBG("sysconfig zone %s", zone);
 
-       fd = open(ETC_LOCALTIME, O_RDONLY);
+       fd = open(ETC_LOCALTIME, O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
                g_free(zone);
                return NULL;
@@ -268,6 +271,67 @@ done:
        return zone;
 }
 
+static int write_file(void *src_map, struct stat *src_st, const char *pathname)
+{
+       struct stat st;
+       int fd;
+       ssize_t written;
+
+       DBG("pathname %s", pathname);
+
+       if (lstat(pathname, &st) == 0) {
+               if (S_ISLNK(st.st_mode))
+                       unlink(pathname);
+       }
+
+       fd = open(pathname, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
+       if (fd < 0)
+               return -EIO;
+
+       written = write(fd, src_map, src_st->st_size);
+
+       close(fd);
+
+       if (written < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int __connman_timezone_change(const char *zone)
+{
+       struct stat st;
+       char *map, pathname[PATH_MAX];
+       int fd, err;
+
+       DBG("zone %s", zone);
+
+       snprintf(pathname, PATH_MAX, "%s/%s", USR_SHARE_ZONEINFO, zone);
+
+       fd = open(pathname, O_RDONLY | O_CLOEXEC);
+       if (fd < 0)
+               return -EINVAL;
+
+       if (fstat(fd, &st) < 0) {
+               close(fd);
+               return -EIO;
+       }
+
+       map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+       if (map == NULL || map == MAP_FAILED) {
+               close(fd);
+               return -EIO;
+       }
+
+       err = write_file(map, &st, ETC_LOCALTIME);
+
+       munmap(map, st.st_size);
+
+       close(fd);
+
+       return err;
+}
+
 static guint inotify_watch = 0;
 
 static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
@@ -298,7 +362,7 @@ static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
                return FALSE;
        }
 
-       DBG("bytes read %ld", bytes_read);
+       DBG("bytes read %zd", bytes_read);
 
        while (bytes_read > 0) {
                struct inotify_event *event = ptr;
@@ -356,10 +420,13 @@ int __connman_timezone_init(void)
        dirname = g_path_get_dirname(ETC_LOCALTIME);
 
        wd = inotify_add_watch(fd, dirname, IN_DONT_FOLLOW |
-                                               IN_MODIFY | IN_MOVED_TO);
+                                               IN_CLOSE_WRITE | IN_MOVED_TO);
 
        g_free(dirname);
 
+       if (wd < 0)
+               return -EIO;
+
        return 0;
 }