[BACK]Return to at.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / at

Diff for /src/usr.bin/at/at.c between version 1.34 and 1.35

version 1.34, 2003/02/18 02:25:39 version 1.35, 2003/02/20 20:38:08
Line 1 
Line 1 
 /*      $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
Line 9 
Line 8 
  *  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
Line 32 
Line 31 
  * 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() */
Line 85 
Line 53 
 };  };
   
 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) */
Line 96 
Line 64 
   
 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)
 {  {
Line 142 
Line 164 
          * 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);
Line 157 
Line 179 
  * 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;
Line 178 
Line 200 
          * 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;
Line 186 
Line 208 
   
         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
Line 243 
Line 269 
                 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;
Line 268 
Line 294 
                         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);
Line 329 
Line 355 
          * 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 {
Line 377 
Line 401 
         (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);
 }  }
   
Line 440 
Line 466 
   
 /*  /*
  * 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.
Line 461 
Line 487 
   
         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
Line 499 
Line 523 
         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;
   
Line 546 
Line 570 
   
                 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;
         }          }
Line 597 
Line 621 
 }  }
   
 /*  /*
  * 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.
  */   */
Line 618 
Line 642 
   
         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;
   
Line 633 
Line 657 
         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);
Line 641 
Line 665 
                             *(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]);  
                 }                  }
         }          }
   
Line 659 
Line 684 
   
                 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)
Line 676 
Line 701 
                 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;
Line 730 
Line 754 
                                 break;                                  break;
   
                         default:                          default:
                                 errx(EXIT_FAILURE,                                  panic("Internal error");
                                     "Internal error, process_jobs = %d",  
                                     what);  
                                 break;                                  break;
                         }                          }
                 }                  }
Line 740 
Line 762 
         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++;
                 }                  }
         }          }
Line 748 
Line 771 
         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);
 }  }
Line 823 
Line 852 
                     "[[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)
 {  {
Line 865 
Line 910 
         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";
         }          }
Line 969 
Line 1020 
         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) {
Line 988 
Line 1043 
   
         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:
Line 999 
Line 1058 
                 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);
 }  }

Legend:
Removed from v.1.34  
changed lines
  Added in v.1.35