chiark / gitweb /
logind: make seat device management accessible to normal users/via polkit
[elogind.git] / src / util.c
index de5feeb8d03eb4a2db31f929d167a5b99c29a63b..11f77abde14412f50c6032d56c3616e2444a103d 100644 (file)
@@ -1100,6 +1100,37 @@ int get_process_cmdline(pid_t pid, size_t max_length, bool comm_fallback, char *
         return 0;
 }
 
+int is_kernel_thread(pid_t pid) {
+        char *p;
+        size_t count;
+        char c;
+        bool eof;
+        FILE *f;
+
+        if (pid == 0)
+                return 0;
+
+        if (asprintf(&p, "/proc/%lu/cmdline", (unsigned long) pid) < 0)
+                return -ENOMEM;
+
+        f = fopen(p, "re");
+        free(p);
+
+        if (!f)
+                return -errno;
+
+        count = fread(&c, 1, 1, f);
+        eof = feof(f);
+        fclose(f);
+
+        /* Kernel threads have an empty cmdline */
+
+        if (count <= 0)
+                return eof ? 1 : -errno;
+
+        return 0;
+}
+
 int get_process_exe(pid_t pid, char **name) {
         int r;
 
@@ -2403,7 +2434,7 @@ fail:
         return r;
 }
 
