1/* 2 * at.c : Put file into atrun queue 3 * Copyright (C) 1993, 1994 Thomas Koenig 4 * 5 * Atrun & Atq modifications 6 * Copyright (C) 1993 David Parsons 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. The name of the author(s) may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h>
| 1/* 2 * at.c : Put file into atrun queue 3 * Copyright (C) 1993, 1994 Thomas Koenig 4 * 5 * Atrun & Atq modifications 6 * Copyright (C) 1993 David Parsons 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. The name of the author(s) may not be used to endorse or promote 14 * products derived from this software without specific prior written 15 * permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h>
|
30__FBSDID("$FreeBSD: head/usr.bin/at/at.c 96216 2002-05-08 11:23:45Z kuriyama $");
| 30__FBSDID("$FreeBSD: head/usr.bin/at/at.c 96701 2002-05-16 00:47:14Z tjr $");
|
31 32#define _USE_BSD 1 33 34/* System Headers */ 35 36#include <sys/param.h> 37#include <sys/stat.h> 38#include <sys/time.h> 39#include <sys/wait.h> 40#include <ctype.h> 41#include <dirent.h> 42#include <err.h> 43#include <errno.h> 44#include <fcntl.h> 45#ifndef __FreeBSD__ 46#include <getopt.h> 47#endif 48#ifdef __FreeBSD__ 49#include <locale.h> 50#endif 51#include <pwd.h> 52#include <signal.h> 53#include <stddef.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <time.h> 58#include <unistd.h> 59#include <utmp.h> 60 61#if (MAXLOGNAME-1) > UT_NAMESIZE 62#define LOGNAMESIZE UT_NAMESIZE 63#else 64#define LOGNAMESIZE (MAXLOGNAME-1) 65#endif 66 67/* Local headers */ 68 69#include "at.h" 70#include "panic.h" 71#include "parsetime.h" 72#include "perm.h" 73 74#define MAIN 75#include "privs.h" 76 77/* Macros */ 78 79#ifndef ATJOB_DIR 80#define ATJOB_DIR "/usr/spool/atjobs/" 81#endif 82 83#ifndef LFILE 84#define LFILE ATJOB_DIR ".lockfile" 85#endif 86 87#ifndef ATJOB_MX 88#define ATJOB_MX 255 89#endif 90 91#define ALARMC 10 /* Number of seconds to wait for timeout */ 92 93#define SIZE 255 94#define TIMESIZE 50 95 96enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */ 97 98/* File scope variables */ 99 100const char *no_export[] = 101{ 102 "TERM", "TERMCAP", "DISPLAY", "_" 103} ; 104static int send_mail = 0; 105 106/* External variables */ 107 108extern char **environ; 109int fcreated; 110char atfile[] = ATJOB_DIR "12345678901234"; 111 112char *atinput = (char*)0; /* where to get input from */ 113char atqueue = 0; /* which queue to examine for jobs (atq) */ 114char atverify = 0; /* verify time instead of queuing job */ 115char *namep; 116 117/* Function declarations */ 118 119static void sigc(int signo); 120static void alarmc(int signo); 121static char *cwdname(void); 122static void writefile(time_t runtimer, char queue);
| 31 32#define _USE_BSD 1 33 34/* System Headers */ 35 36#include <sys/param.h> 37#include <sys/stat.h> 38#include <sys/time.h> 39#include <sys/wait.h> 40#include <ctype.h> 41#include <dirent.h> 42#include <err.h> 43#include <errno.h> 44#include <fcntl.h> 45#ifndef __FreeBSD__ 46#include <getopt.h> 47#endif 48#ifdef __FreeBSD__ 49#include <locale.h> 50#endif 51#include <pwd.h> 52#include <signal.h> 53#include <stddef.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include <time.h> 58#include <unistd.h> 59#include <utmp.h> 60 61#if (MAXLOGNAME-1) > UT_NAMESIZE 62#define LOGNAMESIZE UT_NAMESIZE 63#else 64#define LOGNAMESIZE (MAXLOGNAME-1) 65#endif 66 67/* Local headers */ 68 69#include "at.h" 70#include "panic.h" 71#include "parsetime.h" 72#include "perm.h" 73 74#define MAIN 75#include "privs.h" 76 77/* Macros */ 78 79#ifndef ATJOB_DIR 80#define ATJOB_DIR "/usr/spool/atjobs/" 81#endif 82 83#ifndef LFILE 84#define LFILE ATJOB_DIR ".lockfile" 85#endif 86 87#ifndef ATJOB_MX 88#define ATJOB_MX 255 89#endif 90 91#define ALARMC 10 /* Number of seconds to wait for timeout */ 92 93#define SIZE 255 94#define TIMESIZE 50 95 96enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */ 97 98/* File scope variables */ 99 100const char *no_export[] = 101{ 102 "TERM", "TERMCAP", "DISPLAY", "_" 103} ; 104static int send_mail = 0; 105 106/* External variables */ 107 108extern char **environ; 109int fcreated; 110char atfile[] = ATJOB_DIR "12345678901234"; 111 112char *atinput = (char*)0; /* where to get input from */ 113char atqueue = 0; /* which queue to examine for jobs (atq) */ 114char atverify = 0; /* verify time instead of queuing job */ 115char *namep; 116 117/* Function declarations */ 118 119static void sigc(int signo); 120static void alarmc(int signo); 121static char *cwdname(void); 122static void writefile(time_t runtimer, char queue);
|
123static void list_jobs(void);
| 123static void list_jobs(long *, int);
|
124static long nextjob(void); 125static time_t ttime(const char *arg);
| 124static long nextjob(void); 125static time_t ttime(const char *arg);
|
| 126static int in_job_list(long, long *, int); 127static long *get_job_list(int, char *[], int *);
|
126 127/* Signal catching functions */ 128 129static void sigc(int signo __unused) 130{ 131/* If the user presses ^C, remove the spool file and exit 132 */ 133 if (fcreated) 134 { 135 PRIV_START 136 unlink(atfile); 137 PRIV_END 138 } 139 140 _exit(EXIT_FAILURE); 141} 142 143static void alarmc(int signo __unused) 144{ 145 char buf[1024]; 146 147 /* Time out after some seconds. */ 148 strlcpy(buf, namep, sizeof(buf)); 149 strlcat(buf, ": file locking timed out\n", sizeof(buf)); 150 write(STDERR_FILENO, buf, strlen(buf)); 151 sigc(0); 152} 153 154/* Local functions */ 155 156static char *cwdname(void) 157{ 158/* Read in the current directory; the name will be overwritten on 159 * subsequent calls. 160 */ 161 static char *ptr = NULL; 162 static size_t size = SIZE; 163 164 if (ptr == NULL) 165 if ((ptr = malloc(size)) == NULL) 166 errx(EXIT_FAILURE, "virtual memory exhausted"); 167 168 while (1) 169 { 170 if (ptr == NULL) 171 panic("out of memory"); 172 173 if (getcwd(ptr, size-1) != NULL) 174 return ptr; 175 176 if (errno != ERANGE) 177 perr("cannot get directory"); 178 179 free (ptr); 180 size += SIZE; 181 if ((ptr = malloc(size)) == NULL) 182 errx(EXIT_FAILURE, "virtual memory exhausted"); 183 } 184} 185 186static long 187nextjob() 188{ 189 long jobno; 190 FILE *fid; 191 192 if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != (FILE*)0) { 193 if (fscanf(fid, "%5lx", &jobno) == 1) { 194 rewind(fid); 195 jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */ 196 fprintf(fid, "%05lx\n", jobno); 197 } 198 else 199 jobno = EOF; 200 fclose(fid); 201 return jobno; 202 } 203 else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != (FILE*)0) { 204 fprintf(fid, "%05lx\n", jobno = 1); 205 fclose(fid); 206 return 1; 207 } 208 return EOF; 209} 210 211static void 212writefile(time_t runtimer, char queue) 213{ 214/* This does most of the work if at or batch are invoked for writing a job. 215 */ 216 long jobno; 217 char *ap, *ppos, *mailname; 218 struct passwd *pass_entry; 219 struct stat statbuf; 220 int fdes, lockdes, fd2; 221 FILE *fp, *fpin; 222 struct sigaction act; 223 char **atenv; 224 int ch; 225 mode_t cmask; 226 struct flock lock; 227 228#ifdef __FreeBSD__ 229 (void) setlocale(LC_TIME, ""); 230#endif 231 232/* Install the signal handler for SIGINT; terminate after removing the 233 * spool file if necessary 234 */ 235 act.sa_handler = sigc; 236 sigemptyset(&(act.sa_mask)); 237 act.sa_flags = 0; 238 239 sigaction(SIGINT, &act, NULL); 240 241 ppos = atfile + strlen(ATJOB_DIR); 242 243 /* Loop over all possible file names for running something at this 244 * particular time, see if a file is there; the first empty slot at any 245 * particular time is used. Lock the file LFILE first to make sure 246 * we're alone when doing this. 247 */ 248 249 PRIV_START 250 251 if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0) 252 perr("cannot open lockfile " LFILE); 253 254 lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; 255 lock.l_len = 0; 256 257 act.sa_handler = alarmc; 258 sigemptyset(&(act.sa_mask)); 259 act.sa_flags = 0; 260 261 /* Set an alarm so a timeout occurs after ALARMC seconds, in case 262 * something is seriously broken. 263 */ 264 sigaction(SIGALRM, &act, NULL); 265 alarm(ALARMC); 266 fcntl(lockdes, F_SETLKW, &lock); 267 alarm(0); 268 269 if ((jobno = nextjob()) == EOF) 270 perr("cannot generate job number"); 271 272 sprintf(ppos, "%c%5lx%8lx", queue, 273 jobno, (unsigned long) (runtimer/60)); 274 275 for(ap=ppos; *ap != '\0'; ap ++) 276 if (*ap == ' ') 277 *ap = '0'; 278 279 if (stat(atfile, &statbuf) != 0) 280 if (errno != ENOENT) 281 perr("cannot access " ATJOB_DIR); 282 283 /* Create the file. The x bit is only going to be set after it has 284 * been completely written out, to make sure it is not executed in the 285 * meantime. To make sure they do not get deleted, turn off their r 286 * bit. Yes, this is a kluge. 287 */ 288 cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR); 289 if ((fdes = creat(atfile, O_WRONLY)) == -1) 290 perr("cannot create atjob file"); 291 292 if ((fd2 = dup(fdes)) <0) 293 perr("error in dup() of job file"); 294 295 if(fchown(fd2, real_uid, real_gid) != 0) 296 perr("cannot give away file"); 297 298 PRIV_END 299 300 /* We no longer need suid root; now we just need to be able to write 301 * to the directory, if necessary. 302 */ 303 304 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 305 306 /* We've successfully created the file; let's set the flag so it 307 * gets removed in case of an interrupt or error. 308 */ 309 fcreated = 1; 310 311 /* Now we can release the lock, so other people can access it 312 */ 313 lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; 314 lock.l_len = 0; 315 fcntl(lockdes, F_SETLKW, &lock); 316 close(lockdes); 317 318 if((fp = fdopen(fdes, "w")) == NULL) 319 panic("cannot reopen atjob file"); 320 321 /* Get the userid to mail to, first by trying getlogin(), which reads 322 * /etc/utmp, then from LOGNAME, finally from getpwuid(). 323 */ 324 mailname = getlogin(); 325 if (mailname == NULL) 326 mailname = getenv("LOGNAME"); 327 328 if ((mailname == NULL) || (mailname[0] == '\0') 329 || (strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname)==NULL)) 330 { 331 pass_entry = getpwuid(real_uid); 332 if (pass_entry != NULL) 333 mailname = pass_entry->pw_name; 334 } 335 336 if (atinput != (char *) NULL) 337 { 338 fpin = freopen(atinput, "r", stdin); 339 if (fpin == NULL) 340 perr("cannot open input file"); 341 } 342 fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n", 343 (long) real_uid, (long) real_gid, LOGNAMESIZE, mailname, send_mail); 344 345 /* Write out the umask at the time of invocation 346 */ 347 fprintf(fp, "umask %lo\n", (unsigned long) cmask); 348 349 /* Write out the environment. Anything that may look like a 350 * special character to the shell is quoted, except for \n, which is 351 * done with a pair of "'s. Don't export the no_export list (such 352 * as TERM or DISPLAY) because we don't want these. 353 */ 354 for (atenv= environ; *atenv != NULL; atenv++) 355 { 356 int export = 1; 357 char *eqp; 358 359 eqp = strchr(*atenv, '='); 360 if (ap == NULL) 361 eqp = *atenv; 362 else 363 { 364 size_t i; 365 for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++) 366 { 367 export = export 368 && (strncmp(*atenv, no_export[i], 369 (size_t) (eqp-*atenv)) != 0); 370 } 371 eqp++; 372 } 373 374 if (export) 375 { 376 fwrite(*atenv, sizeof(char), eqp-*atenv, fp); 377 for(ap = eqp;*ap != '\0'; ap++) 378 { 379 if (*ap == '\n') 380 fprintf(fp, "\"\n\""); 381 else 382 { 383 if (!isalnum(*ap)) { 384 switch (*ap) { 385 case '%': case '/': case '{': case '[': 386 case ']': case '=': case '}': case '@': 387 case '+': case '#': case ',': case '.': 388 case ':': case '-': case '_': 389 break; 390 default: 391 fputc('\\', fp); 392 break; 393 } 394 } 395 fputc(*ap, fp); 396 } 397 } 398 fputs("; export ", fp); 399 fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp); 400 fputc('\n', fp); 401 402 } 403 } 404 /* Cd to the directory at the time and write out all the 405 * commands the user supplies from stdin. 406 */ 407 fprintf(fp, "cd "); 408 for (ap = cwdname(); *ap != '\0'; ap++) 409 { 410 if (*ap == '\n') 411 fprintf(fp, "\"\n\""); 412 else 413 { 414 if (*ap != '/' && !isalnum(*ap)) 415 fputc('\\', fp); 416 417 fputc(*ap, fp); 418 } 419 } 420 /* Test cd's exit status: die if the original directory has been 421 * removed, become unreadable or whatever 422 */ 423 fprintf(fp, " || {\n\t echo 'Execution directory " 424 "inaccessible' >&2\n\t exit 1\n}\n"); 425 426 while((ch = getchar()) != EOF) 427 fputc(ch, fp); 428 429 fprintf(fp, "\n"); 430 if (ferror(fp)) 431 panic("output error"); 432 433 if (ferror(stdin)) 434 panic("input error"); 435 436 fclose(fp); 437 438 /* Set the x bit so that we're ready to start executing 439 */ 440 441 if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0) 442 perr("cannot give away file"); 443 444 close(fd2); 445 fprintf(stderr, "Job %ld will be executed using /bin/sh\n", jobno); 446} 447
| 128 129/* Signal catching functions */ 130 131static void sigc(int signo __unused) 132{ 133/* If the user presses ^C, remove the spool file and exit 134 */ 135 if (fcreated) 136 { 137 PRIV_START 138 unlink(atfile); 139 PRIV_END 140 } 141 142 _exit(EXIT_FAILURE); 143} 144 145static void alarmc(int signo __unused) 146{ 147 char buf[1024]; 148 149 /* Time out after some seconds. */ 150 strlcpy(buf, namep, sizeof(buf)); 151 strlcat(buf, ": file locking timed out\n", sizeof(buf)); 152 write(STDERR_FILENO, buf, strlen(buf)); 153 sigc(0); 154} 155 156/* Local functions */ 157 158static char *cwdname(void) 159{ 160/* Read in the current directory; the name will be overwritten on 161 * subsequent calls. 162 */ 163 static char *ptr = NULL; 164 static size_t size = SIZE; 165 166 if (ptr == NULL) 167 if ((ptr = malloc(size)) == NULL) 168 errx(EXIT_FAILURE, "virtual memory exhausted"); 169 170 while (1) 171 { 172 if (ptr == NULL) 173 panic("out of memory"); 174 175 if (getcwd(ptr, size-1) != NULL) 176 return ptr; 177 178 if (errno != ERANGE) 179 perr("cannot get directory"); 180 181 free (ptr); 182 size += SIZE; 183 if ((ptr = malloc(size)) == NULL) 184 errx(EXIT_FAILURE, "virtual memory exhausted"); 185 } 186} 187 188static long 189nextjob() 190{ 191 long jobno; 192 FILE *fid; 193 194 if ((fid = fopen(ATJOB_DIR ".SEQ", "r+")) != (FILE*)0) { 195 if (fscanf(fid, "%5lx", &jobno) == 1) { 196 rewind(fid); 197 jobno = (1+jobno) % 0xfffff; /* 2^20 jobs enough? */ 198 fprintf(fid, "%05lx\n", jobno); 199 } 200 else 201 jobno = EOF; 202 fclose(fid); 203 return jobno; 204 } 205 else if ((fid = fopen(ATJOB_DIR ".SEQ", "w")) != (FILE*)0) { 206 fprintf(fid, "%05lx\n", jobno = 1); 207 fclose(fid); 208 return 1; 209 } 210 return EOF; 211} 212 213static void 214writefile(time_t runtimer, char queue) 215{ 216/* This does most of the work if at or batch are invoked for writing a job. 217 */ 218 long jobno; 219 char *ap, *ppos, *mailname; 220 struct passwd *pass_entry; 221 struct stat statbuf; 222 int fdes, lockdes, fd2; 223 FILE *fp, *fpin; 224 struct sigaction act; 225 char **atenv; 226 int ch; 227 mode_t cmask; 228 struct flock lock; 229 230#ifdef __FreeBSD__ 231 (void) setlocale(LC_TIME, ""); 232#endif 233 234/* Install the signal handler for SIGINT; terminate after removing the 235 * spool file if necessary 236 */ 237 act.sa_handler = sigc; 238 sigemptyset(&(act.sa_mask)); 239 act.sa_flags = 0; 240 241 sigaction(SIGINT, &act, NULL); 242 243 ppos = atfile + strlen(ATJOB_DIR); 244 245 /* Loop over all possible file names for running something at this 246 * particular time, see if a file is there; the first empty slot at any 247 * particular time is used. Lock the file LFILE first to make sure 248 * we're alone when doing this. 249 */ 250 251 PRIV_START 252 253 if ((lockdes = open(LFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0) 254 perr("cannot open lockfile " LFILE); 255 256 lock.l_type = F_WRLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; 257 lock.l_len = 0; 258 259 act.sa_handler = alarmc; 260 sigemptyset(&(act.sa_mask)); 261 act.sa_flags = 0; 262 263 /* Set an alarm so a timeout occurs after ALARMC seconds, in case 264 * something is seriously broken. 265 */ 266 sigaction(SIGALRM, &act, NULL); 267 alarm(ALARMC); 268 fcntl(lockdes, F_SETLKW, &lock); 269 alarm(0); 270 271 if ((jobno = nextjob()) == EOF) 272 perr("cannot generate job number"); 273 274 sprintf(ppos, "%c%5lx%8lx", queue, 275 jobno, (unsigned long) (runtimer/60)); 276 277 for(ap=ppos; *ap != '\0'; ap ++) 278 if (*ap == ' ') 279 *ap = '0'; 280 281 if (stat(atfile, &statbuf) != 0) 282 if (errno != ENOENT) 283 perr("cannot access " ATJOB_DIR); 284 285 /* Create the file. The x bit is only going to be set after it has 286 * been completely written out, to make sure it is not executed in the 287 * meantime. To make sure they do not get deleted, turn off their r 288 * bit. Yes, this is a kluge. 289 */ 290 cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR); 291 if ((fdes = creat(atfile, O_WRONLY)) == -1) 292 perr("cannot create atjob file"); 293 294 if ((fd2 = dup(fdes)) <0) 295 perr("error in dup() of job file"); 296 297 if(fchown(fd2, real_uid, real_gid) != 0) 298 perr("cannot give away file"); 299 300 PRIV_END 301 302 /* We no longer need suid root; now we just need to be able to write 303 * to the directory, if necessary. 304 */ 305 306 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 307 308 /* We've successfully created the file; let's set the flag so it 309 * gets removed in case of an interrupt or error. 310 */ 311 fcreated = 1; 312 313 /* Now we can release the lock, so other people can access it 314 */ 315 lock.l_type = F_UNLCK; lock.l_whence = SEEK_SET; lock.l_start = 0; 316 lock.l_len = 0; 317 fcntl(lockdes, F_SETLKW, &lock); 318 close(lockdes); 319 320 if((fp = fdopen(fdes, "w")) == NULL) 321 panic("cannot reopen atjob file"); 322 323 /* Get the userid to mail to, first by trying getlogin(), which reads 324 * /etc/utmp, then from LOGNAME, finally from getpwuid(). 325 */ 326 mailname = getlogin(); 327 if (mailname == NULL) 328 mailname = getenv("LOGNAME"); 329 330 if ((mailname == NULL) || (mailname[0] == '\0') 331 || (strlen(mailname) > LOGNAMESIZE) || (getpwnam(mailname)==NULL)) 332 { 333 pass_entry = getpwuid(real_uid); 334 if (pass_entry != NULL) 335 mailname = pass_entry->pw_name; 336 } 337 338 if (atinput != (char *) NULL) 339 { 340 fpin = freopen(atinput, "r", stdin); 341 if (fpin == NULL) 342 perr("cannot open input file"); 343 } 344 fprintf(fp, "#!/bin/sh\n# atrun uid=%ld gid=%ld\n# mail %*s %d\n", 345 (long) real_uid, (long) real_gid, LOGNAMESIZE, mailname, send_mail); 346 347 /* Write out the umask at the time of invocation 348 */ 349 fprintf(fp, "umask %lo\n", (unsigned long) cmask); 350 351 /* Write out the environment. Anything that may look like a 352 * special character to the shell is quoted, except for \n, which is 353 * done with a pair of "'s. Don't export the no_export list (such 354 * as TERM or DISPLAY) because we don't want these. 355 */ 356 for (atenv= environ; *atenv != NULL; atenv++) 357 { 358 int export = 1; 359 char *eqp; 360 361 eqp = strchr(*atenv, '='); 362 if (ap == NULL) 363 eqp = *atenv; 364 else 365 { 366 size_t i; 367 for (i=0; i<sizeof(no_export)/sizeof(no_export[0]); i++) 368 { 369 export = export 370 && (strncmp(*atenv, no_export[i], 371 (size_t) (eqp-*atenv)) != 0); 372 } 373 eqp++; 374 } 375 376 if (export) 377 { 378 fwrite(*atenv, sizeof(char), eqp-*atenv, fp); 379 for(ap = eqp;*ap != '\0'; ap++) 380 { 381 if (*ap == '\n') 382 fprintf(fp, "\"\n\""); 383 else 384 { 385 if (!isalnum(*ap)) { 386 switch (*ap) { 387 case '%': case '/': case '{': case '[': 388 case ']': case '=': case '}': case '@': 389 case '+': case '#': case ',': case '.': 390 case ':': case '-': case '_': 391 break; 392 default: 393 fputc('\\', fp); 394 break; 395 } 396 } 397 fputc(*ap, fp); 398 } 399 } 400 fputs("; export ", fp); 401 fwrite(*atenv, sizeof(char), eqp-*atenv -1, fp); 402 fputc('\n', fp); 403 404 } 405 } 406 /* Cd to the directory at the time and write out all the 407 * commands the user supplies from stdin. 408 */ 409 fprintf(fp, "cd "); 410 for (ap = cwdname(); *ap != '\0'; ap++) 411 { 412 if (*ap == '\n') 413 fprintf(fp, "\"\n\""); 414 else 415 { 416 if (*ap != '/' && !isalnum(*ap)) 417 fputc('\\', fp); 418 419 fputc(*ap, fp); 420 } 421 } 422 /* Test cd's exit status: die if the original directory has been 423 * removed, become unreadable or whatever 424 */ 425 fprintf(fp, " || {\n\t echo 'Execution directory " 426 "inaccessible' >&2\n\t exit 1\n}\n"); 427 428 while((ch = getchar()) != EOF) 429 fputc(ch, fp); 430 431 fprintf(fp, "\n"); 432 if (ferror(fp)) 433 panic("output error"); 434 435 if (ferror(stdin)) 436 panic("input error"); 437 438 fclose(fp); 439 440 /* Set the x bit so that we're ready to start executing 441 */ 442 443 if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) < 0) 444 perr("cannot give away file"); 445 446 close(fd2); 447 fprintf(stderr, "Job %ld will be executed using /bin/sh\n", jobno); 448} 449
|
| 450static int 451in_job_list(long job, long *joblist, int len) 452{ 453 int i; 454 455 for (i = 0; i < len; i++) 456 if (job == joblist[i]) 457 return 1; 458 459 return 0; 460} 461
|
448static void
| 462static void
|
449list_jobs()
| 463list_jobs(long *joblist, int len)
|
450{ 451 /* List all a user's jobs in the queue, by looping through ATJOB_DIR, 452 * or everybody's if we are root 453 */ 454 struct passwd *pw; 455 DIR *spool; 456 struct dirent *dirent; 457 struct stat buf; 458 struct tm runtime; 459 unsigned long ctm; 460 char queue; 461 long jobno; 462 time_t runtimer; 463 char timestr[TIMESIZE]; 464 int first=1; 465 466#ifdef __FreeBSD__ 467 (void) setlocale(LC_TIME, ""); 468#endif 469 470 PRIV_START 471 472 if (chdir(ATJOB_DIR) != 0) 473 perr("cannot change to " ATJOB_DIR); 474 475 if ((spool = opendir(".")) == NULL) 476 perr("cannot open " ATJOB_DIR); 477 478 /* Loop over every file in the directory 479 */ 480 while((dirent = readdir(spool)) != NULL) { 481 if (stat(dirent->d_name, &buf) != 0) 482 perr("cannot stat in " ATJOB_DIR); 483 484 /* See it's a regular file and has its x bit turned on and 485 * is the user's 486 */ 487 if (!S_ISREG(buf.st_mode) 488 || ((buf.st_uid != real_uid) && ! (real_uid == 0)) 489 || !(S_IXUSR & buf.st_mode || atverify)) 490 continue; 491 492 if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3) 493 continue; 494
| 464{ 465 /* List all a user's jobs in the queue, by looping through ATJOB_DIR, 466 * or everybody's if we are root 467 */ 468 struct passwd *pw; 469 DIR *spool; 470 struct dirent *dirent; 471 struct stat buf; 472 struct tm runtime; 473 unsigned long ctm; 474 char queue; 475 long jobno; 476 time_t runtimer; 477 char timestr[TIMESIZE]; 478 int first=1; 479 480#ifdef __FreeBSD__ 481 (void) setlocale(LC_TIME, ""); 482#endif 483 484 PRIV_START 485 486 if (chdir(ATJOB_DIR) != 0) 487 perr("cannot change to " ATJOB_DIR); 488 489 if ((spool = opendir(".")) == NULL) 490 perr("cannot open " ATJOB_DIR); 491 492 /* Loop over every file in the directory 493 */ 494 while((dirent = readdir(spool)) != NULL) { 495 if (stat(dirent->d_name, &buf) != 0) 496 perr("cannot stat in " ATJOB_DIR); 497 498 /* See it's a regular file and has its x bit turned on and 499 * is the user's 500 */ 501 if (!S_ISREG(buf.st_mode) 502 || ((buf.st_uid != real_uid) && ! (real_uid == 0)) 503 || !(S_IXUSR & buf.st_mode || atverify)) 504 continue; 505 506 if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3) 507 continue; 508
|
| 509 /* If jobs are given, only list those jobs */ 510 if (joblist && !in_job_list(jobno, joblist, len)) 511 continue; 512
|
495 if (atqueue && (queue != atqueue)) 496 continue; 497 498 runtimer = 60*(time_t) ctm; 499 runtime = *localtime(&runtimer); 500 strftime(timestr, TIMESIZE, "%+", &runtime); 501 if (first) { 502 printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n"); 503 first=0; 504 } 505 pw = getpwuid(buf.st_uid); 506 507 printf("%s\t%-16s%c%s\t%ld\n", 508 timestr, 509 pw ? pw->pw_name : "???", 510 queue, 511 (S_IXUSR & buf.st_mode) ? "":"(done)", 512 jobno); 513 } 514 PRIV_END 515} 516 517static void 518process_jobs(int argc, char **argv, int what) 519{ 520 /* Delete every argument (job - ID) given 521 */ 522 int i; 523 struct stat buf; 524 DIR *spool; 525 struct dirent *dirent; 526 unsigned long ctm; 527 char queue; 528 long jobno; 529 530 PRIV_START 531 532 if (chdir(ATJOB_DIR) != 0) 533 perr("cannot change to " ATJOB_DIR); 534 535 if ((spool = opendir(".")) == NULL) 536 perr("cannot open " ATJOB_DIR); 537 538 PRIV_END 539 540 /* Loop over every file in the directory 541 */ 542 while((dirent = readdir(spool)) != NULL) { 543 544 PRIV_START 545 if (stat(dirent->d_name, &buf) != 0) 546 perr("cannot stat in " ATJOB_DIR); 547 PRIV_END 548 549 if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3) 550 continue; 551 552 for (i=optind; i < argc; i++) { 553 if (atoi(argv[i]) == jobno) { 554 if ((buf.st_uid != real_uid) && !(real_uid == 0)) 555 errx(EXIT_FAILURE, "%s: not owner", argv[i]); 556 switch (what) { 557 case ATRM: 558 559 PRIV_START 560 561 if (unlink(dirent->d_name) != 0) 562 perr(dirent->d_name); 563 564 PRIV_END 565 566 break; 567 568 case CAT: 569 { 570 FILE *fp; 571 int ch; 572 573 PRIV_START 574 575 fp = fopen(dirent->d_name,"r"); 576 577 PRIV_END 578 579 if (!fp) { 580 perr("cannot open file"); 581 } 582 while((ch = getc(fp)) != EOF) { 583 putchar(ch); 584 } 585 } 586 break; 587 588 default: 589 errx(EXIT_FAILURE, "internal error, process_jobs = %d", 590 what); 591 } 592 } 593 } 594 } 595} /* delete_jobs */ 596 597#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 598 599static time_t 600ttime(const char *arg) 601{ 602 /* 603 * This is pretty much a copy of stime_arg1() from touch.c. I changed 604 * the return value and the argument list because it's more convenient 605 * (IMO) to do everything in one place. - Joe Halpin 606 */ 607 struct timeval tv[2]; 608 time_t now; 609 struct tm *t; 610 int yearset; 611 char *p; 612 613 if (gettimeofday(&tv[0], NULL)) 614 panic("Cannot get current time"); 615 616 /* Start with the current time. */ 617 now = tv[0].tv_sec; 618 if ((t = localtime(&now)) == NULL) 619 panic("localtime"); 620 /* [[CC]YY]MMDDhhmm[.SS] */ 621 if ((p = strchr(arg, '.')) == NULL) 622 t->tm_sec = 0; /* Seconds defaults to 0. */ 623 else { 624 if (strlen(p + 1) != 2) 625 goto terr; 626 *p++ = '\0'; 627 t->tm_sec = ATOI2(p); 628 } 629 630 yearset = 0; 631 switch(strlen(arg)) { 632 case 12: /* CCYYMMDDhhmm */ 633 t->tm_year = ATOI2(arg); 634 t->tm_year *= 100; 635 yearset = 1; 636 /* FALLTHROUGH */ 637 case 10: /* YYMMDDhhmm */ 638 if (yearset) { 639 yearset = ATOI2(arg); 640 t->tm_year += yearset; 641 } else { 642 yearset = ATOI2(arg); 643 t->tm_year = yearset + 2000; 644 } 645 t->tm_year -= 1900; /* Convert to UNIX time. */ 646 /* FALLTHROUGH */ 647 case 8: /* MMDDhhmm */ 648 t->tm_mon = ATOI2(arg); 649 --t->tm_mon; /* Convert from 01-12 to 00-11 */ 650 t->tm_mday = ATOI2(arg); 651 t->tm_hour = ATOI2(arg); 652 t->tm_min = ATOI2(arg); 653 break; 654 default: 655 goto terr; 656 } 657 658 t->tm_isdst = -1; /* Figure out DST. */ 659 tv[0].tv_sec = tv[1].tv_sec = mktime(t); 660 if (tv[0].tv_sec != -1) 661 return tv[0].tv_sec; 662 else 663terr: 664 panic( 665 "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); 666} 667
| 513 if (atqueue && (queue != atqueue)) 514 continue; 515 516 runtimer = 60*(time_t) ctm; 517 runtime = *localtime(&runtimer); 518 strftime(timestr, TIMESIZE, "%+", &runtime); 519 if (first) { 520 printf("Date\t\t\t\tOwner\t\tQueue\tJob#\n"); 521 first=0; 522 } 523 pw = getpwuid(buf.st_uid); 524 525 printf("%s\t%-16s%c%s\t%ld\n", 526 timestr, 527 pw ? pw->pw_name : "???", 528 queue, 529 (S_IXUSR & buf.st_mode) ? "":"(done)", 530 jobno); 531 } 532 PRIV_END 533} 534 535static void 536process_jobs(int argc, char **argv, int what) 537{ 538 /* Delete every argument (job - ID) given 539 */ 540 int i; 541 struct stat buf; 542 DIR *spool; 543 struct dirent *dirent; 544 unsigned long ctm; 545 char queue; 546 long jobno; 547 548 PRIV_START 549 550 if (chdir(ATJOB_DIR) != 0) 551 perr("cannot change to " ATJOB_DIR); 552 553 if ((spool = opendir(".")) == NULL) 554 perr("cannot open " ATJOB_DIR); 555 556 PRIV_END 557 558 /* Loop over every file in the directory 559 */ 560 while((dirent = readdir(spool)) != NULL) { 561 562 PRIV_START 563 if (stat(dirent->d_name, &buf) != 0) 564 perr("cannot stat in " ATJOB_DIR); 565 PRIV_END 566 567 if(sscanf(dirent->d_name, "%c%5lx%8lx", &queue, &jobno, &ctm)!=3) 568 continue; 569 570 for (i=optind; i < argc; i++) { 571 if (atoi(argv[i]) == jobno) { 572 if ((buf.st_uid != real_uid) && !(real_uid == 0)) 573 errx(EXIT_FAILURE, "%s: not owner", argv[i]); 574 switch (what) { 575 case ATRM: 576 577 PRIV_START 578 579 if (unlink(dirent->d_name) != 0) 580 perr(dirent->d_name); 581 582 PRIV_END 583 584 break; 585 586 case CAT: 587 { 588 FILE *fp; 589 int ch; 590 591 PRIV_START 592 593 fp = fopen(dirent->d_name,"r"); 594 595 PRIV_END 596 597 if (!fp) { 598 perr("cannot open file"); 599 } 600 while((ch = getc(fp)) != EOF) { 601 putchar(ch); 602 } 603 } 604 break; 605 606 default: 607 errx(EXIT_FAILURE, "internal error, process_jobs = %d", 608 what); 609 } 610 } 611 } 612 } 613} /* delete_jobs */ 614 615#define ATOI2(ar) ((ar)[0] - '0') * 10 + ((ar)[1] - '0'); (ar) += 2; 616 617static time_t 618ttime(const char *arg) 619{ 620 /* 621 * This is pretty much a copy of stime_arg1() from touch.c. I changed 622 * the return value and the argument list because it's more convenient 623 * (IMO) to do everything in one place. - Joe Halpin 624 */ 625 struct timeval tv[2]; 626 time_t now; 627 struct tm *t; 628 int yearset; 629 char *p; 630 631 if (gettimeofday(&tv[0], NULL)) 632 panic("Cannot get current time"); 633 634 /* Start with the current time. */ 635 now = tv[0].tv_sec; 636 if ((t = localtime(&now)) == NULL) 637 panic("localtime"); 638 /* [[CC]YY]MMDDhhmm[.SS] */ 639 if ((p = strchr(arg, '.')) == NULL) 640 t->tm_sec = 0; /* Seconds defaults to 0. */ 641 else { 642 if (strlen(p + 1) != 2) 643 goto terr; 644 *p++ = '\0'; 645 t->tm_sec = ATOI2(p); 646 } 647 648 yearset = 0; 649 switch(strlen(arg)) { 650 case 12: /* CCYYMMDDhhmm */ 651 t->tm_year = ATOI2(arg); 652 t->tm_year *= 100; 653 yearset = 1; 654 /* FALLTHROUGH */ 655 case 10: /* YYMMDDhhmm */ 656 if (yearset) { 657 yearset = ATOI2(arg); 658 t->tm_year += yearset; 659 } else { 660 yearset = ATOI2(arg); 661 t->tm_year = yearset + 2000; 662 } 663 t->tm_year -= 1900; /* Convert to UNIX time. */ 664 /* FALLTHROUGH */ 665 case 8: /* MMDDhhmm */ 666 t->tm_mon = ATOI2(arg); 667 --t->tm_mon; /* Convert from 01-12 to 00-11 */ 668 t->tm_mday = ATOI2(arg); 669 t->tm_hour = ATOI2(arg); 670 t->tm_min = ATOI2(arg); 671 break; 672 default: 673 goto terr; 674 } 675 676 t->tm_isdst = -1; /* Figure out DST. */ 677 tv[0].tv_sec = tv[1].tv_sec = mktime(t); 678 if (tv[0].tv_sec != -1) 679 return tv[0].tv_sec; 680 else 681terr: 682 panic( 683 "out of range or illegal time specification: [[CC]YY]MMDDhhmm[.SS]"); 684} 685
|
| 686static long * 687get_job_list(int argc, char *argv[], int *joblen) 688{ 689 int i, len; 690 long *joblist; 691 char *ep; 692 693 joblist = NULL; 694 len = argc; 695 if (len > 0) { 696 if ((joblist = malloc(len * sizeof(*joblist))) == NULL) 697 panic("out of memory"); 698 699 for (i = 0; i < argc; i++) { 700 errno = 0; 701 if ((joblist[i] = strtol(argv[i], &ep, 10)) < 0 || 702 ep == argv[i] || *ep != '\0' || errno) 703 panic("invalid job number"); 704 } 705 } 706 707 *joblen = len; 708 return joblist; 709} 710
|
668int 669main(int argc, char **argv) 670{ 671 int c; 672 char queue = DEFAULT_AT_QUEUE; 673 char queue_set = 0; 674 char *pgm; 675 676 int program = AT; /* our default program */ 677 const char *options = "q:f:t:rmvldbc"; /* default options for at */ 678 time_t timer;
| 711int 712main(int argc, char **argv) 713{ 714 int c; 715 char queue = DEFAULT_AT_QUEUE; 716 char queue_set = 0; 717 char *pgm; 718 719 int program = AT; /* our default program */ 720 const char *options = "q:f:t:rmvldbc"; /* default options for at */ 721 time_t timer;
|
| 722 long *joblist; 723 int joblen;
|
679
| 724
|
| 725 joblist = NULL; 726 joblen = 0;
|
680 timer = -1; 681 RELINQUISH_PRIVS 682 683 /* Eat any leading paths 684 */ 685 if ((pgm = strrchr(argv[0], '/')) == NULL) 686 pgm = argv[0]; 687 else 688 pgm++; 689 690 namep = pgm; 691 692 /* find out what this program is supposed to do 693 */ 694 if (strcmp(pgm, "atq") == 0) { 695 program = ATQ; 696 options = "q:v"; 697 } 698 else if (strcmp(pgm, "atrm") == 0) { 699 program = ATRM; 700 options = ""; 701 } 702 else if (strcmp(pgm, "batch") == 0) { 703 program = BATCH; 704 options = "f:q:mv"; 705 } 706 707 /* process whatever options we can process 708 */ 709 opterr=1; 710 while ((c=getopt(argc, argv, options)) != -1) 711 switch (c) { 712 case 'v': /* verify time settings */ 713 atverify = 1; 714 break; 715 716 case 'm': /* send mail when job is complete */ 717 send_mail = 1; 718 break; 719 720 case 'f': 721 atinput = optarg; 722 break; 723 724 case 'q': /* specify queue */ 725 if (strlen(optarg) > 1) 726 usage(); 727 728 atqueue = queue = *optarg; 729 if (!(islower(queue)||isupper(queue))) 730 usage(); 731 732 queue_set = 1; 733 break; 734 735 case 'd': 736 warnx("-d is deprecated; use -r instead"); 737 /* fall through to 'r' */ 738 739 case 'r': 740 if (program != AT) 741 usage(); 742 743 program = ATRM; 744 options = ""; 745 break; 746 747 case 't': 748 if (program != AT) 749 usage(); 750 timer = ttime(optarg); 751 break; 752 753 case 'l': 754 if (program != AT) 755 usage(); 756 757 program = ATQ;
| 727 timer = -1; 728 RELINQUISH_PRIVS 729 730 /* Eat any leading paths 731 */ 732 if ((pgm = strrchr(argv[0], '/')) == NULL) 733 pgm = argv[0]; 734 else 735 pgm++; 736 737 namep = pgm; 738 739 /* find out what this program is supposed to do 740 */ 741 if (strcmp(pgm, "atq") == 0) { 742 program = ATQ; 743 options = "q:v"; 744 } 745 else if (strcmp(pgm, "atrm") == 0) { 746 program = ATRM; 747 options = ""; 748 } 749 else if (strcmp(pgm, "batch") == 0) { 750 program = BATCH; 751 options = "f:q:mv"; 752 } 753 754 /* process whatever options we can process 755 */ 756 opterr=1; 757 while ((c=getopt(argc, argv, options)) != -1) 758 switch (c) { 759 case 'v': /* verify time settings */ 760 atverify = 1; 761 break; 762 763 case 'm': /* send mail when job is complete */ 764 send_mail = 1; 765 break; 766 767 case 'f': 768 atinput = optarg; 769 break; 770 771 case 'q': /* specify queue */ 772 if (strlen(optarg) > 1) 773 usage(); 774 775 atqueue = queue = *optarg; 776 if (!(islower(queue)||isupper(queue))) 777 usage(); 778 779 queue_set = 1; 780 break; 781 782 case 'd': 783 warnx("-d is deprecated; use -r instead"); 784 /* fall through to 'r' */ 785 786 case 'r': 787 if (program != AT) 788 usage(); 789 790 program = ATRM; 791 options = ""; 792 break; 793 794 case 't': 795 if (program != AT) 796 usage(); 797 timer = ttime(optarg); 798 break; 799 800 case 'l': 801 if (program != AT) 802 usage(); 803 804 program = ATQ;
|
758 options = "q:v";
| 805 options = "q:";
|
759 break; 760 761 case 'b': 762 if (program != AT) 763 usage(); 764 765 program = BATCH; 766 options = "f:q:mv"; 767 break; 768 769 case 'c': 770 program = CAT; 771 options = ""; 772 break; 773 774 default: 775 usage(); 776 break; 777 } 778 /* end of options eating 779 */ 780 781 /* select our program 782 */ 783 if(!check_permission()) 784 errx(EXIT_FAILURE, "you do not have permission to use this program"); 785 switch (program) { 786 case ATQ: 787 788 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 789
| 806 break; 807 808 case 'b': 809 if (program != AT) 810 usage(); 811 812 program = BATCH; 813 options = "f:q:mv"; 814 break; 815 816 case 'c': 817 program = CAT; 818 options = ""; 819 break; 820 821 default: 822 usage(); 823 break; 824 } 825 /* end of options eating 826 */ 827 828 /* select our program 829 */ 830 if(!check_permission()) 831 errx(EXIT_FAILURE, "you do not have permission to use this program"); 832 switch (program) { 833 case ATQ: 834 835 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 836
|
790 list_jobs();
| 837 if (queue_set == 0) 838 joblist = get_job_list(argc - optind, argv + optind, &joblen); 839 list_jobs(joblist, joblen);
|
791 break; 792 793 case ATRM: 794 795 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 796 797 process_jobs(argc, argv, ATRM); 798 break; 799 800 case CAT: 801 802 process_jobs(argc, argv, CAT); 803 break; 804 805 case AT: 806 /* 807 * If timer is > -1, then the user gave the time with -t. In that 808 * case, it's already been set. If not, set it now. 809 */ 810 if (timer == -1) 811 timer = parsetime(argc, argv); 812 813 if (atverify) 814 { 815 struct tm *tm = localtime(&timer); 816 fprintf(stderr, "%s\n", asctime(tm)); 817 } 818 writefile(timer, queue); 819 break; 820 821 case BATCH: 822 if (queue_set) 823 queue = toupper(queue); 824 else 825 queue = DEFAULT_BATCH_QUEUE; 826 827 if (argc > optind) 828 timer = parsetime(argc, argv); 829 else 830 timer = time(NULL); 831 832 if (atverify) 833 { 834 struct tm *tm = localtime(&timer); 835 fprintf(stderr, "%s\n", asctime(tm)); 836 } 837 838 writefile(timer, queue); 839 break; 840 841 default: 842 panic("internal error"); 843 break; 844 } 845 exit(EXIT_SUCCESS); 846}
| 840 break; 841 842 case ATRM: 843 844 REDUCE_PRIV(DAEMON_UID, DAEMON_GID) 845 846 process_jobs(argc, argv, ATRM); 847 break; 848 849 case CAT: 850 851 process_jobs(argc, argv, CAT); 852 break; 853 854 case AT: 855 /* 856 * If timer is > -1, then the user gave the time with -t. In that 857 * case, it's already been set. If not, set it now. 858 */ 859 if (timer == -1) 860 timer = parsetime(argc, argv); 861 862 if (atverify) 863 { 864 struct tm *tm = localtime(&timer); 865 fprintf(stderr, "%s\n", asctime(tm)); 866 } 867 writefile(timer, queue); 868 break; 869 870 case BATCH: 871 if (queue_set) 872 queue = toupper(queue); 873 else 874 queue = DEFAULT_BATCH_QUEUE; 875 876 if (argc > optind) 877 timer = parsetime(argc, argv); 878 else 879 timer = time(NULL); 880 881 if (atverify) 882 { 883 struct tm *tm = localtime(&timer); 884 fprintf(stderr, "%s\n", asctime(tm)); 885 } 886 887 writefile(timer, queue); 888 break; 889 890 default: 891 panic("internal error"); 892 break; 893 } 894 exit(EXIT_SUCCESS); 895}
|