chiark / gitweb /
sd-daemon: Add sd_is_special for special file descriptors
[elogind.git] / src / util.c
index 021be62547a9ef82ec548ac45944a233d685d147..4046938fcdbef876c9dfdee5f3bfc8d3faf52cfa 100644 (file)
@@ -51,6 +51,8 @@
 #include <dlfcn.h>
 #include <sys/wait.h>
 #include <sys/capability.h>
+#include <sys/time.h>
+#include <linux/rtc.h>
 
 #include "macro.h"
 #include "util.h"
@@ -4449,16 +4451,27 @@ int terminal_vhangup(const char *name) {
 int vt_disallocate(const char *name) {
         int fd, r;
         unsigned u;
-        int temporary_vt, temporary_fd;
-        char tpath[64];
-        struct vt_stat vt_stat;
 
         /* Deallocate the VT if possible. If not possible
          * (i.e. because it is the active one), at least clear it
          * entirely (including the scrollback buffer) */
 
-        if (!tty_is_vc(name))
-                return -EIO;
+        if (!startswith(name, "/dev/"))
+                return -EINVAL;
+
+        if (!tty_is_vc(name)) {
+                /* So this is not a VT. I guess we cannot deallocate
+                 * it then. But let's at least clear the screen */
+
+                fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+                if (fd < 0)
+                        return fd;
+
+                loop_write(fd, "\033[H\033[2J", 7, false); /* clear screen */
+                close_nointr_nofail(fd);
+
+                return 0;
+        }
 
         if (!startswith(name, "/dev/tty"))
                 return -EINVAL;
@@ -4468,79 +4481,33 @@ int vt_disallocate(const char *name) {
                 return r;
 
         if (u <= 0)
-                return -EIO;
+                return -EINVAL;
 
+        /* Try to deallocate */
         fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
         if (fd < 0)
                 return fd;
 
         r = ioctl(fd, VT_DISALLOCATE, u);
-        if (r >= 0) {
-                close_nointr_nofail(fd);
-                return 0;
-        }
-
-        if (errno != EBUSY) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
-
-        if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0) {
-                close_nointr_nofail(fd);
-                return -errno;
-        }
+        close_nointr_nofail(fd);
 
-        if (u != vt_stat.v_active) {
-                close_nointr_nofail(fd);
-                return -EBUSY;
-        }
+        if (r >= 0)
+                return 0;
 
-        if (ioctl(fd, VT_OPENQRY, &temporary_vt) < 0) {
-                close_nointr_nofail(fd);
+        if (errno != EBUSY)
                 return -errno;
-        }
 
-        if (temporary_vt <= 0) {
-                close_nointr_nofail(fd);
-                return -EIO;
-        }
-
-        /* Switch to temporary VT */
-        snprintf(tpath, sizeof(tpath), "/dev/tty%i", temporary_vt);
-        char_array_0(tpath);
-        temporary_fd = open_terminal(tpath, O_RDWR|O_NOCTTY|O_CLOEXEC);
-        ioctl(fd, VT_ACTIVATE, temporary_vt);
-        if (temporary_fd >= 0)
-                close_nointr_nofail(temporary_fd);
-
-        /* Reopen /dev/tty0 */
-        close_nointr_nofail(fd);
-        fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
+        /* Couldn't deallocate, so let's clear it fully with
+         * scrollback */
+        fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
         if (fd < 0)
-                r = -errno;
-        else {
-                /* Disallocate the real VT */
-                if (ioctl(fd, VT_DISALLOCATE, u) < 0)
-                        r = -errno;
-                else
-                        r = 0;
-        }
-
-        /* Recreate original VT */
-        temporary_fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
-
-        if (temporary_fd >= 0) {
-                loop_write(temporary_fd, "\033[H\033[2J", 7, false); /* clear screen explicitly */
-                close_nointr_nofail(temporary_fd);
-        }
+                return fd;
 
-        /* Switch back to original VT */
-        if (fd >= 0) {
-                ioctl(fd, VT_ACTIVATE, vt_stat.v_active);
-                close_nointr_nofail(fd);
-        }
+        /* Requires Linux 2.6.40 */
+        loop_write(fd, "\033[H\033[3J", 7, false); /* clear screen including scrollback */
+        close_nointr_nofail(fd);
 
-        return r;
+        return 0;
 }
 
 static const char *const ioprio_class_table[] = {
@@ -4796,3 +4763,81 @@ finish:
         *strv = files;
         return r;
 }
+
+bool hwclock_is_localtime(void) {
+        FILE *f;
+        char line[LINE_MAX];
+        bool local = false;
+
+        /*
+         * The third line of adjtime is "UTC" or "LOCAL" or nothing.
+         *   # /etc/adjtime
+         *   0.0 0 0.0
+         *   0
+         *   UTC
+         */
+        f = fopen("/etc/adjtime", "re");
+        if (f) {
+                if (fgets(line, sizeof(line), f) &&
+                    fgets(line, sizeof(line), f) &&
+                    fgets(line, sizeof(line), f) ) {
+                            if (!strcmp(line, "LOCAL\n"))
+                                 local = true;
+                }
+                fclose(f);
+        }
+        return local;
+}
+
+int hwclock_apply_localtime_delta(void) {
+        const struct timeval *tv_null = NULL;
+        struct timeval tv;
+        struct tm *tm;
+        int minuteswest;
+        struct timezone tz;
+
+        gettimeofday(&tv, NULL);
+        tm = localtime(&tv.tv_sec);
+        minuteswest = tm->tm_gmtoff / 60;
+
+        tz.tz_minuteswest = -minuteswest;
+        tz.tz_dsttime = 0; /* DST_NONE*/
+
+        /*
+         * If the hardware clock does not run in UTC, but in local time:
+         * The very first time we set the kernel's timezone, it will warp
+         * the clock so that it runs in UTC instead of local time.
+         */
+        if (settimeofday(tv_null, &tz) < 0)
+                return -errno;
+        else
+                return minuteswest;
+}
+
+int hwclock_get_time(struct tm *tm) {
+        int fd;
+        int err = 0;
+
+        fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+        if (ioctl(fd, RTC_RD_TIME, tm) < 0)
+                err = -errno;
+        close(fd);
+
+        return err;
+}
+
+int hwclock_set_time(const struct tm *tm) {
+        int fd;
+        int err = 0;
+
+        fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
+        if (fd < 0)
+                return -errno;
+        if (ioctl(fd, RTC_SET_TIME, tm) < 0)
+                err = -errno;
+        close(fd);
+
+        return err;
+}