When running at jobs, open the at spool and use the directory fd
authormillert <millert@openbsd.org>
Wed, 7 Jun 2017 17:59:36 +0000 (17:59 +0000)
committermillert <millert@openbsd.org>
Wed, 7 Jun 2017 17:59:36 +0000 (17:59 +0000)
with openat(), fstatat() and unlinkat().  This is similar to how
we run cron jobs and eliminates the need for run_job() to find the
basename of the at file.  OK deraadt@

usr.sbin/cron/atrun.c

index 78798b9..d1414d4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: atrun.c,v 1.43 2016/01/11 14:23:50 millert Exp $      */
+/*     $OpenBSD: atrun.c,v 1.44 2017/06/07 17:59:36 millert Exp $      */
 
 /*
  * Copyright (c) 2002-2003 Todd C. Miller <Todd.Miller@courtesan.com>
@@ -51,7 +51,7 @@
 #include "funcs.h"
 #include "globals.h"
 
-static void run_job(atjob *, char *);
+static void run_job(const atjob *, int, const char *);
 
 static int
 strtot(const char *nptr, char **endptr, time_t *tp)
@@ -169,20 +169,32 @@ atrun(at_db *db, double batch_maxload, time_t now)
        char atfile[PATH_MAX];
        struct stat sb;
        double la;
+       int dfd, len;
        atjob *job, *tjob, *batch = NULL;
 
        if (db == NULL)
                return;
 
+       if ((dfd = open(_PATH_AT_SPOOL, O_RDONLY|O_DIRECTORY)) == -1) {
+               syslog(LOG_ERR, "(CRON) OPEN FAILED (%s)", _PATH_AT_SPOOL);
+               return;
+       }
+
        TAILQ_FOREACH_SAFE(job, &db->jobs, entries, tjob) {
                /* Skip jobs in the future */
                if (job->run_time > now)
                        continue;
 
-               snprintf(atfile, sizeof(atfile), "%s/%lld.%c", _PATH_AT_SPOOL,
+               len = snprintf(atfile, sizeof(atfile), "%lld.%c",
                    (long long)job->run_time, job->queue);
+               if (len >= sizeof(atfile)) {
+                       TAILQ_REMOVE(&db->jobs, job, entries);
+                       free(job);
+                       continue;
+               }
 
-               if (lstat(atfile, &sb) != 0 || !S_ISREG(sb.st_mode)) {
+               if (fstatat(dfd, atfile, &sb, AT_SYMLINK_NOFOLLOW) != 0 ||
+                   !S_ISREG(sb.st_mode)) {
                        TAILQ_REMOVE(&db->jobs, job, entries);
                        free(job);
                        continue;               /* disapeared or not a file */
@@ -200,7 +212,7 @@ atrun(at_db *db, double batch_maxload, time_t now)
                                        batch = job;
                        } else {
                                /* normal at job */
-                               run_job(job, atfile);
+                               run_job(job, dfd, atfile);
                                TAILQ_REMOVE(&db->jobs, job, entries);
                                free(job);
                        }
@@ -212,19 +224,22 @@ atrun(at_db *db, double batch_maxload, time_t now)
            && (batch_maxload == 0.0 ||
            ((getloadavg(&la, 1) == 1) && la <= batch_maxload))
            ) {
-               snprintf(atfile, sizeof(atfile), "%s/%lld.%c", _PATH_AT_SPOOL,
+               len = snprintf(atfile, sizeof(atfile), "%lld.%c",
                    (long long)batch->run_time, batch->queue);
-               run_job(batch, atfile);
+               if (len < sizeof(atfile))
+                       run_job(batch, dfd, atfile);
                TAILQ_REMOVE(&db->jobs, batch, entries);
                free(job);
        }
+
+       close(dfd);
 }
 
 /*
  * Run the specified job contained in atfile.
  */
 static void
-run_job(atjob *job, char *atfile)
+run_job(const atjob *job, int dfd, const char *atfile)
 {
        struct stat sb;
        struct passwd *pw;
@@ -241,15 +256,11 @@ run_job(atjob *job, char *atfile)
        char *nargv[2], *nenvp[1];
 
        /* Open the file and unlink it so we don't try running it again. */
-       if ((fd = open(atfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) {
+       if ((fd = openat(dfd, atfile, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) {
                syslog(LOG_ERR, "(CRON) CAN'T OPEN (%s)", atfile);
                return;
        }
-       unlink(atfile);
-
-       /* We don't want the atjobs dir in the log messages. */
-       if ((cp = strrchr(atfile, '/')) != NULL)
-               atfile = cp + 1;
+       unlinkat(dfd, atfile, 0);
 
        /* Fork so other pending jobs don't have to wait for us to finish. */
        switch (fork()) {