16 # define TIMESTAMP_DIR "/tmp/doas"
19 # define TMPFS_MAGIC 0x01021994
22 #define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
23 #define timespeccmp(tsp, usp, cmp) \
24 (((tsp)->tv_sec == (usp)->tv_sec) ? \
25 ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
26 ((tsp)->tv_sec cmp (usp)->tv_sec))
27 #define timespecadd(tsp, usp, vsp) do { \
28 (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
29 (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
30 if ((vsp)->tv_nsec >= 1000000000L) { \
32 (vsp)->tv_nsec -= 1000000000L; \
39 char *path, *tty, *ttynorm, *p;
40 if (!(tty = ttyname(0))
41 && !(tty = ttyname(1))
42 && !(tty = ttyname(2)))
44 if (!(ttynorm = strdup(tty)))
46 for (p = ttynorm; *p; p++)
49 if (asprintf(&path, "%s/.%s_%d", TIMESTAMP_DIR, ttynorm, getppid()) == -1)
56 checktsdir(const char *path)
63 if (!(buf = strdup(path)))
68 if (lstat(dir, &st) == -1) {
69 if (errno == ENOENT) {
73 if (mkdir(dir, (S_IRUSR|S_IWUSR|S_IXUSR)) != 0)
75 if (setegid(gid) != 0)
83 if ((st.st_mode & S_IFMT) != S_IFDIR)
84 errx(1, "timestamp directory is not a directory");
85 if ((st.st_mode & (S_IWGRP|S_IRGRP|S_IWOTH|S_IROTH)) != 0)
86 errx(1, "timestamp directory permissions wrong");
87 if (st.st_uid != 0 || st.st_gid != 0)
88 errx(1, "timestamp directory is not owned by root");
89 if (statfs(dir, &sf) == -1)
91 if (sf.f_type != TMPFS_MAGIC)
92 errx(1, "timestamp directory not on tmpfs");
99 timestamp_read(int fd, struct timespec *mono, struct timespec *real)
101 if (read(fd, (void *)mono, sizeof *mono) != sizeof *mono ||
102 read(fd, (void *)real, sizeof *real) != sizeof *mono)
104 if (!timespecisset(mono) || !timespecisset(real))
105 errx(1, "timespecisset");
110 persist_check(int fd, int secs)
112 struct timespec mono, real, ts_mono, ts_real, timeout;
114 if (timestamp_read(fd, &ts_mono, &ts_real) != 0)
117 if (clock_gettime(CLOCK_MONOTONIC, &mono) != 0 || !timespecisset(&mono))
118 err(1, "clock_gettime(CLOCK_MONOTONIC, ?)");
119 if (clock_gettime(CLOCK_REALTIME, &real) != 0 || !timespecisset(&real))
120 err(1, "clock_gettime(CLOCK_REALTIME, ?)");
122 if (timespeccmp(&mono, &ts_mono, >) ||
123 timespeccmp(&real, &ts_real, >))
126 memset(&timeout, 0, sizeof timeout);
127 timeout.tv_sec = secs;
128 timespecadd(&timeout, &mono, &mono);
129 timespecadd(&timeout, &real, &real);
131 if (timespeccmp(&mono, &ts_mono, <) ||
132 timespeccmp(&real, &ts_real, <))
133 errx(1, "timestamp is too far in the future");
139 persist_set(int fd, int secs)
141 struct timespec mono, real, ts_mono, ts_real, timeout;
143 if (clock_gettime(CLOCK_MONOTONIC, &mono) != 0 || !timespecisset(&mono))
144 err(1, "clock_gettime(XLOCK_MONOTONIC, ?)");
145 if (clock_gettime(CLOCK_REALTIME, &real) != 0 || !timespecisset(&real))
146 err(1, "clock_gettime(CLOCK_REALTIME, ?)");
148 memset(&timeout, 0, sizeof timeout);
149 timeout.tv_sec = secs;
150 timespecadd(&timeout, &mono, &ts_mono);
151 timespecadd(&timeout, &real, &ts_real);
153 if (lseek(fd, 0, SEEK_SET) == -1)
155 if (write(fd, (void *)&ts_mono, sizeof ts_mono) != sizeof ts_mono ||
156 write(fd, (void *)&ts_real, sizeof ts_real) != sizeof ts_real)
163 persist_open(int *valid, int secs)
171 if (checktsdir(path))
172 errx(1, "checktsdir");
174 if ((fd = open(path, (O_RDWR), (S_IRUSR|S_IWUSR))) == -1)
176 err(1, "open: %s", path);
179 if ((fd = open(path, (O_RDWR|O_CREAT|O_EXCL), (S_IRUSR|S_IWUSR))) == -1)
180 err(1, "open: %s", path);
185 if (fstat(fd, &st) == -1)
187 if ((st.st_mode & S_IFMT) != S_IFREG)
188 errx(1, "timestamp is not a file");
189 if ((st.st_mode & (S_IWGRP|S_IRGRP|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH)) != 0)
190 errx(1, "timestamp permissions wrong");
193 if (st.st_uid != 0 || st.st_gid != gid)
194 errx(1, "timestamp has wrong owner");
196 if (st.st_size == 0) {
201 if (st.st_size != sizeof(struct timespec) * 2)
202 errx(1, "corrupt timestamp file");
204 *valid = persist_check(fd, secs) == 0;
214 if (unlink(path) == -1 && errno != ENOENT)