chiark / gitweb /
util: fix bad memory access
[elogind.git] / src / shared / util.c
index 59d8544d053b9eca14e917e5c51c45ad5bb76603..8e1409671f258cc31968eb7ae42a382d9dce5fb6 100644 (file)
@@ -439,7 +439,6 @@ int get_parent_of_pid(pid_t pid, pid_t *_ppid) {
 
         if (!fgets(line, sizeof(line), f)) {
                 r = feof(f) ? -EIO : -errno;
-                fclose(f);
                 return r;
         }
 
@@ -905,13 +904,10 @@ int get_process_comm(pid_t pid, char **name) {
 }
 
 int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char **line) {
-        char *r, *k;
+        char *r = NULL, *k;
         int c;
-        bool space = false;
-        size_t left;
         FILE *f;
 
-        assert(max_length > 0);
         assert(line);
 
         if (pid == 0)
@@ -927,47 +923,64 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
 
         if (!f)
                 return -errno;
+        if (max_length == 0) {
+                size_t len = 1;
+                while ((c = getc(f)) != EOF) {
+                        k = realloc(r, len+1);
+                        if (k == NULL) {
+                                free(r);
+                                fclose(f);
+                                return -ENOMEM;
+                        }
+                        r = k;
+                        r[len-1] = isprint(c) ? c : ' ';
+                        r[len] = 0;
+                        len++;
+                }
+        } else {
+                bool space = false;
+                size_t left;
+                r = new(char, max_length);
+                if (!r) {
+                        fclose(f);
+                        return -ENOMEM;
+                }
 
-        r = new(char, max_length);
-        if (!r) {
-                fclose(f);
-                return -ENOMEM;
-        }
+                k = r;
+                left = max_length;
+                while ((c = getc(f)) != EOF) {
+
+                        if (isprint(c)) {
+                                if (space) {
+                                        if (left <= 4)
+                                                break;
 
-        k = r;
-        left = max_length;
-        while ((c = getc(f)) != EOF) {
+                                        *(k++) = ' ';
+                                        left--;
+                                        space = false;
+                                }
 
-                if (isprint(c)) {
-                        if (space) {
                                 if (left <= 4)
                                         break;
 
-                                *(k++) = ' ';
+                                *(k++) = (char) c;
                                 left--;
-                                space = false;
-                        }
-
-                        if (left <= 4)
-                                break;
+                        }  else
+                                space = true;
+                }
 
-                        *(k++) = (char) c;
-                        left--;
-                }  else
-                        space = true;
+                if (left <= 4) {
+                        size_t n = MIN(left-1, 3U);
+                        memcpy(k, "...", n);
+                        k[n] = 0;
+                } else
+                        *k = 0;
         }
 
-        if (left <= 4) {
-                size_t n = MIN(left-1, 3U);
-                memcpy(k, "...", n);
-                k[n] = 0;
-        } else
-                *k = 0;
-
         fclose(f);
 
         /* Kernel threads have no argv[] */
-        if (r[0] == 0) {
+        if (r == NULL || r[0] == 0) {
                 char *t;
                 int h;
 
@@ -4444,6 +4457,23 @@ int get_user_creds(
         return 0;
 }
 
+char* uid_to_name(uid_t uid) {
+        struct passwd *p;
+        char *r;
+
+        if (uid == 0)
+                return strdup("root");
+
+        p = getpwuid(uid);
+        if (p)
+                return strdup(p->pw_name);
+
+        if (asprintf(&r, "%lu", (unsigned long) uid) < 0)
+                return NULL;
+
+        return r;
+}
+
 int get_group_creds(const char **groupname, gid_t *gid) {
         struct group *g;
         gid_t id;
@@ -5282,9 +5312,13 @@ int can_sleep(const char *type) {
 
         assert(type);
 
+        /* If /sys is read-only we cannot sleep */
+        if (access("/sys/power/state", W_OK) < 0)
+                return false;
+
         r = read_one_line_file("/sys/power/state", &p);
         if (r < 0)
-                return r == -ENOENT ? 0 : r;
+                return false;
 
         k = strlen(type);
         FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state)
@@ -5302,9 +5336,14 @@ int can_sleep_disk(const char *type) {
 
         assert(type);
 
+        /* If /sys is read-only we cannot sleep */
+        if (access("/sys/power/state", W_OK) < 0 ||
+            access("/sys/power/disk", W_OK) < 0)
+                return false;
+
         r = read_one_line_file("/sys/power/disk", &p);
         if (r < 0)
-                return r == -ENOENT ? 0 : r;
+                return false;
 
         k = strlen(type);
         FOREACH_WORD_SEPARATOR(w, l, p, WHITESPACE, state) {
@@ -5673,7 +5712,7 @@ oom:
 }
 
 char *strip_tab_ansi(char **ibuf, size_t *_isz) {
-        const char *i, *begin;
+        const char *i, *begin = NULL;
         enum {
                 STATE_OTHER,
                 STATE_ESCAPE,
@@ -5754,3 +5793,81 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz) {
 
         return obuf;
 }
+
+int on_ac_power(void) {
+        bool found_offline = false, found_online = false;
+        _cleanup_closedir_ DIR *d = NULL;
+
+        d = opendir("/sys/class/power_supply");
+        if (!d)
+                return -errno;
+
+        for (;;) {
+                struct dirent *de;
+                union dirent_storage buf;
+                _cleanup_free_ char *p = NULL;
+                _cleanup_close_ int fd = -1, device = -1;
+                char contents[6];
+                ssize_t n;
+                int k;
+
+                k = readdir_r(d, &buf.de, &de);
+                if (k != 0)
+                        return -k;
+
+                if (!de)
+                        break;
+
+                if (ignore_file(de->d_name))
+                        continue;
+
+                device = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (device < 0) {
+                        if (errno == ENOENT || errno == ENOTDIR)
+                                continue;
+
+                        return -errno;
+                }
+
+                fd = openat(device, "type", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        return -errno;
+                }
+
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
+
+                if (n != 6 || memcmp(contents, "Mains\n", 6))
+                        continue;
+
+                close_nointr_nofail(fd);
+                fd = openat(device, "online", O_RDONLY|O_CLOEXEC|O_NOCTTY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
+
+                        return -errno;
+                }
+
+                n = read(fd, contents, sizeof(contents));
+                if (n < 0)
+                        return -errno;
+
+                if (n != 2 || contents[1] != '\n')
+                        return -EIO;
+
+                if (contents[0] == '1') {
+                        found_online = true;
+                        break;
+                } else if (contents[0] == '0')
+                        found_offline = true;
+                else
+                        return -EIO;
+        }
+
+        return found_online || !found_offline;
+}