-int read_one_char(FILE *f, char *ret, bool *need_nl) {
+int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) {
         struct termios old_termios, new_termios;
         char c;
         char line[LINE_MAX];
@@ -2421,6 +2452,13 @@ int read_one_char(FILE *f, char *ret, bool *need_nl) {
                 if (tcsetattr(fileno(f), TCSADRAIN, &new_termios) >= 0) {
                         size_t k;
 
+                        if (t != (usec_t) -1) {
+                                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0) {
+                                        tcsetattr(fileno(f), TCSADRAIN, &old_termios);
+                                        return -ETIMEDOUT;
+                                }
+                        }
+
                         k = fread(&c, 1, 1, f);
 
                         tcsetattr(fileno(f), TCSADRAIN, &old_termios);
@@ -2436,7 +2474,11 @@ int read_one_char(FILE *f, char *ret, bool *need_nl) {
                 }
         }
 
-        if (!(fgets(line, sizeof(line), f)))
+        if (t != (usec_t) -1)
+                if (fd_wait_for_event(fileno(f), POLLIN, t) <= 0)
+                        return -ETIMEDOUT;
+
+        if (!fgets(line, sizeof(line), f))
                 return -EIO;
 
         truncate_nl(line);
@@ -2478,7 +2520,8 @@ int ask(char *ret, const char *replies, const char *text, ...) {
 
                 fflush(stdout);
 
-                if ((r = read_one_char(stdin, &c, &need_nl)) < 0) {
+                r = read_one_char(stdin, &c, (usec_t) -1, &need_nl);
+                if (r < 0) {
 
                         if (r == -EBADMSG) {
                                 puts("Bad input, please try again.");
@@ -2501,7 +2544,7 @@ int ask(char *ret, const char *replies, const char *text, ...) {
         }
 }
 
-int reset_terminal_fd(int fd) {
+int reset_terminal_fd(int fd, bool switch_to_text) {
         struct termios termios;
         int r = 0;
 
@@ -2517,7 +2560,8 @@ int reset_terminal_fd(int fd) {
         ioctl(fd, TIOCNXCL);
 
         /* Switch to text mode */
-        ioctl(fd, KDSETMODE, KD_TEXT);
+        if (switch_to_text)
+                ioctl(fd, KDSETMODE, KD_TEXT);
 
         /* Enable console unicode mode */
         ioctl(fd, KDSKBMODE, K_UNICODE);
@@ -2571,7 +2615,7 @@ int reset_terminal(const char *name) {
         if (fd < 0)
                 return fd;
 
-        r = reset_terminal_fd(fd);
+        r = reset_terminal_fd(fd, true);
         close_nointr_nofail(fd);
 
         return r;
@@ -2765,7 +2809,8 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
         if (notify >= 0)
                 close_nointr_nofail(notify);
 
-        if ((r = reset_terminal_fd(fd)) < 0)
+        r = reset_terminal_fd(fd, true);
+        if (r < 0)
                 log_warning("Failed to reset terminal: %s", strerror(-r));
 
         return fd;
@@ -3218,11 +3263,15 @@ fallback:
 void rename_process(const char name[8]) {
         assert(name);
 
-        prctl(PR_SET_NAME, name);
+        /* This is a like a poor man's setproctitle(). It changes the
+         * comm field, argv[0], and also the glibc's internally used
+         * name of the process. For the first one a limit of 16 chars
+         * applies, to the second one usually one of 10 (i.e. length
+         * of "/sbin/init"), to the third one one of 7 (i.e. length of
+         * "systemd"). If you pass a longer string it will be
+         * truncated */
 
-        /* This is a like a poor man's setproctitle(). The string
-         * passed should fit in 7 chars (i.e. the length of
-         * "systemd") */
+        prctl(PR_SET_NAME, name);
 
         if (program_invocation_name)
                 strncpy(program_invocation_name, name, strlen(program_invocation_name));
@@ -4048,6 +4097,39 @@ unsigned columns(void) {
         return parsed_columns;
 }
 
+int fd_lines(int fd) {
+        struct winsize ws;
+        zero(ws);
+
+        if (ioctl(fd, TIOCGWINSZ, &ws) < 0)
+                return -errno;
+
+        if (ws.ws_row <= 0)
+                return -EIO;
+
+        return ws.ws_row;
+}
+
+unsigned lines(void) {
+        static __thread int parsed_lines = 0;
+        const char *e;
+
+        if (_likely_(parsed_lines > 0))
+                return parsed_lines;
+
+        e = getenv("LINES");
+        if (e)
+                parsed_lines = atoi(e);
+
+        if (parsed_lines <= 0)
+                parsed_lines = fd_lines(STDOUT_FILENO);
+
+        if (parsed_lines <= 0)
+                parsed_lines = 25;
+
+        return parsed_lines;
+}
+
 int running_in_chroot(void) {
         struct stat a, b;
 
@@ -4541,11 +4623,12 @@ void execute_directory(const char *directory, DIR *d, char *argv[]) {
         }
 
         while (!hashmap_isempty(pids)) {
+                pid_t pid = PTR_TO_UINT(hashmap_first_key(pids));
                 siginfo_t si;
                 char *path;
 
                 zero(si);
-                if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
+                if (waitid(P_PID, pid, &si, WEXITED) < 0) {
 
                         if (errno == EINTR)
                                 continue;
@@ -4819,7 +4902,7 @@ int pipe_eof(int fd) {
         return pollfd.revents & POLLHUP;
 }
 
-int fd_wait_for_event(int fd, int event) {
+int fd_wait_for_event(int fd, int event, usec_t t) {
         struct pollfd pollfd;
         int r;
 
@@ -4827,7 +4910,7 @@ int fd_wait_for_event(int fd, int event) {
         pollfd.fd = fd;
         pollfd.events = event;
 
-        r = poll(&pollfd, 1, -1);
+        r = poll(&pollfd, 1, t == (usec_t) -1 ? -1 : (int) (t / USEC_PER_MSEC));
         if (r < 0)
                 return -errno;
 
@@ -5159,8 +5242,14 @@ int rtc_open(int flags) {
         int fd;
         DIR *d;
 
-        /* We open the first RTC which has hctosys=1 set. If we don't
-         * find any we just take the first one */
+        /* First, we try to make use of the /dev/rtc symlink. If that
+         * doesn't exist, we open the first RTC which has hctosys=1
+         * set. If we don't find any we just take the first RTC that
+         * exists at all. */
+
+        fd = open("/dev/rtc", flags);
+        if (fd >= 0)
+                return fd;
 
         d = opendir("/sys/class/rtc");
         if (!d)
@@ -6197,3 +6286,39 @@ void* memdup(const void *p, size_t l) {
         memcpy(r, p, l);
         return r;
 }
+
+int fd_inc_sndbuf(int fd, size_t n) {
+        int r, value;
+        socklen_t l = sizeof(value);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &l);
+        if (r >= 0 &&
+            l == sizeof(value) &&
+            (size_t) value >= n*2)
+                return 0;
+
+        value = (int) n;
+        r = setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value));
+        if (r < 0)
+                return -errno;
+
+        return 1;
+}
+
+int fd_inc_rcvbuf(int fd, size_t n) {
+        int r, value;
+        socklen_t l = sizeof(value);
+
+        r = getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &l);
+        if (r >= 0 &&
+            l == sizeof(value) &&
+            (size_t) value >= n*2)
+                return 0;
+
+        value = (int) n;
+        r = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, sizeof(value));
+        if (r < 0)
+                return -errno;
+
+        return 1;
+}