version 1.34, 2003/02/18 02:25:39 |
version 1.35, 2003/02/20 20:38:08 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* $NetBSD: at.c,v 1.4 1995/03/25 18:13:31 glass Exp $ */ |
|
|
|
/* |
/* |
* at.c : Put file into atrun queue |
* at.c : Put file into atrun queue |
|
|
* Copyright (C) 1993 David Parsons |
* Copyright (C) 1993 David Parsons |
* |
* |
* Traditional BSD behavior and other significant modifications |
* Traditional BSD behavior and other significant modifications |
* Copyright (C) 2002 Todd C. Miller |
* Copyright (C) 2002-2003 Todd C. Miller |
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
|
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
*/ |
|
|
#include <sys/param.h> |
#define MAIN_PROGRAM |
#include <sys/socket.h> |
|
#include <sys/stat.h> |
|
#include <sys/time.h> |
|
#include <sys/un.h> |
|
|
|
#include <ctype.h> |
#include "cron.h" |
#include <dirent.h> |
|
#include <err.h> |
|
#include <errno.h> |
|
#include <fcntl.h> |
|
#include <limits.h> |
|
#include <locale.h> |
|
#include <pwd.h> |
|
#include <signal.h> |
|
#include <stddef.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <time.h> |
|
#include <unistd.h> |
|
#include <utime.h> |
|
#include <utmp.h> |
|
|
|
#if (MAXLOGNAME-1) > UT_NAMESIZE |
|
#define LOGNAMESIZE UT_NAMESIZE |
|
#else |
|
#define LOGNAMESIZE (MAXLOGNAME-1) |
|
#endif |
|
|
|
#include "at.h" |
#include "at.h" |
#include "panic.h" |
|
#include "parsetime.h" |
|
#include "perm.h" |
|
#include "pathnames.h" |
|
#define MAIN |
|
#include "privs.h" |
#include "privs.h" |
|
#include <limits.h> |
|
|
#define ALARMC 10 /* Number of seconds to wait for timeout */ |
#define ALARMC 10 /* Number of seconds to wait for timeout */ |
#define TIMESIZE 50 /* Size of buffer passed to strftime() */ |
#define TIMESIZE 50 /* Size of buffer passed to strftime() */ |
|
|
}; |
}; |
|
|
int program = AT; /* default program mode */ |
int program = AT; /* default program mode */ |
char atfile[PATH_MAX]; /* path to the at spool file */ |
char atfile[MAX_FNAME]; /* path to the at spool file */ |
int fcreated; /* whether or not we created the file yet */ |
int fcreated; /* whether or not we created the file yet */ |
char *atinput = NULL; /* where to get input from */ |
char *atinput = NULL; /* where to get input from */ |
char atqueue = 0; /* which queue to examine for jobs (atq) */ |
char atqueue = 0; /* which queue to examine for jobs (atq) */ |
|
|
|
|
static void sigc(int); |
static void sigc(int); |
static void alarmc(int); |
static void alarmc(int); |
static void writefile(time_t, char); |
static void writefile(const char *, time_t, char); |
static void list_jobs(int, char **, int, int); |
static void list_jobs(int, char **, int, int); |
static void poke_daemon(void); |
|
static time_t ttime(const char *); |
static time_t ttime(const char *); |
|
static int check_permission(void); |
|
static void panic(const char *); |
|
static void perr(const char *); |
|
static void perr2(const char *, const char *); |
|
static void usage(void); |
|
time_t parsetime(int, char **); |
|
|
static void |
/* |
sigc(int signo) |
* Something fatal has happened, print error message and exit. |
|
*/ |
|
static __dead void |
|
panic(const char *a) |
{ |
{ |
/* If the user presses ^C, remove the spool file and exit. */ |
(void)fprintf(stderr, "%s: %s\n", ProgramName, a); |
if (fcreated) { |
if (fcreated) { |
PRIV_START; |
PRIV_START; |
(void)unlink(atfile); |
unlink(atfile); |
PRIV_END; |
PRIV_END; |
} |
} |
|
|
_exit(EXIT_FAILURE); |
exit(ERROR_EXIT); |
} |
} |
|
|
static void |
/* |
alarmc(int signo) |
* Two-parameter version of panic(). |
|
*/ |
|
static __dead void |
|
panic2(const char *a, const char *b) |
{ |
{ |
char buf[1024]; |
(void)fprintf(stderr, "%s: %s%s\n", ProgramName, a, b); |
|
if (fcreated) { |
|
PRIV_START; |
|
unlink(atfile); |
|
PRIV_END; |
|
} |
|
|
/* Time out after some seconds. */ |
exit(ERROR_EXIT); |
strlcpy(buf, __progname, sizeof(buf)); |
} |
strlcat(buf, ": File locking timed out\n", sizeof(buf)); |
|
write(STDERR_FILENO, buf, strlen(buf)); |
/* |
|
* Some operating system error; print error message and exit. |
|
*/ |
|
static __dead void |
|
perr(const char *a) |
|
{ |
|
if (!force) |
|
perror(a); |
if (fcreated) { |
if (fcreated) { |
PRIV_START; |
PRIV_START; |
unlink(atfile); |
unlink(atfile); |
PRIV_END; |
PRIV_END; |
} |
} |
_exit(EXIT_FAILURE); |
|
|
exit(ERROR_EXIT); |
} |
} |
|
|
|
/* |
|
* Two-parameter version of perr(). |
|
*/ |
|
static __dead void |
|
perr2(const char *a, const char *b) |
|
{ |
|
if (!force) |
|
(void)fputs(a, stderr); |
|
perr(b); |
|
} |
|
|
|
static void |
|
sigc(int signo) |
|
{ |
|
/* If the user presses ^C, remove the spool file and exit. */ |
|
if (fcreated) { |
|
PRIV_START; |
|
(void)unlink(atfile); |
|
PRIV_END; |
|
} |
|
|
|
_exit(ERROR_EXIT); |
|
} |
|
|
|
static void |
|
alarmc(int signo) |
|
{ |
|
/* just return */ |
|
} |
|
|
static int |
static int |
newjob(time_t runtimer, int queue) |
newjob(time_t runtimer, int queue) |
{ |
{ |
|
|
* queues instead... |
* queues instead... |
*/ |
*/ |
for (i = 0; i < 120; i++) { |
for (i = 0; i < 120; i++) { |
snprintf(atfile, sizeof(atfile), "%s/%ld.%c", |
snprintf(atfile, sizeof(atfile), "%s/%ld.%c", AT_DIR, |
_PATH_ATJOBS, (long)runtimer, queue); |
(long)runtimer, queue); |
fd = open(atfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); |
fd = open(atfile, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR); |
if (fd >= 0) |
if (fd >= 0) |
return (fd); |
return (fd); |
|
|
* writing a job. |
* writing a job. |
*/ |
*/ |
static void |
static void |
writefile(time_t runtimer, char queue) |
writefile(const char *cwd, time_t runtimer, char queue) |
{ |
{ |
char *ap, *mailname, *shell; |
const char *ap; |
|
char *mailname, *shell; |
char timestr[TIMESIZE]; |
char timestr[TIMESIZE]; |
char path[PATH_MAX]; |
|
struct passwd *pass_entry; |
struct passwd *pass_entry; |
struct tm runtime; |
struct tm runtime; |
int fdes, lockdes, fd2; |
int fdes, lockdes, fd2; |
|
|
* Install the signal handler for SIGINT; terminate after removing the |
* Install the signal handler for SIGINT; terminate after removing the |
* spool file if necessary |
* spool file if necessary |
*/ |
*/ |
memset(&act, 0, sizeof act); |
bzero(&act, sizeof act); |
act.sa_handler = sigc; |
act.sa_handler = sigc; |
sigemptyset(&act.sa_mask); |
sigemptyset(&act.sa_mask); |
act.sa_flags = 0; |
act.sa_flags = 0; |
|
|
|
|
PRIV_START; |
PRIV_START; |
|
|
|
if ((lockdes = open(AT_DIR, O_RDONLY, 0)) < 0) |
|
perr("Cannot open jobs dir"); |
|
|
/* |
/* |
* Lock the jobs dir so we don't have to worry about someone |
* Lock the jobs dir so we don't have to worry about someone |
* else grabbing a file name out from under us. |
* else grabbing a file name out from under us. |
* Set an alarm so we don't sleep forever waiting on the lock. |
* Set an alarm so we don't sleep forever waiting on the lock. |
* If we don't succeed with ALARMC seconds, something is wrong... |
* If we don't succeed with ALARMC seconds, something is wrong... |
*/ |
*/ |
memset(&act, 0, sizeof act); |
bzero(&act, sizeof act); |
act.sa_handler = alarmc; |
act.sa_handler = alarmc; |
sigemptyset(&act.sa_mask); |
sigemptyset(&act.sa_mask); |
act.sa_flags = 0; |
#ifdef SA_INTERRUPT |
|
act.sa_flags = SA_INTERRUPT; |
|
#endif |
sigaction(SIGALRM, &act, NULL); |
sigaction(SIGALRM, &act, NULL); |
alarm(ALARMC); |
alarm(ALARMC); |
lockdes = open(_PATH_ATJOBS, O_RDONLY|O_EXLOCK, 0); |
ch = flock(lockdes, LOCK_EX); |
alarm(0); |
alarm(0); |
|
if (ch != 0) |
|
panic("Unable to lock jobs dir"); |
|
|
if (lockdes < 0) |
|
perr("Cannot lock jobs dir"); |
|
|
|
/* |
/* |
* Create the file. The x bit is only going to be set after it has |
* 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 |
* been completely written out, to make sure it is not executed in |
|
|
mailname = getenv("USER"); |
mailname = getenv("USER"); |
|
|
if ((mailname == NULL) || (mailname[0] == '\0') || |
if ((mailname == NULL) || (mailname[0] == '\0') || |
(strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname) == NULL)) { |
(strlen(mailname) > MAX_UNAME) || (getpwnam(mailname) == NULL)) { |
pass_entry = getpwuid(real_uid); |
pass_entry = getpwuid(real_uid); |
if (pass_entry != NULL) |
if (pass_entry != NULL) |
mailname = pass_entry->pw_name; |
mailname = pass_entry->pw_name; |
|
|
perr("Cannot open input file"); |
perr("Cannot open input file"); |
} |
} |
(void)fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n", |
(void)fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n", |
(long)real_uid, (long)real_gid, LOGNAMESIZE, mailname, send_mail); |
(long)real_uid, (long)real_gid, MAX_UNAME, mailname, send_mail); |
|
|
/* Write out the umask at the time of invocation */ |
/* Write out the umask at the time of invocation */ |
(void)fprintf(fp, "umask %o\n", cmask); |
(void)fprintf(fp, "umask %o\n", cmask); |
|
|
* Cd to the directory at the time and write out all the |
* Cd to the directory at the time and write out all the |
* commands the user supplies from stdin. |
* commands the user supplies from stdin. |
*/ |
*/ |
if ((ap = getcwd(path, sizeof(path))) == NULL) |
|
perr("Cannot get current working directory"); |
|
(void)fputs("cd ", fp); |
(void)fputs("cd ", fp); |
for (; *ap != '\0'; ap++) { |
for (ap = cwd; *ap != '\0'; ap++) { |
if (*ap == '\n') |
if (*ap == '\n') |
fprintf(fp, "\"\n\""); |
fprintf(fp, "\"\n\""); |
else { |
else { |
|
|
(void)close(fd2); |
(void)close(fd2); |
|
|
/* Poke cron so it knows to reload the at spool. */ |
/* Poke cron so it knows to reload the at spool. */ |
poke_daemon(); |
PRIV_START; |
|
poke_daemon(AT_DIR, RELOAD_AT); |
|
PRIV_END; |
|
|
runtime = *localtime(&runtimer); |
runtime = *localtime(&runtimer); |
strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime); |
strftime(timestr, TIMESIZE, "%a %b %e %T %Y", &runtime); |
(void)fprintf(stderr, "commands will be executed using %s\n", shell); |
(void)fprintf(stderr, "commands will be executed using %s\n", shell); |
(void)fprintf(stderr, "job %s at %s\n", &atfile[sizeof(_PATH_ATJOBS)], |
(void)fprintf(stderr, "job %s at %s\n", &atfile[sizeof(AT_DIR)], |
timestr); |
timestr); |
} |
} |
|
|
|
|
|
|
/* |
/* |
* List all of a user's jobs in the queue, by looping through |
* 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 |
* AT_DIR, or all jobs if we are root. If argc is > 0, argv |
* contains the list of users whose jobs shall be displayed. By |
* contains the list of users whose jobs shall be displayed. By |
* default, the list is sorted by execution date and queue. If |
* default, the list is sorted by execution date and queue. If |
* csort is non-zero jobs will be sorted by creation/submission date. |
* csort is non-zero jobs will be sorted by creation/submission date. |
|
|
|
|
if (argc) { |
if (argc) { |
if ((uids = malloc(sizeof(uid_t) * argc)) == NULL) |
if ((uids = malloc(sizeof(uid_t) * argc)) == NULL) |
err(EXIT_FAILURE, "malloc"); |
panic("Insufficient virtual memory"); |
|
|
for (i = 0; i < argc; i++) { |
for (i = 0; i < argc; i++) { |
if ((pw = getpwnam(argv[i])) == NULL) |
if ((pw = getpwnam(argv[i])) == NULL) |
errx(EXIT_FAILURE, |
panic2(argv[i], ": invalid user name"); |
"%s: invalid user name", argv[i]); |
|
if (pw->pw_uid != real_uid && real_uid != 0) |
if (pw->pw_uid != real_uid && real_uid != 0) |
errx(EXIT_FAILURE, "Only the superuser may " |
panic("Only the superuser may display other users' jobs"); |
"display other users' jobs"); |
|
uids[i] = pw->pw_uid; |
uids[i] = pw->pw_uid; |
} |
} |
} else |
} else |
uids = NULL; |
uids = NULL; |
|
|
shortformat = strcmp(__progname, "at") == 0; |
shortformat = strcmp(ProgramName, "at") == 0; |
|
|
PRIV_START; |
PRIV_START; |
|
|
if (chdir(_PATH_ATJOBS) != 0) |
if (chdir(AT_DIR) != 0) |
perr2("Cannot change to ", _PATH_ATJOBS); |
perr2("Cannot change to ", AT_DIR); |
|
|
if ((spool = opendir(".")) == NULL) |
if ((spool = opendir(".")) == NULL) |
perr2("Cannot open ", _PATH_ATJOBS); |
perr2("Cannot open ", AT_DIR); |
|
|
PRIV_END; |
PRIV_END; |
|
|
if (fstat(dirfd(spool), &stbuf) != 0) |
if (fstat(spool->dd_fd, &stbuf) != 0) |
perr2("Cannot stat ", _PATH_ATJOBS); |
perr2("Cannot stat ", AT_DIR); |
|
|
/* |
/* |
* The directory's link count should give us a good idea |
* The directory's link count should give us a good idea |
|
|
maxjobs = stbuf.st_nlink + 4; |
maxjobs = stbuf.st_nlink + 4; |
atjobs = (struct atjob **)malloc(maxjobs * sizeof(struct atjob *)); |
atjobs = (struct atjob **)malloc(maxjobs * sizeof(struct atjob *)); |
if (atjobs == NULL) |
if (atjobs == NULL) |
err(EXIT_FAILURE, "malloc"); |
panic("Insufficient virtual memory"); |
|
|
/* Loop over every file in the directory. */ |
/* Loop over every file in the directory. */ |
while ((dirent = readdir(spool)) != NULL) { |
while ((dirent = readdir(spool)) != NULL) { |
PRIV_START; |
PRIV_START; |
|
|
if (stat(dirent->d_name, &stbuf) != 0) |
if (stat(dirent->d_name, &stbuf) != 0) |
perr2("Cannot stat in ", _PATH_ATJOBS); |
perr2("Cannot stat in ", AT_DIR); |
|
|
PRIV_END; |
PRIV_END; |
|
|
|
|
|
|
job = (struct atjob *)malloc(sizeof(struct atjob)); |
job = (struct atjob *)malloc(sizeof(struct atjob)); |
if (job == NULL) |
if (job == NULL) |
err(EXIT_FAILURE, "malloc"); |
panic("Insufficient virtual memory"); |
job->runtimer = runtimer; |
job->runtimer = runtimer; |
job->ctime = stbuf.st_ctime; |
job->ctime = stbuf.st_ctime; |
job->queue = queue; |
job->queue = queue; |
if (numjobs == maxjobs) { |
if (numjobs == maxjobs) { |
maxjobs *= 2; |
maxjobs *= 2; |
atjobs = realloc(atjobs, maxjobs * sizeof(struct atjob *)); |
atjobs = realloc(atjobs, maxjobs * sizeof(job)); |
if (atjobs == NULL) |
if (atjobs == NULL) |
err(EXIT_FAILURE, "realloc"); |
panic("Insufficient virtual memory"); |
} |
} |
atjobs[numjobs++] = job; |
atjobs[numjobs++] = job; |
} |
} |
|
|
} |
} |
|
|
/* |
/* |
* Loop through all jobs in _PATH_ATJOBS and display or delete ones |
* Loop through all jobs in AT_DIR and display or delete ones |
* that match argv (may be job or username), or all if argc == 0. |
* that match argv (may be job or username), or all if argc == 0. |
* Only the superuser may display/delete other people's jobs. |
* Only the superuser may display/delete other people's jobs. |
*/ |
*/ |
|
|
|
|
PRIV_START; |
PRIV_START; |
|
|
if (chdir(_PATH_ATJOBS) != 0) |
if (chdir(AT_DIR) != 0) |
perr2("Cannot change to ", _PATH_ATJOBS); |
perr2("Cannot change to ", AT_DIR); |
|
|
if ((spool = opendir(".")) == NULL) |
if ((spool = opendir(".")) == NULL) |
perr2("Cannot open ", _PATH_ATJOBS); |
perr2("Cannot open ", AT_DIR); |
|
|
PRIV_END; |
PRIV_END; |
|
|
|
|
if (argc > 0) { |
if (argc > 0) { |
if ((jobs = malloc(sizeof(char *) * argc)) == NULL || |
if ((jobs = malloc(sizeof(char *) * argc)) == NULL || |
(uids = malloc(sizeof(uid_t) * argc)) == NULL) |
(uids = malloc(sizeof(uid_t) * argc)) == NULL) |
err(EXIT_FAILURE, "malloc"); |
panic("Insufficient virtual memory"); |
|
|
for (i = 0; i < argc; i++) { |
for (i = 0; i < argc; i++) { |
l = strtol(argv[i], &ep, 10); |
l = strtol(argv[i], &ep, 10); |
|
|
*(ep + 2) == '\0' && l > 0 && l < INT_MAX) |
*(ep + 2) == '\0' && l > 0 && l < INT_MAX) |
jobs[jobs_len++] = argv[i]; |
jobs[jobs_len++] = argv[i]; |
else if ((pw = getpwnam(argv[i])) != NULL) { |
else if ((pw = getpwnam(argv[i])) != NULL) { |
if (real_uid != pw->pw_uid && real_uid != 0) |
if (real_uid != pw->pw_uid && real_uid != 0) { |
errx(EXIT_FAILURE, |
fprintf(stderr, "%s: Only the superuser" |
"Only the superuser may %s" |
" may %s other users' jobs", |
" other users' jobs", what == ATRM |
ProgramName, what == ATRM |
? "remove" : "print"); |
? "remove" : "view"); |
|
exit(ERROR_EXIT); |
|
} |
uids[uids_len++] = pw->pw_uid; |
uids[uids_len++] = pw->pw_uid; |
} else |
} else |
errx(EXIT_FAILURE, |
panic2(argv[i], ": invalid user name"); |
"%s: invalid user name", argv[i]); |
|
} |
} |
} |
} |
|
|
|
|
|
|
PRIV_START; |
PRIV_START; |
if (stat(dirent->d_name, &stbuf) != 0) |
if (stat(dirent->d_name, &stbuf) != 0) |
perr2("Cannot stat in ", _PATH_ATJOBS); |
perr2("Cannot stat in ", AT_DIR); |
PRIV_END; |
PRIV_END; |
|
|
if (stbuf.st_uid != real_uid && real_uid != 0) |
if (stbuf.st_uid != real_uid && real_uid != 0) |
|
|
job_matches = (argc == 0) ? 1 : 0; |
job_matches = (argc == 0) ? 1 : 0; |
if (!job_matches) { |
if (!job_matches) { |
for (i = 0; i < jobs_len; i++) { |
for (i = 0; i < jobs_len; i++) { |
if (jobs[i] != NULL && |
if (strcmp(dirent->d_name, jobs[i]) == 0) { |
strcmp(dirent->d_name, jobs[i]) == 0) { |
|
jobs[i] = NULL; |
jobs[i] = NULL; |
job_matches = 1; |
job_matches = 1; |
break; |
break; |
|
|
break; |
break; |
|
|
default: |
default: |
errx(EXIT_FAILURE, |
panic("Internal error"); |
"Internal error, process_jobs = %d", |
|
what); |
|
break; |
break; |
} |
} |
} |
} |
|
|
for (error = 0, i = 0; i < jobs_len; i++) { |
for (error = 0, i = 0; i < jobs_len; i++) { |
if (jobs[i] != NULL) { |
if (jobs[i] != NULL) { |
if (!force) |
if (!force) |
warnx("%s: no such job", jobs[i]); |
fprintf(stderr, "%s: %s: no such job", |
|
ProgramName, jobs[i]); |
error++; |
error++; |
} |
} |
} |
} |
|
|
free(uids); |
free(uids); |
|
|
/* If we modied the spool, poke cron so it knows to reload. */ |
/* If we modied the spool, poke cron so it knows to reload. */ |
if (changed) |
if (changed) { |
poke_daemon(); |
PRIV_START; |
|
if (chdir(CRONDIR) != 0) |
|
perror(CRONDIR); |
|
else |
|
poke_daemon(AT_DIR, RELOAD_AT); |
|
PRIV_END; |
|
} |
|
|
return (error); |
return (error); |
} |
} |
|
|
"[[CC]YY]MMDDhhmm[.SS]"); |
"[[CC]YY]MMDDhhmm[.SS]"); |
} |
} |
|
|
#define RELOAD_AT 0x4 /* XXX - from cron's macros.h */ |
static int |
|
check_permission(void) |
|
{ |
|
int ok; |
|
uid_t uid = geteuid(); |
|
struct passwd *pw; |
|
|
/* XXX - share with crontab */ |
if ((pw = getpwuid(uid)) == NULL) { |
static void |
perror("Cannot access password database"); |
poke_daemon() { |
exit(ERROR_EXIT); |
int sock, flags; |
} |
unsigned char poke; |
|
struct sockaddr_un sun; |
|
|
|
PRIV_START; |
PRIV_START; |
|
|
if (utime(_PATH_ATJOBS, NULL) < 0) { |
ok = allowed(pw->pw_name, AT_ALLOW, AT_DENY); |
warn("can't update mtime on %s", _PATH_ATJOBS); |
|
PRIV_END; |
|
return; |
|
} |
|
|
|
/* Failure to poke the daemon socket is not a fatal error. */ |
|
(void) signal(SIGPIPE, SIG_IGN); |
|
strlcpy(sun.sun_path, CRONDIR "/" SPOOL_DIR "/" CRONSOCK, |
|
sizeof(sun.sun_path)); |
|
sun.sun_family = AF_UNIX; |
|
sun.sun_len = SUN_LEN(&sun); |
|
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 && |
|
connect(sock, (struct sockaddr *)&sun, sizeof(sun)) == 0) { |
|
poke = RELOAD_AT; |
|
write(sock, &poke, 1); |
|
close(sock); |
|
} else |
|
fprintf(stderr, "Warning, cron does not appear to be running.\n"); |
|
(void) signal(SIGPIPE, SIG_DFL); |
|
|
|
PRIV_END; |
PRIV_END; |
|
|
|
return (ok); |
} |
} |
|
|
|
static void |
|
usage(void) |
|
{ |
|
/* Print usage and exit. */ |
|
switch (program) { |
|
case AT: |
|
case CAT: |
|
(void)fprintf(stderr, |
|
"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 [-cnv] [-q queue] [name...]\n"); |
|
break; |
|
case ATRM: |
|
(void)fprintf(stderr, |
|
"usage: atrm [-afi] [[job] [name] ...]\n"); |
|
break; |
|
case BATCH: |
|
(void)fprintf(stderr, |
|
"usage: batch [-m] [-f file] [-q queue] [timespec]\n"); |
|
break; |
|
} |
|
exit(ERROR_EXIT); |
|
} |
|
|
int |
int |
main(int argc, char **argv) |
main(int argc, char **argv) |
{ |
{ |
|
|
char queue = DEFAULT_AT_QUEUE; |
char queue = DEFAULT_AT_QUEUE; |
char queue_set = 0; |
char queue_set = 0; |
char *options = "q:f:t:bcdlmrv"; /* default options for at */ |
char *options = "q:f:t:bcdlmrv"; /* default options for at */ |
|
char cwd[MAX_FNAME]; |
int ch; |
int ch; |
int aflag = 0; |
int aflag = 0; |
int cflag = 0; |
int cflag = 0; |
int nflag = 0; |
int nflag = 0; |
|
|
|
if ((ProgramName = strrchr(argv[0], '/')) != NULL) |
|
ProgramName++; |
|
else |
|
ProgramName = argv[0]; |
|
|
RELINQUISH_PRIVS; |
RELINQUISH_PRIVS; |
|
|
/* find out what this program is supposed to do */ |
/* find out what this program is supposed to do */ |
if (strcmp(__progname, "atq") == 0) { |
if (strcmp(ProgramName, "atq") == 0) { |
program = ATQ; |
program = ATQ; |
options = "cnvq:"; |
options = "cnvq:"; |
} else if (strcmp(__progname, "atrm") == 0) { |
} else if (strcmp(ProgramName, "atrm") == 0) { |
program = ATRM; |
program = ATRM; |
options = "afi"; |
options = "afi"; |
} else if (strcmp(__progname, "batch") == 0) { |
} else if (strcmp(ProgramName, "batch") == 0) { |
program = BATCH; |
program = BATCH; |
options = "f:q:mv"; |
options = "f:q:mv"; |
} |
} |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
|
|
|
if (getcwd(cwd, sizeof(cwd)) == NULL) |
|
perr("Cannot get current working directory"); |
|
|
|
set_cron_cwd(); |
|
|
if (!check_permission()) |
if (!check_permission()) |
errx(EXIT_FAILURE, "You do not have permission to use %s.", |
panic("You do not have permission to use at."); |
__progname); |
|
|
|
/* select our program */ |
/* select our program */ |
switch (program) { |
switch (program) { |
|
|
|
|
case AT: |
case AT: |
/* Time may have been specified via the -t flag. */ |
/* Time may have been specified via the -t flag. */ |
if (timer == -1) |
if (timer == -1) { |
timer = parsetime(argc, argv); |
if (argc == 0) |
writefile(timer, queue); |
usage(); |
|
else if ((timer = parsetime(argc, argv)) == -1) |
|
exit(ERROR_EXIT); |
|
} |
|
writefile(cwd, timer, queue); |
break; |
break; |
|
|
case BATCH: |
case BATCH: |
|
|
else |
else |
queue = DEFAULT_BATCH_QUEUE; |
queue = DEFAULT_BATCH_QUEUE; |
|
|
if (argc > 0) |
if (argc == 0) |
timer = parsetime(argc, argv); |
|
else |
|
timer = time(NULL); |
timer = time(NULL); |
|
else if ((timer = parsetime(argc, argv)) == -1) |
|
exit(ERROR_EXIT); |
|
|
writefile(timer, queue); |
writefile(cwd, timer, queue); |
break; |
break; |
|
|
default: |
default: |
panic("Internal error"); |
panic("Internal error"); |
break; |
break; |
} |
} |
exit(EXIT_SUCCESS); |
exit(OK_EXIT); |
} |
} |