chiark / gitweb /
logind: properly handle if two session with identical loginuids are attempted to...
[elogind.git] / src / util.c
index dfb153bbb6285258e5b0f6400a745a42ff816152..5d57d52dc8ba7763f5e9b52f699e8c839ad0eb60 100644 (file)
@@ -108,6 +108,28 @@ dual_timestamp* dual_timestamp_get(dual_timestamp *ts) {
         return ts;
 }
 
+dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) {
+        int64_t delta;
+        assert(ts);
+
+        ts->realtime = u;
+
+        if (u == 0)
+                ts->monotonic = 0;
+        else {
+                delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u;
+
+                ts->monotonic = now(CLOCK_MONOTONIC);
+
+                if ((int64_t) ts->monotonic > delta)
+                        ts->monotonic -= delta;
+                else
+                        ts->monotonic = 0;
+        }
+
+        return ts;
+}
+
 usec_t timespec_load(const struct timespec *ts) {
         assert(ts);
 
@@ -4018,8 +4040,31 @@ bool tty_is_vc(const char *tty) {
         if (startswith(tty, "/dev/"))
                 tty += 5;
 
-        return startswith(tty, "tty") &&
-                tty[3] >= '0' && tty[3] <= '9';
+        return vtnr_from_tty(tty) >= 0;
+}
+
+int vtnr_from_tty(const char *tty) {
+        int i, r;
+
+        assert(tty);
+
+        if (startswith(tty, "/dev/"))
+                tty += 5;
+
+        if (!startswith(tty, "tty") )
+                return -EINVAL;
+
+        if (tty[3] < '0' || tty[3] > '9')
+                return -EINVAL;
+
+        r = safe_atoi(tty+3, &i);
+        if (r < 0)
+                return r;
+
+        if (i < 0 || i > 63)
+                return -EINVAL;
+
+        return i;
 }
 
 const char *default_term_for_tty(const char *tty) {
@@ -4785,40 +4830,50 @@ finish:
         return r;
 }
 
-bool hwclock_is_localtime(void) {
+int 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.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;
-                }
+                char line[LINE_MAX];
+                bool b;
+
+                b = fgets(line, sizeof(line), f) &&
+                        fgets(line, sizeof(line), f) &&
+                        fgets(line, sizeof(line), f);
+
                 fclose(f);
-        }
+
+                if (!b)
+                        return -EIO;
+
+
+                truncate_nl(line);
+                local = streq(line, "LOCAL");
+
+        } else if (errno != -ENOENT)
+                return -errno;
+
         return local;
 }
 
 int hwclock_apply_localtime_delta(void) {
         const struct timeval *tv_null = NULL;
-        struct timeval tv;
+        struct timespec ts;
         struct tm *tm;
         int minuteswest;
         struct timezone tz;
 
-        gettimeofday(&tv, NULL);
-        tm = localtime(&tv.tv_sec);
+        assert_se(clock_gettime(CLOCK_REALTIME, &ts) == 0);
+        assert_se(tm = localtime(&ts.tv_sec));
         minuteswest = tm->tm_gmtoff / 60;
 
         tz.tz_minuteswest = -minuteswest;
@@ -4831,20 +4886,43 @@ int hwclock_apply_localtime_delta(void) {
          */
         if (settimeofday(tv_null, &tz) < 0)
                 return -errno;
-        else
-                return minuteswest;
+
+        return minuteswest;
+}
+
+int hwclock_reset_localtime_delta(void) {
+        const struct timeval *tv_null = NULL;
+        struct timezone tz;
+
+        tz.tz_minuteswest = 0;
+        tz.tz_dsttime = 0; /* DST_NONE*/
+
+        if (settimeofday(tv_null, &tz) < 0)
+                return -errno;
+
+        return 0;
 }
 
 int hwclock_get_time(struct tm *tm) {
         int fd;
         int err = 0;
 
+        assert(tm);
+
         fd = open("/dev/rtc0", O_RDONLY|O_CLOEXEC);
         if (fd < 0)
                 return -errno;
+
+        /* This leaves the timezone fields of struct tm
+         * uninitialized! */
         if (ioctl(fd, RTC_RD_TIME, tm) < 0)
                 err = -errno;
-        close(fd);
+
+        /* We don't now daylight saving, so we reset this in order not
+         * to confused mktime(). */
+        tm->tm_isdst = -1;
+
+        close_nointr_nofail(fd);
 
         return err;
 }
@@ -4853,12 +4931,16 @@ int hwclock_set_time(const struct tm *tm) {
         int fd;
         int err = 0;
 
+        assert(tm);
+
         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);
+
+        close_nointr_nofail(fd);
 
         return err;
 }
@@ -5009,6 +5091,38 @@ int symlink_or_copy_atomic(const char *from, const char *to) {
         return r;
 }
 
+int audit_session_from_pid(pid_t pid, uint32_t *id) {
+        char *p, *s;
+        uint32_t u;
+        int r;
+
+        assert(pid >= 1);
+        assert(id);
+
+        if (have_effective_cap(CAP_AUDIT_CONTROL) <= 0)
+                return -ENOENT;
+
+        if (asprintf(&p, "/proc/%lu/sessionid", (unsigned long) pid) < 0)
+                return -ENOMEM;
+
+        r = read_one_line_file(p, &s);
+        free(p);
+        if (r < 0)
+                return r;
+
+        r = safe_atou32(s, &u);
+        free(s);
+
+        if (r < 0)
+                return r;
+
+        if (u == (uint32_t) -1 || u <= 0)
+                return -ENOENT;
+
+        *id = u;
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",