X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Futil.c;h=4046938fcdbef876c9dfdee5f3bfc8d3faf52cfa;hb=f8e08a77e7bbea802b50adcb442f99af462fa96e;hp=14aa1f97280a5a8f700a3cf7d1b2cd044c08bae8;hpb=6ea832a20700f5282c08c70f38422c6ab290a0b5;p=elogind.git diff --git a/src/util.c b/src/util.c index 14aa1f972..4046938fc 100644 --- a/src/util.c +++ b/src/util.c @@ -51,6 +51,8 @@ #include #include #include +#include +#include #include "macro.h" #include "util.h" @@ -2141,7 +2143,7 @@ bool fstype_is_network(const char *fstype) { int chvt(int vt) { int fd, r = 0; - if ((fd = open("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) + if ((fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0) return -errno; if (vt < 0) { @@ -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; +}