summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2002-05-14 18:05:40 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2002-05-14 18:05:40 +0000
commit08bdd093b4355d9008dac6b5cec89d39b2d71b79 (patch)
tree4a82520cc19050b278817d22b754a496d7334c8f
parent146815f3a476f9cc068bef652174b4c1c22a2aa4 (diff)
Major changes:
Job names are now "runtime.queue" where runtime is when the job will run in Unix time format. This is what SysV at does and allows us to nuke the .SEQ file. Historic BSD options for atq and atrm are now implemented; atq and atrm get their own man pages. At no longer does anything with the -v flag. We print the execution time when jobs are submitted so there is no need. Most *scanf() usage is gone (one remains in atrun). Better sanity checks in atrun. Random style/cleanup. With these changes we have the best of both worlds; POSIX compliance with the traditional BSD features.
-rw-r--r--etc/Makefile4
-rw-r--r--libexec/atrun/atrun.c133
-rw-r--r--usr.bin/at/Makefile12
-rw-r--r--usr.bin/at/at.148
-rw-r--r--usr.bin/at/at.c610
-rw-r--r--usr.bin/at/at.h12
-rw-r--r--usr.bin/at/atq.1107
-rw-r--r--usr.bin/at/atrm.193
-rw-r--r--usr.bin/at/panic.c53
-rw-r--r--usr.bin/at/parsetime.c47
-rw-r--r--usr.bin/at/perm.c17
11 files changed, 722 insertions, 414 deletions
diff --git a/etc/Makefile b/etc/Makefile
index a04ed640631..c394c31943c 100644
--- a/etc/Makefile
+++ b/etc/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.160 2002/05/13 07:22:42 espie Exp $
+# $OpenBSD: Makefile,v 1.161 2002/05/14 18:05:38 millert Exp $
TZDIR= /usr/share/zoneinfo
LOCALTIME= US/Pacific
@@ -187,8 +187,6 @@ distribution-etc-root-var: distrib-dirs
${DESTDIR}/etc/skeykeys
${INSTALL} -c -o root -g crontab -m 660 /dev/null \
${DESTDIR}/var/at/at.deny
- ${INSTALL} -c -o root -g crontab -m 660 /dev/null \
- ${DESTDIR}/var/at/.SEQ
${INSTALL} -c -o root -g wheel -m 600 /dev/null \
${DESTDIR}/var/cron/log
${INSTALL} -c -o root -g wheel -m 444 /dev/null \
diff --git a/libexec/atrun/atrun.c b/libexec/atrun/atrun.c
index 8c286f92c30..e99b03a8bc6 100644
--- a/libexec/atrun/atrun.c
+++ b/libexec/atrun/atrun.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: atrun.c,v 1.20 2002/05/11 23:11:59 millert Exp $ */
+/* $OpenBSD: atrun.c,v 1.21 2002/05/14 18:05:39 millert Exp $ */
/*
* atrun.c - run jobs queued by at; run with root privileges.
@@ -27,55 +27,46 @@
/* System Headers */
-#include <sys/types.h>
#include <sys/fcntl.h>
+#include <sys/param.h>
+#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/resource.h>
#include <sys/wait.h>
-#include <sys/param.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
-#include <pwd.h>
#include <grp.h>
#include <limits.h>
+#include <paths.h>
+#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
#include <time.h>
#include <unistd.h>
-#include <syslog.h>
#include <utmp.h>
-#include <paths.h>
#include <login_cap.h>
#include <bsd_auth.h>
-/* Local headers */
-
#define MAIN
#include "privs.h"
#include "pathnames.h"
#include "atrun.h"
-/* File scope defines */
-
#if (MAXLOGNAME-1) > UT_NAMESIZE
#define LOGNAMESIZE UT_NAMESIZE
#else
#define LOGNAMESIZE (MAXLOGNAME-1)
#endif
-/* File scope variables */
-
-static const char rcsid[] = "$OpenBSD: atrun.c,v 1.20 2002/05/11 23:11:59 millert Exp $";
+static const char rcsid[] = "$OpenBSD: atrun.c,v 1.21 2002/05/14 18:05:39 millert Exp $";
static int debug = 0;
-/* Local functions */
-
static void
perr(const char *a)
{
@@ -105,14 +96,14 @@ write_string(int fd, const char *a)
return(write(fd, a, strlen(a)));
}
+/*
+ * Run a file by spawning off a process which redirects I/O,
+ * spawns a subshell, then waits for it to complete and spawns
+ * another process to send mail to the user.
+ */
static void
run_file(const char *filename, uid_t uid, gid_t gid)
{
- /*
- * Run a file by spawning off a process which redirects I/O,
- * spawns a subshell, then waits for it to complete and spawns another
- * process to send mail to the user.
- */
pid_t pid;
int fd_out, fd_in;
int queue;
@@ -120,7 +111,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
char *mailname = NULL;
FILE *stream;
int send_mail = 0;
- struct stat buf, lbuf;
+ struct stat stbuf;
off_t size;
struct passwd *pw;
int fflags;
@@ -147,7 +138,6 @@ run_file(const char *filename, uid_t uid, gid_t gid)
* command file; if not, send it to the owner, or, failing that, to
* root.
*/
-
pw = getpwuid(uid);
if (pw == NULL) {
syslog(LOG_ERR,"Userid %u not found - aborting job %s",
@@ -170,37 +160,31 @@ run_file(const char *filename, uid_t uid, gid_t gid)
PRIV_START;
- fd_in = open(filename, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0);
+ fd_in = open(filename, O_RDONLY | O_NONBLOCK | O_NOFOLLOW, 0);
PRIV_END;
if (fd_in < 0)
perr("Cannot open input file");
- if (fstat(fd_in, &buf) == -1)
+ if (fstat(fd_in, &stbuf) == -1)
perr("Error in fstat of input file descriptor");
- PRIV_START;
-
- if (lstat(filename, &lbuf) == -1)
- perr("Error in lstat of input file");
-
- PRIV_END;
-
- if (S_ISLNK(lbuf.st_mode)) {
- syslog(LOG_ERR, "Symbolic link encountered in job %s - aborting",
+ if (!S_ISREG(stbuf.st_mode)) {
+ syslog(LOG_ERR, "Job %s is not a regular file - aborting",
filename);
exit(EXIT_FAILURE);
}
- if ((lbuf.st_dev != buf.st_dev) || (lbuf.st_ino != buf.st_ino) ||
- (lbuf.st_uid != buf.st_uid) || (lbuf.st_gid != buf.st_gid) ||
- (lbuf.st_size!=buf.st_size)) {
- syslog(LOG_ERR, "Somebody changed files from under us for job %s - aborting", filename);
+ if (stbuf.st_uid != uid) {
+ syslog(LOG_ERR, "Uid mismatch for job %s", filename);
exit(EXIT_FAILURE);
}
- if (buf.st_nlink > 1) {
- syslog(LOG_ERR, "Somebody is trying to run a linked script for job %s",
- filename);
+ if (stbuf.st_nlink != 1) {
+ syslog(LOG_ERR, "Bad link count for job %s", filename);
+ exit(EXIT_FAILURE);
+ }
+ if ((stbuf.st_mode & ALLPERMS) != S_IRUSR) {
+ syslog(LOG_ERR, "Bad file mode for job %s", filename);
exit(EXIT_FAILURE);
}
if ((fflags = fcntl(fd_in, F_GETFD)) < 0)
@@ -261,9 +245,9 @@ run_file(const char *filename, uid_t uid, gid_t gid)
write_string(fd_out, "\nSubject: Output from your job ");
write_string(fd_out, filename);
write_string(fd_out, "\n\n");
- if (fstat(fd_out, &buf) == -1)
+ if (fstat(fd_out, &stbuf) == -1)
perr("Error in fstat of output file descriptor");
- size = buf.st_size;
+ size = stbuf.st_size;
(void)close(STDIN_FILENO);
(void)close(STDOUT_FILENO);
@@ -337,16 +321,16 @@ run_file(const char *filename, uid_t uid, gid_t gid)
*/
PRIV_START;
- if (stat(filename, &buf) == -1)
+ if (stat(filename, &stbuf) == -1)
perr("Error in stat of output file");
- if (open(filename, O_RDONLY) != STDIN_FILENO)
+ if (open(filename, O_RDONLY | O_NOFOLLOW) != STDIN_FILENO)
perr("Open of jobfile failed");
(void)unlink(filename);
PRIV_END;
- if ((buf.st_size != size) || send_mail) {
+ if ((stbuf.st_size != size) || send_mail) {
/* Fork off a child for sending mail */
PRIV_START;
@@ -366,35 +350,31 @@ run_file(const char *filename, uid_t uid, gid_t gid)
exit(EXIT_SUCCESS);
}
-/* Global functions */
int
main(int argc, char **argv)
{
/*
- * Browse through _PATH_ATJOBS, checking all the jobfiles wether
- * they should be executed and or deleted. The queue is coded into
- * the first byte of the job filename, the date (in minutes since
- * Eon) as a hex number in the following eight bytes, followed by
- * a dot and a serial number. A file which has not been executed
- * yet is denoted by its execute - bit set. For those files which
- * are to be executed, run_file() is called, which forks off a
- * child which takes care of I/O redirection, forks off another
- * child for execution and yet another one, optionally, for sending
- * mail. Files which already have run are removed during the
- * next invocation.
+ * Browse through _PATH_ATJOBS, looking for jobs that should be
+ * be executed and/or deleted. The filename consists of the date
+ * (in seconds since the epoch) followed by a '.' and then the
+ * queue (a letter). A file which has not been executed yet will
+ * have its execute bit set. For each file which is to be executed,
+ * run_file() is called, which forks off a child to take care of
+ * I/O redirection, forking off another child for execution and
+ * yet another one, optionally, for sending mail. Files which
+ * have already run are removed during the next invocation.
*/
DIR *spool;
struct dirent *dirent;
- struct stat buf;
- unsigned long ctm;
- int jobno;
+ struct stat stbuf;
char queue;
char *ep;
time_t now, run_time;
- char batch_name[] = "Z2345678901234";
+ char batch_name[FILENAME_MAX];
uid_t batch_uid;
gid_t batch_gid;
+ long l;
int c;
int run_batch;
double la, load_avg = ATRUN_MAXLOAD;
@@ -407,7 +387,6 @@ main(int argc, char **argv)
openlog("atrun", LOG_PID, LOG_CRON);
- opterr = 0;
errno = 0;
while ((c = getopt(argc, argv, "dl:")) != -1) {
switch (c) {
@@ -436,7 +415,6 @@ main(int argc, char **argv)
if (chdir(_PATH_ATJOBS) != 0)
perr2("Cannot change to ", _PATH_ATJOBS);
-
/*
* Main loop. Open spool directory for reading and look over all
* the files in there. If the filename indicates that the job
@@ -458,42 +436,45 @@ main(int argc, char **argv)
run_batch = 0;
batch_uid = (uid_t) -1;
batch_gid = (gid_t) -1;
+ batch_name[0] = '\0';
while ((dirent = readdir(spool)) != NULL) {
PRIV_START;
- if (stat(dirent->d_name, &buf) != 0)
+ if (stat(dirent->d_name, &stbuf) != 0)
perr2("Cannot stat in ", _PATH_ATJOBS);
PRIV_END;
/* We don't want directories */
- if (!S_ISREG(buf.st_mode))
+ if (!S_ISREG(stbuf.st_mode))
continue;
- if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) != 3)
+ l = strtol(dirent->d_name, &ep, 10);
+ if (*ep != '.' || !isalpha(*(ep + 1)) || l < 0 || l >= INT_MAX)
continue;
+ run_time = (time_t)l;
+ queue = *(ep + 1);
- run_time = (time_t) ctm * 60;
-
- if ((S_IXUSR & buf.st_mode) && (run_time <= now)) {
+ if ((S_IXUSR & stbuf.st_mode) && (run_time <= now)) {
if (isupper(queue) &&
(strcmp(batch_name, dirent->d_name) > 0)) {
run_batch = 1;
- (void)strncpy(batch_name, dirent->d_name,
+ (void)strlcpy(batch_name, dirent->d_name,
sizeof(batch_name));
- batch_uid = buf.st_uid;
- batch_gid = buf.st_gid;
+ batch_uid = stbuf.st_uid;
+ batch_gid = stbuf.st_gid;
}
/* The file is executable and old enough */
if (islower(queue))
- run_file(dirent->d_name, buf.st_uid, buf.st_gid);
+ run_file(dirent->d_name, stbuf.st_uid,
+ stbuf.st_gid);
}
/* Delete older files */
- if ((run_time < now) && !(S_IXUSR & buf.st_mode) &&
- (S_IRUSR & buf.st_mode)) {
+ if ((run_time < now) && !(S_IXUSR & stbuf.st_mode) &&
+ (S_IRUSR & stbuf.st_mode)) {
PRIV_START;
(void)unlink(dirent->d_name);
diff --git a/usr.bin/at/Makefile b/usr.bin/at/Makefile
index 406cb0f0b3b..18fbe101830 100644
--- a/usr.bin/at/Makefile
+++ b/usr.bin/at/Makefile
@@ -1,20 +1,14 @@
-# $OpenBSD: Makefile,v 1.5 2002/05/11 18:41:20 millert Exp $
+# $OpenBSD: Makefile,v 1.6 2002/05/14 18:05:39 millert Exp $
PROG= at
SRCS= at.c panic.c parsetime.c perm.c
+MAN= at.1 atrm.1 atq.1
LINKS= ${BINDIR}/at ${BINDIR}/atq \
${BINDIR}/at ${BINDIR}/atrm \
${BINDIR}/at ${BINDIR}/batch
-MLINKS= at.1 batch.1 \
- at.1 atq.1 \
- at.1 atrm.1
+MLINKS= at.1 batch.1
BINGRP= crontab
BINMODE= 2555
-afterinstall:
- test -f ${DESTDIR}/var/at/.SEQ || touch ${DESTDIR}/var/at/.SEQ
- chown ${BINOWN}:${BINGRP} ${DESTDIR}/var/at/.SEQ; \
- chmod 0660 ${DESTDIR}/var/at/.SEQ; \
-
.include <bsd.prog.mk>
diff --git a/usr.bin/at/at.1 b/usr.bin/at/at.1
index 820ba8f76bd..9c44910d7ef 100644
--- a/usr.bin/at/at.1
+++ b/usr.bin/at/at.1
@@ -1,35 +1,27 @@
-.\" $OpenBSD: at.1,v 1.24 2002/05/13 18:43:53 millert Exp $
+.\" $OpenBSD: at.1,v 1.25 2002/05/14 18:05:39 millert Exp $
.\" $FreeBSD: at.man,v 1.6 1997/02/22 19:54:05 peter Exp $
-.Dd April 12, 1995
+.Dd May 13, 2002
.Dt AT 1
.Os
.Sh NAME
.Nm at ,
-.Nm atq ,
-.Nm atrm ,
.Nm batch
.Nd queue, examine or delete jobs for later execution
.Sh SYNOPSIS
.Nm at
-.Op Fl blmrv
+.Op Fl blmr
.Op Fl f Ar file
.Op Fl q Ar queue
.Fl t Ar time_arg
.Nm at
-.Op Fl blmrv
+.Op Fl blmr
.Op Fl f Ar file
.Op Fl q Ar queue
.Ar timespec
.Nm at
.Fl c Ar job Op Ar job ...
-.Nm atq
-.Op Fl q Ar queue
-.Op Fl v
-.Nm atrm
-.Ar job
-.Op Ar job ...
.Nm batch
-.Op Fl mv
+.Op Fl m
.Op Fl f Ar file
.Op Fl q Ar queue
.Op Ar timespec
@@ -54,11 +46,6 @@ The related programs are as follows:
.Bl -tag -width Ds
.It Nm at
Executes commands at a specified time.
-.It Nm atq
-Lists the user's pending jobs, unless the user is the superuser.
-In that case, all users' jobs are listed.
-.It Nm atrm
-Deletes jobs.
.It Nm batch
Executes commands when system load levels permit.
In other words, when
@@ -78,8 +65,9 @@ Reads the job from
.Ar file
rather than standard input.
.It Fl l
-An alias for
-.Nm atq .
+Lists the user's pending jobs, unless the user is the superuser.
+In that case, all users' jobs are listed.
+.\" XXX - should document that user names may be specified (like atq)
.It Fl m
Send mail to the user when the job has completed, even if there was no
output.
@@ -105,12 +93,15 @@ queue for
Queues with higher letters run with increased niceness.
If a job is submitted to a queue designated with an uppercase letter, it
is treated as if it had been submitted to batch at that time.
-If
-.Nm atq
-is given a specific queue, it will only show jobs pending in that queue.
+If the user specified the
+.Fl l
+option and
+.Nm at
+is given a specific queue, only jobs pending in that queue will be shown.
.It Fl r
-An alias for
-.Nm atrm .
+Remove the specified job(s) from the
+.Nm at
+queue.
.It Fl t Ar time_arg
Specify the job time using the format specified by
.Xr touch 1 .
@@ -145,10 +136,9 @@ If the
.Ar SS
letter pair is not specified, the value defaults to 0.
.It Fl v
-For
-.Nm atq ,
-shows completed but not yet deleted jobs in the queue.
-Otherwise shows the time the job will be executed.
+When used in conjuction with the
+.Fl l
+option, shows completed but not yet deleted jobs in the queue.
.El
.Pp
.Nm at
diff --git a/usr.bin/at/at.c b/usr.bin/at/at.c
index c666e69fcd9..50ec0e973eb 100644
--- a/usr.bin/at/at.c
+++ b/usr.bin/at/at.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: at.c,v 1.28 2002/05/13 18:43:53 millert Exp $ */
+/* $OpenBSD: at.c,v 1.29 2002/05/14 18:05:39 millert Exp $ */
/* $NetBSD: at.c,v 1.4 1995/03/25 18:13:31 glass Exp $ */
/*
@@ -8,6 +8,9 @@
* Atrun & Atq modifications
* Copyright (C) 1993 David Parsons
*
+ * Traditional BSD behavior and other significant modifications
+ * Copyright (C) 2002 Todd C. Miller
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -29,14 +32,15 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* System Headers */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <ctype.h>
#include <dirent.h>
+#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <locale.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
@@ -46,8 +50,6 @@
#include <time.h>
#include <unistd.h>
#include <utmp.h>
-#include <locale.h>
-#include <err.h>
#if (MAXLOGNAME-1) > UT_NAMESIZE
#define LOGNAMESIZE UT_NAMESIZE
@@ -55,7 +57,6 @@
#define LOGNAMESIZE (MAXLOGNAME-1)
#endif
-/* Local headers */
#include "at.h"
#include "panic.h"
#include "parsetime.h"
@@ -64,45 +65,36 @@
#define MAIN
#include "privs.h"
-/* Macros */
#define ALARMC 10 /* Number of seconds to wait for timeout */
+#define TIMESIZE 50 /* Size of buffer passed to strftime() */
-#define TIMESIZE 50
-
-/* File scope variables */
#ifndef lint
-static const char rcsid[] = "$OpenBSD: at.c,v 1.28 2002/05/13 18:43:53 millert Exp $";
+static const char rcsid[] = "$OpenBSD: at.c,v 1.29 2002/05/14 18:05:39 millert Exp $";
#endif
+/* Variables to remove from the job's environment. */
char *no_export[] =
{
"TERM", "TERMCAP", "DISPLAY", "_", "SHELLOPTS", "BASH_VERSINFO",
"EUID", "GROUPS", "PPID", "UID", "SSH_AUTH_SOCK", "SSH_AGENT_PID",
};
-static int send_mail = 0;
-
-/* External variables */
-extern char **environ;
-int fcreated;
int program = AT; /* default program mode */
-char atfile[FILENAME_MAX];
-
-char *atinput = (char *)0; /* where to get input from */
+char atfile[PATH_MAX]; /* path to the at spool file */
+int fcreated; /* whether or not we created the file yet */
+char *atinput = NULL; /* where to get input from */
char atqueue = 0; /* which queue to examine for jobs (atq) */
-char atverify = 0; /* verify time instead of queuing job */
-
-/* Function declarations */
+char vflag = 0; /* show completed but unremoved jobs (atq) */
+char force = 0; /* suppress errors (atrm) */
+char interactive = 0; /* interactive mode (atrm) */
+static int send_mail = 0; /* whether we are sending mail */
static void sigc(int);
static void alarmc(int);
-static char *cwdname(void);
static void writefile(time_t, char);
-static void list_jobs(void);
+static void list_jobs(int, char **, int, int);
static time_t ttime(const char *);
-/* Signal catching functions */
-
static void
sigc(int signo)
{
@@ -133,53 +125,37 @@ alarmc(int signo)
_exit(EXIT_FAILURE);
}
-/* Local functions */
-
-static char *
-cwdname(void)
-{
- /*
- * Read in the current directory; the name will be overwritten on
- * subsequent calls.
- */
- static char path[MAXPATHLEN];
-
- return (getcwd(path, sizeof(path)));
-}
-
static int
-nextjob(void)
+newjob(time_t runtimer, int queue)
{
- int jobno;
- FILE *fid;
-
- /* We require that the sequence file already exist. */
- if ((fid = fopen(_PATH_SEQFILE, "r+")) == NULL)
- return (EOF);
-
- if (fscanf(fid, "%5x", &jobno) == 1)
- jobno = (jobno + 1) % 0xfffff; /* 2^20 jobs enough? */
- else
- jobno = 1;
- (void)rewind(fid);
- (void)fprintf(fid, "%05x\n", jobno);
- (void)fclose(fid);
+ int fd, i;
- return (jobno);
+ /*
+ * If we have a collision, try shifting the time by up to
+ * two minutes. Perhaps it would be better to try different
+ * queues instead...
+ */
+ for (i = 0; i < 120; i++) {
+ snprintf(atfile, sizeof(atfile), "%s/%ld.%c",
+ _PATH_ATJOBS, (long)runtimer, queue);
+ fd = open(atfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR);
+ if (fd >= 0)
+ return (fd);
+ }
+ return (-1);
}
+/*
+ * This does most of the work if at or batch are invoked for
+ * writing a job.
+ */
static void
writefile(time_t runtimer, char queue)
{
- /*
- * This does most of the work if at or batch are invoked for
- * writing a job.
- */
- int jobno;
- char *ap, *ppos, *mailname, *shell;
+ char *ap, *mailname, *shell;
char timestr[TIMESIZE];
+ char path[PATH_MAX];
struct passwd *pass_entry;
- struct stat statbuf;
struct tm runtime;
int fdes, lockdes, fd2;
FILE *fp, *fpin;
@@ -187,7 +163,7 @@ writefile(time_t runtimer, char queue)
char **atenv;
int ch;
mode_t cmask;
- struct flock lock;
+ extern char **environ;
(void)setlocale(LC_TIME, "");
@@ -197,29 +173,21 @@ writefile(time_t runtimer, char queue)
*/
memset(&act, 0, sizeof act);
act.sa_handler = sigc;
- sigemptyset(&(act.sa_mask));
+ sigemptyset(&act.sa_mask);
act.sa_flags = 0;
-
sigaction(SIGINT, &act, NULL);
- (void)strlcpy(atfile, _PATH_ATJOBS, sizeof atfile);
- ppos = atfile + strlen(atfile);
-
- /*
- * Loop over all possible file names for running something at this
- * particular time, see if a file is there; the first empty slot at
- * any particular time is used. Lock the jobs directory first
- * to make sure we're alone when doing this.
- */
-
PRIV_START;
/*
+ * Lock the jobs dir so we don't have to worry about someone
+ * else grabbing a file name out from under us.
* Set an alarm so we don't sleep forever waiting on the lock.
* If we don't succeed with ALARMC seconds, something is wrong...
*/
+ memset(&act, 0, sizeof act);
act.sa_handler = alarmc;
- sigemptyset(&(act.sa_mask));
+ sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
alarm(ALARMC);
@@ -229,20 +197,6 @@ writefile(time_t runtimer, char queue)
if (lockdes < 0)
perr("Cannot lock jobs dir");
- if ((jobno = nextjob()) == EOF)
- perr("Cannot generate job number");
-
- (void)snprintf(ppos, sizeof(atfile) - (ppos - atfile),
- "%c%5x%8x", queue, jobno, (unsigned) (runtimer/60));
-
- for (ap = ppos; *ap != '\0'; ap++)
- if (*ap == ' ')
- *ap = '0';
-
- if (stat(atfile, &statbuf) != 0)
- if (errno != ENOENT)
- perr2("Cannot access ", _PATH_ATJOBS);
-
/*
* Create the file. The x bit is only going to be set after it has
* been completely written out, to make sure it is not executed in
@@ -250,7 +204,7 @@ writefile(time_t runtimer, char queue)
* their r bit. Yes, this is a kluge.
*/
cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR);
- if ((fdes = open(atfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR)) == -1)
+ if ((fdes = newjob(runtimer, queue)) == -1)
perr("Cannot create atjob file");
if ((fd2 = dup(fdes)) < 0)
@@ -268,11 +222,6 @@ writefile(time_t runtimer, char queue)
fcreated = 1;
/* Now we can release the lock, so other people can access it */
- lock.l_type = F_UNLCK;
- lock.l_whence = SEEK_SET;
- lock.l_start = 0;
- lock.l_len = 0;
- (void)fcntl(lockdes, F_SETLKW, &lock);
(void)close(lockdes);
if ((fp = fdopen(fdes, "w")) == NULL)
@@ -373,7 +322,7 @@ writefile(time_t runtimer, char queue)
* Cd to the directory at the time and write out all the
* commands the user supplies from stdin.
*/
- if ((ap = cwdname()) == NULL)
+ if ((ap = getcwd(path, sizeof(path))) == NULL)
perr("Cannot get current working directory");
(void)fputs("cd ", fp);
for (; *ap != '\0'; ap++) {
@@ -390,7 +339,8 @@ writefile(time_t runtimer, char queue)
* Test cd's exit status: die if the original directory has been
* removed, become unreadable or whatever.
*/
- (void)fprintf(fp, " || {\n\t echo 'Execution directory inaccessible' >&2\n\t exit 1\n}\n");
+ (void)fprintf(fp, " || {\n\t echo 'Execution directory inaccessible'"
+ " >&2\n\t exit 1\n}\n");
if ((ch = getchar()) == EOF)
panic("Input error");
@@ -422,27 +372,100 @@ writefile(time_t runtimer, char queue)
runtime = *localtime(&runtimer);
strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
(void)fprintf(stderr, "commands will be executed using %s\n", shell);
- (void)fprintf(stderr, "job %d at %s\n", jobno, timestr);
+ (void)fprintf(stderr, "job %s at %s\n", &atfile[sizeof(_PATH_ATJOBS)],
+ timestr);
+}
+
+/* Sort by creation time. */
+static int
+byctime(const void *v1, const void *v2)
+{
+ const struct atjob *j1 = *(struct atjob **)v1;
+ const struct atjob *j2 = *(struct atjob **)v2;
+
+ return (j1->ctime - j2->ctime);
+}
+
+/* Sort by job number (and thus execution time). */
+static int
+byjobno(const void *v1, const void *v2)
+{
+ const struct atjob *j1 = *(struct atjob **)v1;
+ const struct atjob *j2 = *(struct atjob **)v2;
+
+ if (j1->runtimer == j2->runtimer)
+ return (j1->queue - j2->queue);
+ return (j1->runtimer - j2->runtimer);
}
static void
-list_jobs(void)
+print_job(struct atjob *job, int n, struct stat *st, int shortformat)
{
- /*
- * List all a user's jobs in the queue, by looping through
- * _PATH_ATJOBS, or everybody's if we are root
- */
struct passwd *pw;
- DIR *spool;
- struct dirent *dirent;
- struct stat buf;
struct tm runtime;
- unsigned long ctm;
- char queue;
- int jobno;
- time_t runtimer;
char timestr[TIMESIZE];
- int first = 1;
+ static char *ranks[] = {
+ "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"
+ };
+
+ runtime = *localtime(&job->runtimer);
+ if (shortformat) {
+ strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
+ (void)printf("%ld.%c\t%s\n", (long)job->runtimer,
+ job->queue, timestr);
+ } else {
+ pw = getpwuid(st->st_uid);
+ /* Rank hack shamelessly stolen from lpq */
+ if (n / 10 == 1)
+ printf("%3d%-5s", n,"th");
+ else
+ printf("%3d%-5s", n, ranks[n % 10]);
+ strftime(timestr, TIMESIZE, "%b %e, %Y %R", &runtime);
+ (void)printf("%-21.18s%-11.8s%10ld.%c %c%s\n",
+ timestr, pw ? pw->pw_name : "???",
+ (long)job->runtimer, job->queue, job->queue,
+ (S_IXUSR & st->st_mode) ? "" : " (done)");
+ }
+}
+
+/*
+ * List all of a user's jobs in the queue, by looping through
+ * _PATH_ATJOBS, or all jobs if we are root. If argc is > 0, argv
+ * contains the list of users whose jobs shall be displayed. By
+ * default, the list is sorted by execution date and queue. If
+ * csort is non-zero jobs will be sorted by creation/submission date.
+ */
+static void
+list_jobs(int argc, char **argv, int count_only, int csort)
+{
+ struct passwd *pw;
+ struct dirent *dirent;
+ struct atjob **atjobs, *job;
+ struct stat stbuf;
+ time_t runtimer;
+ uid_t *uids;
+ long l;
+ char queue, *ep;
+ DIR *spool;
+ int i, shortformat, numjobs, maxjobs;
+
+ if (argc) {
+ if ((uids = malloc(sizeof(uid_t) * argc)) == NULL)
+ err(EXIT_FAILURE, "malloc");
+
+ for (i = 0; i < argc; i++) {
+ if ((pw = getpwnam(argv[i])) == NULL)
+ errx(EXIT_FAILURE,
+ "%s: invalid user name", argv[i]);
+ if (pw->pw_uid != real_uid && real_uid != 0)
+ errx(EXIT_FAILURE, "Only the superuser may "
+ "display other users' jobs");
+ uids[i] = pw->pw_uid;
+ }
+ } else
+ uids = NULL;
+
+ shortformat = strcmp(__progname, "at") == 0;
PRIV_START;
@@ -452,56 +475,136 @@ list_jobs(void)
if ((spool = opendir(".")) == NULL)
perr2("Cannot open ", _PATH_ATJOBS);
- /* Loop over every file in the directory */
+ PRIV_END;
+
+ if (fstat(dirfd(spool), &stbuf) != 0)
+ perr2("Cannot stat ", _PATH_ATJOBS);
+
+ /*
+ * The directory's link count should give us a good idea
+ * of how many files are in it. Fudge things a little just
+ * in case someone adds a job or two.
+ */
+ numjobs = 0;
+ maxjobs = stbuf.st_nlink + 4;
+ atjobs = (struct atjob **)malloc(maxjobs * sizeof(struct atjob *));
+ if (atjobs == NULL)
+ err(EXIT_FAILURE, "malloc");
+
+ /* Loop over every file in the directory. */
while ((dirent = readdir(spool)) != NULL) {
- if (stat(dirent->d_name, &buf) != 0)
+ PRIV_START;
+
+ if (stat(dirent->d_name, &stbuf) != 0)
perr2("Cannot stat in ", _PATH_ATJOBS);
+ PRIV_END;
+
/*
* See it's a regular file and has its x bit turned on and
* is the user's
*/
- if (!S_ISREG(buf.st_mode)
- || ((buf.st_uid != real_uid) && !(real_uid == 0))
- || !(S_IXUSR & buf.st_mode || atverify))
+ if (!S_ISREG(stbuf.st_mode)
+ || ((stbuf.st_uid != real_uid) && !(real_uid == 0))
+ || !(S_IXUSR & stbuf.st_mode || vflag))
continue;
- if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) != 3)
+ l = strtol(dirent->d_name, &ep, 10);
+ if (*ep != '.' || !isalpha(*(ep + 1)) || *(ep + 2) != '\0' ||
+ l < 0 || l >= INT_MAX)
continue;
+ runtimer = (time_t)l;
+ queue = *(ep + 1);
if (atqueue && (queue != atqueue))
continue;
- runtimer = 60 * (time_t) ctm;
- runtime = *localtime(&runtimer);
- strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime);
- if (first) {
- (void)printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n");
- first = 0;
+ /* Check against specified user(s). */
+ if (argc) {
+ for (i = 0; i < argc; i++) {
+ if (uids[0] == stbuf.st_uid)
+ break;
+ }
+ if (i == argc)
+ continue; /* user doesn't match */
}
- pw = getpwuid(buf.st_uid);
-
- (void)printf("%s\t%-16s%c%s\t%d\n",
- timestr,
- pw ? pw->pw_name : "???",
- queue,
- (S_IXUSR & buf.st_mode) ? "" : "(done)",
- jobno);
+
+ if (count_only) {
+ numjobs++;
+ continue;
+ }
+
+ job = (struct atjob *)malloc(sizeof(struct atjob));
+ if (job == NULL)
+ err(EXIT_FAILURE, "malloc");
+ job->runtimer = runtimer;
+ job->ctime = stbuf.st_ctime;
+ job->queue = queue;
+ if (numjobs == maxjobs) {
+ maxjobs *= 2;
+ atjobs = realloc(atjobs, maxjobs * sizeof(struct atjob *));
+ if (atjobs == NULL)
+ err(EXIT_FAILURE, "realloc");
+ }
+ atjobs[numjobs++] = job;
}
- PRIV_END;
+ free(uids);
+
+ if (count_only || numjobs == 0) {
+ if (numjobs == 0 && !shortformat)
+ fprintf(stderr, "no files in queue.\n");
+ else if (count_only)
+ printf("%d\n", numjobs);
+ free(atjobs);
+ return;
+ }
+
+ /* Sort by job run time or by job creation time. */
+ qsort(atjobs, numjobs, sizeof(struct atjob *),
+ csort ? byctime : byjobno);
+
+ if (!shortformat)
+ (void)puts(" Rank Execution Date Owner "
+ "Job Queue");
+
+ for (i = 0; i < numjobs; i++) {
+ print_job(atjobs[i], i + 1, &stbuf, shortformat);
+ free(atjobs[i]);
+ }
+ free(atjobs);
+}
+
+static int
+rmok(int job)
+{
+ int ch, junk;
+
+ printf("%d: remove it? ", job);
+ ch = getchar();
+ while ((junk = getchar()) != EOF && junk != '\n')
+ ;
+ return (ch == 'y' || ch == 'Y');
}
+/*
+ * Loop through all jobs in _PATH_ATJOBS and display or delete ones
+ * that match argv (may be job or username), or all if argc == 0.
+ * Only the superuser may display/delete other people's jobs.
+ */
static int
process_jobs(int argc, char **argv, int what)
{
- int i;
- struct stat buf;
- DIR *spool;
+ struct stat stbuf;
struct dirent *dirent;
- unsigned long ctm;
- char queue;
- int jobno;
- int error;
+ struct passwd *pw;
+ time_t runtimer;
+ uid_t *uids;
+ char **jobs, *ep, queue;
+ long l;
+ FILE *fp;
+ DIR *spool;
+ int job_matches, jobs_len, uids_len;
+ int error, i, ch;
PRIV_START;
@@ -513,81 +616,134 @@ process_jobs(int argc, char **argv, int what)
PRIV_END;
+ /* Convert argv into a list of jobs and uids. */
+ jobs = NULL;
+ uids = NULL;
+ jobs_len = uids_len = 0;
+ if (argc > 0) {
+ if ((jobs = malloc(sizeof(char *) * argc)) == NULL ||
+ (uids = malloc(sizeof(uid_t) * argc)) == NULL)
+ err(EXIT_FAILURE, "malloc");
+
+ for (i = 0; i < argc; i++) {
+ l = strtol(argv[i], &ep, 10);
+ if (*ep == '.' && isalpha(*(ep + 1)) &&
+ *(ep + 2) == '\0' && l > 0 && l < INT_MAX)
+ jobs[jobs_len++] = argv[i];
+ else if ((pw = getpwnam(argv[i])) != NULL) {
+ if (real_uid != pw->pw_uid && real_uid != 0)
+ errx(EXIT_FAILURE,
+ "Only the superuser may %s"
+ " other users' jobs", what == ATRM
+ ? "remove" : "print");
+ uids[uids_len++] = pw->pw_uid;
+ } else
+ errx(EXIT_FAILURE,
+ "%s: invalid user name", argv[i]);
+ }
+ }
+
/* Loop over every file in the directory */
while ((dirent = readdir(spool)) != NULL) {
PRIV_START;
- if (stat(dirent->d_name, &buf) != 0)
+ if (stat(dirent->d_name, &stbuf) != 0)
perr2("Cannot stat in ", _PATH_ATJOBS);
PRIV_END;
- if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) !=3)
+ if (stbuf.st_uid != real_uid && real_uid != 0)
+ continue;
+
+ l = strtol(dirent->d_name, &ep, 10);
+ if (*ep != '.' || !isalpha(*(ep + 1)) || *(ep + 2) != '\0' ||
+ l < 0 || l >= INT_MAX)
continue;
+ runtimer = (time_t)l;
+ queue = *(ep + 1);
+
+ /* Check runtimer against argv; argc==0 means do all. */
+ job_matches = (argc == 0) ? 1 : 0;
+ if (!job_matches) {
+ for (i = 0; i < jobs_len; i++) {
+ if (strcmp(dirent->d_name, jobs[i]) == 0) {
+ jobs[i] = NULL;
+ job_matches = 1;
+ break;
+ }
+ }
+ }
+ if (!job_matches) {
+ for (i = 0; i < uids_len; i++) {
+ if (uids[i] == stbuf.st_uid) {
+ job_matches = 1;
+ break;
+ }
+ }
+ }
- for (i = optind; i < argc; i++) {
- if (argv[i] != NULL && atoi(argv[i]) == jobno) {
- /* Treat wrong owner like unknown job. */
- if ((buf.st_uid != real_uid) && !(real_uid == 0))
- continue;
- argv[i] = NULL;
- switch (what) {
- case ATRM:
- PRIV_START;
+ if (job_matches) {
+ switch (what) {
+ case ATRM:
+ PRIV_START;
+ if (!interactive ||
+ (interactive && rmok(runtimer))) {
if (unlink(dirent->d_name) != 0)
perr(dirent->d_name);
+ if (!force && !interactive)
+ fprintf(stderr,
+ "%s removed\n",
+ dirent->d_name);
+ }
- PRIV_END;
+ PRIV_END;
- break;
+ break;
- case CAT:
- {
- FILE *fp;
- int ch;
+ case CAT:
+ PRIV_START;
- PRIV_START;
+ fp = fopen(dirent->d_name, "r");
- fp = fopen(dirent->d_name, "r");
+ PRIV_END;
- PRIV_END;
+ if (!fp)
+ perr("Cannot open file");
- if (!fp)
- perr("Cannot open file");
+ while ((ch = getc(fp)) != EOF)
+ putchar(ch);
- while((ch = getc(fp)) != EOF)
- putchar(ch);
- }
- break;
+ break;
- default:
- errx(EXIT_FAILURE,
- "Internal error, process_jobs = %d",
- what);
- break;
- }
+ default:
+ errx(EXIT_FAILURE,
+ "Internal error, process_jobs = %d",
+ what);
+ break;
}
}
}
- for (error = 0, i = optind; i < argc; i++) {
- if (argv[i] != NULL) {
- warnx("%s: no such job number", argv[i]);
+ for (error = 0, i = 0; i < jobs_len; i++) {
+ if (jobs[i] != NULL) {
+ if (!force)
+ warnx("%s: no such job", jobs[i]);
error++;
}
}
- return(error);
+ free(jobs);
+ free(uids);
+
+ return (error);
}
#define ATOI2(s) ((s) += 2, ((s)[-2] - '0') * 10 + ((s)[-1] - '0'))
+/*
+ * This is pretty much a copy of stime_arg1() from touch.c.
+ */
static time_t
ttime(const char *arg)
{
- /*
- * This is pretty much a copy of stime_arg1() from touch.c. I changed
- * the return value and the argument list because it's more convenient
- * (IMO) to do everything in one place. - Joe Halpin
- */
struct timeval tv[2];
time_t now;
struct tm *t;
@@ -649,38 +805,51 @@ ttime(const char *arg)
"[[CC]YY]MMDDhhmm[.SS]");
}
-/* Global functions */
-
int
main(int argc, char **argv)
{
- int c;
+ time_t timer = -1;
char queue = DEFAULT_AT_QUEUE;
char queue_set = 0;
char *options = "q:f:t:bcdlmrv"; /* default options for at */
- time_t timer;
- int tflag = 0;
+ int ch;
+ int aflag = 0;
+ int cflag = 0;
+ int nflag = 0;
RELINQUISH_PRIVS;
/* find out what this program is supposed to do */
if (strcmp(__progname, "atq") == 0) {
program = ATQ;
- options = "q:v";
+ options = "cnvq:";
} else if (strcmp(__progname, "atrm") == 0) {
program = ATRM;
- options = "";
+ options = "afi";
} else if (strcmp(__progname, "batch") == 0) {
program = BATCH;
options = "f:q:mv";
}
/* process whatever options we can process */
- opterr = 1;
- while ((c = getopt(argc, argv, options)) != -1)
- switch (c) {
- case 'v': /* verify time settings */
- atverify = 1;
+ while ((ch = getopt(argc, argv, options)) != -1) {
+ switch (ch) {
+ case 'a':
+ aflag = 1;
+ break;
+
+ case 'i':
+ interactive = 1;
+ force = 0;
+ break;
+
+ case 'v': /* show completed but unremoved jobs */
+ /*
+ * This option is only useful when we are invoked
+ * as atq but we accept (and ignore) this flag in
+ * the other programs for backwards compatibility.
+ */
+ vflag = 1;
break;
case 'm': /* send mail when job is complete */
@@ -688,7 +857,11 @@ main(int argc, char **argv)
break;
case 'f':
- atinput = optarg;
+ if (program == ATRM) {
+ force = 1;
+ interactive = 0;
+ } else
+ atinput = optarg;
break;
case 'q': /* specify queue */
@@ -704,46 +877,44 @@ main(int argc, char **argv)
case 'd': /* for backwards compatibility */
case 'r':
- if (program != AT)
- usage();
-
program = ATRM;
options = "";
break;
case 't':
- if (program != AT)
- usage();
- tflag++;
timer = ttime(optarg);
break;
case 'l':
- if (program != AT)
- usage();
-
program = ATQ;
- options = "q:v";
+ options = "cnvq:";
break;
case 'b':
- if (program != AT)
- usage();
-
program = BATCH;
options = "f:q:mv";
break;
case 'c':
- program = CAT;
- options = "";
+ if (program == ATQ) {
+ cflag = 1;
+ } else {
+ program = CAT;
+ options = "";
+ }
+ break;
+
+ case 'n':
+ nflag = 1;
break;
default:
usage();
break;
}
- /* end of options eating */
+ }
+ argc -= optind;
+ argv += optind;
if (!check_permission())
errx(EXIT_FAILURE, "You do not have permission to use %s.",
@@ -752,26 +923,20 @@ main(int argc, char **argv)
/* select our program */
switch (program) {
case ATQ:
- if (optind != argc)
- usage();
- list_jobs();
+ list_jobs(argc, argv, nflag, cflag);
break;
case ATRM:
case CAT:
- if (optind == argc)
+ if ((aflag && argc) || (!aflag && !argc))
usage();
exit(process_jobs(argc, argv, program));
break;
case AT:
/* Time may have been specified via the -t flag. */
- if (!tflag)
+ if (timer == -1)
timer = parsetime(argc, argv);
- if (atverify) {
- struct tm *tm = localtime(&timer);
- (void)fprintf(stderr, "%s\n", asctime(tm));
- }
writefile(timer, queue);
break;
@@ -781,16 +946,11 @@ main(int argc, char **argv)
else
queue = DEFAULT_BATCH_QUEUE;
- if (argc > optind)
+ if (argc > 0)
timer = parsetime(argc, argv);
else
timer = time(NULL);
- if (atverify) {
- struct tm *tm = localtime(&timer);
- (void)fprintf(stderr, "%s\n", asctime(tm));
- }
-
writefile(timer, queue);
break;
diff --git a/usr.bin/at/at.h b/usr.bin/at/at.h
index 660a41af0ca..121157ac42b 100644
--- a/usr.bin/at/at.h
+++ b/usr.bin/at/at.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: at.h,v 1.6 2002/05/13 16:12:07 millert Exp $ */
+/* $OpenBSD: at.h,v 1.7 2002/05/14 18:05:39 millert Exp $ */
/* $NetBSD: at.h,v 1.2 1995/03/25 18:13:32 glass Exp $ */
/*
@@ -30,10 +30,18 @@ extern int fcreated;
extern char *__progname;
extern int program;
extern char atfile[];
-extern char atverify;
+extern char vflag;
+extern char force;
+extern char interactive;
enum { ATQ, ATRM, AT, BATCH, CAT }; /* what are we running as? */
+struct atjob {
+ time_t runtimer;
+ time_t ctime;
+ char queue;
+};
+
#define AT_MAXJOBS 255 /* max jobs outstanding per user */
#define DEFAULT_BATCH_QUEUE 'E'
diff --git a/usr.bin/at/atq.1 b/usr.bin/at/atq.1
new file mode 100644
index 00000000000..37ab415efd2
--- /dev/null
+++ b/usr.bin/at/atq.1
@@ -0,0 +1,107 @@
+.\" $OpenBSD: atq.1,v 1.1 2002/05/14 18:05:39 millert Exp $
+.\"
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atq.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd May 13, 2002
+.Dt ATQ 1
+.Os
+.Sh NAME
+.Nm atq
+.Nd display the
+.Xr at 1
+job queue
+.Sh SYNOPSIS
+.Nm atq
+.Op Fl cnv
+.Op Fl q Ar queue
+.Op Ar name ...
+.Sh DESCRIPTION
+.Nm atq
+displays the queue of jobs, created by the
+.Xr at 1
+command, which are currently awaiting execution.
+Unless the user is the superuser, only the user's own jobs will be displayed.
+With no flags, the queue is sorted in the order that
+the jobs will be executed.
+.Pp
+The options are as follows:
+.Bl -tag -width "-q queueX"
+.It Fl c
+Sort the queue by the time that the jobs were submitted (created).
+By default,
+.Nm
+will sort the queue by the time that the jobs will run.
+.It Fl n
+Only print the total number of files that are currently in the queue.
+.It Fl q Ar queue
+Restrict output to jobs in the specified
+.Ar queue .
+.Sy a
+to
+.Sy z
+and
+.Sy A
+to
+.Sy Z .
+The
+.Sy c
+queue is the default for
+.Xr at 1
+and the
+.Sy E
+queue for
+.Xr batch 1 .
+By default,
+.Nm
+will display jobs in all queues.
+.It Fl v
+Jobs that have completed but have not yet been removed are also displayed.
+.El
+.Pp
+If a name(s) is provided, only those files belonging to that user(s) are
+displayed.
+.Sh FILES
+.Bl -tag -width /var/at/jobs -compact
+.It Pa /var/at/jobs
+directory containing job files
+.El
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr atrm 1 ,
+.Xr cron 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.bin/at/atrm.1 b/usr.bin/at/atrm.1
new file mode 100644
index 00000000000..ff2668bc1a8
--- /dev/null
+++ b/usr.bin/at/atrm.1
@@ -0,0 +1,93 @@
+.\" $OpenBSD: atrm.1,v 1.1 2002/05/14 18:05:39 millert Exp $
+.\"
+.\" Copyright (c) 1985, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)atrm.1 8.1 (Berkeley) 6/6/93
+.\"
+.Dd May 13, 2002
+.Dt ATRM 1
+.Os
+.Sh NAME
+.Nm atrm
+.Nd remove jobs spooled by
+.Xr at 1
+.Sh SYNOPSIS
+.Nm atrm
+.Op Fl afi
+.Oo Op Ar job
+.Op Ar name ... Oc
+.Sh DESCRIPTION
+.Nm atrm
+removes jobs that were created with the
+.Xr at 1
+command.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a
+Remove all jobs belonging to the user invoking
+.Nm atrm .
+If the user is the superuser, remove all jobs.
+.It Fl f
+All information regarding the removal of the specified jobs is suppressed.
+.It Fl i
+.Nm atrm
+asks whether a job should be removed.
+If the user responds with
+.Ql y ,
+the job will be removed.
+.El
+.Pp
+If one or more
+.Ar job
+ids are specified,
+.Nm atrm
+attempts to remove only those
+.Ar job s.
+.Pp
+If one or more user names are specified, all jobs belonging to those users
+are removed.
+Only the superuser may remove other users' jobs.
+.Sh FILES
+.Bl -tag -width /var/at/jobs -compact
+.It Pa /var/at/jobs
+directory containing job files
+.El
+.Sh SEE ALSO
+.Xr at 1 ,
+.Xr atq 1 ,
+.Xr cron 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 .
diff --git a/usr.bin/at/panic.c b/usr.bin/at/panic.c
index 007d540cce0..e9e2c635b17 100644
--- a/usr.bin/at/panic.c
+++ b/usr.bin/at/panic.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: panic.c,v 1.9 2002/05/13 16:12:07 millert Exp $ */
+/* $OpenBSD: panic.c,v 1.10 2002/05/14 18:05:39 millert Exp $ */
/* $NetBSD: panic.c,v 1.2 1995/03/25 18:13:33 glass Exp $ */
/*
@@ -26,35 +26,25 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* System Headers */
-
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
-/* Local headers */
-
-#include "panic.h"
#include "at.h"
+#include "panic.h"
#include "privs.h"
-/* File scope variables */
-
#ifndef lint
-static const char rcsid[] = "$OpenBSD: panic.c,v 1.9 2002/05/13 16:12:07 millert Exp $";
+static const char rcsid[] = "$OpenBSD: panic.c,v 1.10 2002/05/14 18:05:39 millert Exp $";
#endif
-/* External variables */
-
-/* Global functions */
-
+/*
+ * Something fatal has happened, print error message and exit.
+ */
__dead void
panic(const char *a)
{
- /*
- * Something fatal has happened, print error message and exit.
- */
(void)fprintf(stderr, "%s: %s\n", __progname, a);
if (fcreated) {
PRIV_START;
@@ -65,13 +55,14 @@ panic(const char *a)
exit(EXIT_FAILURE);
}
+/*
+ * Some operating system error; print error message and exit.
+ */
__dead void
perr(const char *a)
{
- /*
- * Some operating system error; print error message and exit.
- */
- perror(a);
+ if (!force)
+ perror(a);
if (fcreated) {
PRIV_START;
unlink(atfile);
@@ -81,10 +72,14 @@ perr(const char *a)
exit(EXIT_FAILURE);
}
+/*
+ * Two-parameter version of perr().
+ */
__dead void
perr2(const char *a, const char *b)
{
- (void)fputs(a, stderr);
+ if (!force)
+ (void)fputs(a, stderr);
perr(b);
}
@@ -96,19 +91,23 @@ usage(void)
case AT:
case CAT:
(void)fprintf(stderr,
- "Usage: at [-blmrv] [-f file] [-q queue] -t time_arg\n"
- " at [-blmrv] [-f file] [-q queue] timespec\n"
- " at -c job [job ...]\n");
+ "usage: at [-bm] [-f file] [-q queue] -t time_arg\n"
+ " at [-bm] [-f file] [-q queue] timespec\n"
+ " at -c job [job ...]\n"
+ " at -l [-q queue] [job ...]\n"
+ " at -r job [job ...]\n");
break;
case ATQ:
- (void)fprintf(stderr, "Usage: atq [-q queue] [-v]\n");
+ (void)fprintf(stderr,
+ "usage: atq [-cnv] [-q queue] [name...]\n");
break;
case ATRM:
- (void)fprintf(stderr, "Usage: atrm job [job ...]\n");
+ (void)fprintf(stderr,
+ "usage: atrm [-afi] [[job] [name] ...]\n");
break;
case BATCH:
(void)fprintf(stderr,
- "Usage: batch [-mv] [-f file] [-q queue] [timespec]\n");
+ "usage: batch [-m] [-f file] [-q queue] [timespec]\n");
break;
}
exit(EXIT_FAILURE);
diff --git a/usr.bin/at/parsetime.c b/usr.bin/at/parsetime.c
index 1c4b7b6a5f5..188b9a33a1a 100644
--- a/usr.bin/at/parsetime.c
+++ b/usr.bin/at/parsetime.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parsetime.c,v 1.10 2002/05/11 23:16:44 millert Exp $ */
+/* $OpenBSD: parsetime.c,v 1.11 2002/05/14 18:05:39 millert Exp $ */
/* $NetBSD: parsetime.c,v 1.3 1995/03/25 18:13:36 glass Exp $ */
/*
@@ -36,20 +36,16 @@
* \PLUS NUMBER MINUTES|HOURS|DAYS|WEEKS/
*/
-/* System Headers */
-
#include <sys/types.h>
+#include <err.h>
#include <errno.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <tzfile.h>
#include <unistd.h>
-#include <ctype.h>
-#include <err.h>
-
-/* Local headers */
#include "at.h"
#include "panic.h"
@@ -138,24 +134,19 @@ struct {
{ "sat", SAT, 0 },
};
-/* File scope variables */
-
static char **scp; /* scanner - pointer at arglist */
static char scc; /* scanner - count of remaining arguments */
static char *sct; /* scanner - next char pointer in current argument */
static int need; /* scanner - need to advance to next argument */
-
static char *sc_token; /* scanner - token buffer */
static size_t sc_len; /* scanner - lenght of token buffer */
static int sc_tokid; /* scanner - token id */
static int sc_tokplur; /* scanner - is token plural? */
#ifndef lint
-static const char rcsid[] = "$OpenBSD: parsetime.c,v 1.10 2002/05/11 23:16:44 millert Exp $";
+static const char rcsid[] = "$OpenBSD: parsetime.c,v 1.11 2002/05/14 18:05:39 millert Exp $";
#endif
-/* Local functions */
-
/*
* parse a token, checking if it's something special to us
*/
@@ -173,7 +164,7 @@ parse_token(char *arg)
/* not special - must be some random id */
return (ID);
-} /* parse_token */
+}
/*
@@ -191,7 +182,7 @@ init_scanner(int argc, char **argv)
if ((sc_token = (char *) malloc(sc_len)) == NULL)
panic("Insufficient virtual memory");
-} /* init_scanner */
+}
/*
* token() fetches a token from the input stream
@@ -259,8 +250,8 @@ token(void)
return ((sc_tokid = SLASH));
else
return ((sc_tokid = JUNK));
- } /* while (1) */
-} /* token */
+ }
+}
/*
@@ -270,7 +261,7 @@ static void
plonk(int tok)
{
panic((tok == EOF) ? "incomplete time" : "garbled time");
-} /* plonk */
+}
/*
@@ -281,7 +272,7 @@ expect(int desired)
{
if (token() != desired)
plonk(sc_tokid); /* and we die here... */
-} /* expect */
+}
/*
@@ -321,7 +312,7 @@ dateadd(int minutes, struct tm *tm)
tm->tm_hour = 0;
}
}
-} /* dateadd */
+}
/*
@@ -356,7 +347,7 @@ plus(struct tm *tm)
}
plonk(sc_tokid);
-} /* plus */
+}
/*
@@ -423,7 +414,7 @@ tod(struct tm *tm)
tm->tm_hour = 0;
tm->tm_mday++;
}
-} /* tod */
+}
/*
@@ -460,7 +451,7 @@ assign_date(struct tm *tm, int mday, int mon, int year)
if (year >= 0)
tm->tm_year = year;
-} /* assign_date */
+}
/*
@@ -575,10 +566,8 @@ month(struct tm *tm)
assign_date(tm, mday, mon, year);
break;
} /* case */
-} /* month */
-
+}
-/* Global functions */
time_t
parsetime(int argc, char **argv)
@@ -599,10 +588,10 @@ parsetime(int argc, char **argv)
runtime.tm_sec = 0;
runtime.tm_isdst = 0;
- if (argc <= optind)
+ if (argc == 0)
usage();
- init_scanner(argc - optind, argv + optind);
+ init_scanner(argc, argv);
switch (token()) {
case NOW: /* now is optional prefix for PLUS tree */
@@ -666,4 +655,4 @@ parsetime(int argc, char **argv)
panic("Trying to travel back in time");
return (runtimer);
-} /* parsetime */
+}
diff --git a/usr.bin/at/perm.c b/usr.bin/at/perm.c
index 38031ed7b76..6ff4eabfe5a 100644
--- a/usr.bin/at/perm.c
+++ b/usr.bin/at/perm.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: perm.c,v 1.3 2002/05/11 23:16:44 millert Exp $ */
+/* $OpenBSD: perm.c,v 1.4 2002/05/14 18:05:39 millert Exp $ */
/*
* perm.c - check user permission for at(1)
@@ -25,8 +25,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/* System Headers */
-
#include <sys/types.h>
#include <errno.h>
#include <pwd.h>
@@ -36,24 +34,17 @@
#include <string.h>
#include <unistd.h>
-/* Local headers */
-
#include "at.h"
#include "panic.h"
#include "pathnames.h"
#include "privs.h"
-/* File scope variables */
-
#ifndef lint
-static const char rcsid[] = "$OpenBSD: perm.c,v 1.3 2002/05/11 23:16:44 millert Exp $";
+static const char rcsid[] = "$OpenBSD: perm.c,v 1.4 2002/05/14 18:05:39 millert Exp $";
#endif
-/* Function declarations */
-
static int check_for_user(FILE *, const char *);
-/* Local functions */
static int
check_for_user(FILE *fp, const char *name)
@@ -78,8 +69,6 @@ check_for_user(FILE *fp, const char *name)
}
-/* Global functions */
-
int
check_permission(void)
{
@@ -91,7 +80,7 @@ check_permission(void)
return 1;
if ((pentry = getpwuid(uid)) == NULL) {
- perror("Cannot access user database");
+ perror("Cannot access password database");
exit(EXIT_FAILURE);
}