From: millert Date: Wed, 7 Jun 2017 17:59:36 +0000 (+0000) Subject: When running at jobs, open the at spool and use the directory fd X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=f64f78fdcec057c9198eb39401b383191138d63d;p=openbsd When running at jobs, open the at spool and use the directory fd 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@ --- diff --git a/usr.sbin/cron/atrun.c b/usr.sbin/cron/atrun.c index 78798b960ff..d1414d42592 100644 --- a/usr.sbin/cron/atrun.c +++ b/usr.sbin/cron/atrun.c @@ -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 @@ -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()) {