]>
git.saurik.com Git - apple/system_cmds.git/blob - at.tproj/at.c
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
22 * @APPLE_LICENSE_HEADER_END@
25 * at.c : Put file into atrun queue
26 * Copyright (C) 1993 Thomas Koenig
28 * Atrun & Atq modifications
29 * Copyright (C) 1993 David Parsons
30 * All rights reserved.
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
35 * 1. Redistributions of source code must retain the above copyright
36 * notice, this list of conditions and the following disclaimer.
37 * 2. The name of the author(s) may not be used to endorse or promote
38 * products derived from this software without specific prior written
41 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
42 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
44 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
47 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
48 * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
50 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
56 #include <sys/types.h>
75 #include "parsetime.h"
76 #include "pathnames.h"
82 #define ALARMC 10 /* Number of seconds to wait for timeout */
87 /* File scope variables */
88 static char rcsid
[] = "$Id: at.c,v 1.1.1.2 2000/01/11 02:10:04 wsanchez Exp $";
91 "TERM", "TERMCAP", "DISPLAY", "_"
95 /* External variables */
96 extern char **environ
;
99 char atfile
[FILENAME_MAX
];
101 char *atinput
= (char *) 0; /* where to get input from */
102 char atqueue
= 0; /* which queue to examine for jobs (atq) */
103 char atverify
= 0; /* verify time instead of queuing job */
105 /* Function declarations */
106 static void sigc
__P((int signo
));
107 static void alarmc
__P((int signo
));
108 static char *cwdname
__P((void));
109 static void writefile
__P((time_t runtimer
, char queue
));
110 static void list_jobs
__P((void));
112 /* Signal catching functions */
118 /* If the user presses ^C, remove the spool file and exit
133 /* Time out after some seconds
135 panic("File locking timed out");
138 /* Local functions */
143 /* Read in the current directory; the name will be overwritten on
146 static char *ptr
= NULL
;
147 static size_t size
= SIZE
;
150 ptr
= (char *) malloc(size
);
154 panic("Out of memory");
156 if (getcwd(ptr
, size
- 1) != NULL
)
160 perr("Cannot get directory");
164 ptr
= (char *) malloc(size
);
169 writefile(runtimer
, queue
)
174 * This does most of the work if at or batch are invoked for
178 char *ap
, *ppos
, *mailname
;
179 struct passwd
*pass_entry
;
181 int fdes
, lockdes
, fd2
;
183 struct sigaction act
;
190 * Install the signal handler for SIGINT; terminate after removing the
191 * spool file if necessary
193 act
.sa_handler
= sigc
;
194 sigemptyset(&(act
.sa_mask
));
197 sigaction(SIGINT
, &act
, NULL
);
199 strcpy(atfile
, _PATH_ATJOBS
);
200 ppos
= atfile
+ strlen(_PATH_ATJOBS
);
203 * Loop over all possible file names for running something at this
204 * particular time, see if a file is there; the first empty slot at
205 * any particular time is used. Lock the file _PATH_LOCKFILE first
206 * to make sure we're alone when doing this.
211 if ((lockdes
= open(_PATH_LOCKFILE
, O_WRONLY
| O_CREAT
, 0600)) < 0)
212 perr2("Cannot open lockfile ", _PATH_LOCKFILE
);
214 lock
.l_type
= F_WRLCK
;
215 lock
.l_whence
= SEEK_SET
;
219 act
.sa_handler
= alarmc
;
220 sigemptyset(&(act
.sa_mask
));
224 * Set an alarm so a timeout occurs after ALARMC seconds, in case
225 * something is seriously broken.
227 sigaction(SIGALRM
, &act
, NULL
);
229 fcntl(lockdes
, F_SETLKW
, &lock
);
232 for (i
= 0; i
< AT_MAXJOBS
; i
++) {
233 sprintf(ppos
, "%c%8lx.%3x", queue
,
234 (unsigned long) (runtimer
/ 60), i
);
235 for (ap
= ppos
; *ap
!= '\0'; ap
++)
239 if (stat(atfile
, &statbuf
) != 0) {
243 perr2("Cannot access ", _PATH_ATJOBS
);
248 panic("Too many jobs already");
251 * Create the file. The x bit is only going to be set after it has
252 * been completely written out, to make sure it is not executed in
253 * the meantime. To make sure they do not get deleted, turn off
254 * their r bit. Yes, this is a kluge.
256 cmask
= umask(S_IRUSR
| S_IWUSR
| S_IXUSR
);
257 if ((fdes
= creat(atfile
, O_WRONLY
)) == -1)
258 perr("Cannot create atjob file");
260 if ((fd2
= dup(fdes
)) < 0)
261 perr("Error in dup() of job file");
263 if (fchown(fd2
, real_uid
, -1) != 0)
264 perr("Cannot give away file");
269 * We no longer need suid root; now we just need to be able to
270 * write to the directory, if necessary.
276 * We've successfully created the file; let's set the flag so it
277 * gets removed in case of an interrupt or error.
281 /* Now we can release the lock, so other people can access it */
282 lock
.l_type
= F_UNLCK
;
283 lock
.l_whence
= SEEK_SET
;
286 fcntl(lockdes
, F_SETLKW
, &lock
);
289 if ((fp
= fdopen(fdes
, "w")) == NULL
)
290 panic("Cannot reopen atjob file");
293 * Get the userid to mail to, first by trying getlogin(), which
294 * reads /etc/utmp, then from LOGNAME, finally from getpwuid().
296 mailname
= getlogin();
297 if (mailname
== NULL
)
298 mailname
= getenv("LOGNAME");
300 if ((mailname
== NULL
) || (mailname
[0] == '\0')
301 || (strlen(mailname
) > 8)) {
302 pass_entry
= getpwuid(getuid());
303 if (pass_entry
!= NULL
)
304 mailname
= pass_entry
->pw_name
;
307 if (atinput
!= (char *) NULL
) {
308 fpin
= freopen(atinput
, "r", stdin
);
310 perr("Cannot open input file");
312 fprintf(fp
, "#! /bin/sh\n# mail %8s %d\n", mailname
, send_mail
);
314 /* Write out the umask at the time of invocation */
315 fprintf(fp
, "umask %lo\n", (unsigned long) cmask
);
318 * Write out the environment. Anything that may look like a special
319 * character to the shell is quoted, except for \n, which is done
320 * with a pair of "'s. Dont't export the no_export list (such as
321 * TERM or DISPLAY) because we don't want these.
323 for (atenv
= environ
; *atenv
!= NULL
; atenv
++) {
327 eqp
= strchr(*atenv
, '=');
333 for (i
= 0;i
< sizeof(no_export
) /
334 sizeof(no_export
[0]); i
++) {
336 && (strncmp(*atenv
, no_export
[i
],
337 (size_t) (eqp
- *atenv
)) != 0);
343 fwrite(*atenv
, sizeof(char), eqp
- *atenv
, fp
);
344 for (ap
= eqp
; *ap
!= '\0'; ap
++) {
346 fprintf(fp
, "\"\n\"");
354 fputs("; export ", fp
);
355 fwrite(*atenv
, sizeof(char), eqp
- *atenv
- 1, fp
);
361 * Cd to the directory at the time and write out all the commands
362 * the user supplies from stdin.
364 fprintf(fp
, "cd %s\n", cwdname());
366 while ((ch
= getchar()) != EOF
)
371 panic("Output error");
374 panic("Input error");
379 * Set the x bit so that we're ready to start executing
381 if (fchmod(fd2
, S_IRUSR
| S_IWUSR
| S_IXUSR
) < 0)
382 perr("Cannot give away file");
385 fprintf(stderr
, "Job %s will be executed using /bin/sh\n", ppos
);
392 * List all a user's jobs in the queue, by looping through
393 * _PATH_ATJOBS, or everybody's if we are root
397 struct dirent
*dirent
;
403 char timestr
[TIMESIZE
];
408 if (chdir(_PATH_ATJOBS
) != 0)
409 perr2("Cannot change to ", _PATH_ATJOBS
);
411 if ((spool
= opendir(".")) == NULL
)
412 perr2("Cannot open ", _PATH_ATJOBS
);
414 /* Loop over every file in the directory */
415 while ((dirent
= readdir(spool
)) != NULL
) {
416 if (stat(dirent
->d_name
, &buf
) != 0)
417 perr2("Cannot stat in ", _PATH_ATJOBS
);
420 * See it's a regular file and has its x bit turned on and
423 if (!S_ISREG(buf
.st_mode
)
424 || ((buf
.st_uid
!= real_uid
) && !(real_uid
== 0))
425 || !(S_IXUSR
& buf
.st_mode
|| atverify
))
428 if (sscanf(dirent
->d_name
, "%c%8lx", &queue
, &ctm
) != 2)
431 if (atqueue
&& (queue
!= atqueue
))
434 runtimer
= 60 * (time_t) ctm
;
435 runtime
= *localtime(&runtimer
);
436 strftime(timestr
, TIMESIZE
, "%X %x", &runtime
);
438 printf("Date\t\t\tOwner\tQueue\tJob#\n");
441 pw
= getpwuid(buf
.st_uid
);
443 printf("%s\t%s\t%c%s\t%s\n",
445 pw
? pw
->pw_name
: "???",
447 (S_IXUSR
& buf
.st_mode
) ? "" : "(done)",
454 delete_jobs(argc
, argv
)
458 /* Delete every argument (job - ID) given */
464 if (chdir(_PATH_ATJOBS
) != 0)
465 perr2("Cannot change to ", _PATH_ATJOBS
);
467 for (i
= optind
; i
< argc
; i
++) {
468 if (stat(argv
[i
], &buf
) != 0)
470 if ((buf
.st_uid
!= real_uid
) && !(real_uid
== 0)) {
471 fprintf(stderr
, "%s: Not owner\n", argv
[i
]);
474 if (unlink(argv
[i
]) != 0)
480 /* Global functions */
493 }; /* what program we want to run */
494 int program
= AT
; /* our default program */
495 char *options
= "q:f:mv"; /* default options for at */
500 /* Eat any leading paths */
501 if ((pgm
= strrchr(argv
[0], '/')) == NULL
)
508 /* find out what this program is supposed to do */
509 if (strcmp(pgm
, "atq") == 0) {
512 } else if (strcmp(pgm
, "atrm") == 0) {
515 } else if (strcmp(pgm
, "batch") == 0) {
520 /* process whatever options we can process */
522 while ((c
= getopt(argc
, argv
, options
)) != EOF
)
524 case 'v': /* verify time settings */
528 case 'm': /* send mail when job is complete */
536 case 'q': /* specify queue */
537 if (strlen(optarg
) > 1)
540 atqueue
= queue
= *optarg
;
541 if ((!islower(queue
)) || (queue
> 'l'))
549 /* end of options eating */
551 /* select our program */
552 if (!check_permission())
554 fprintf(stderr
, "You do not have permission to use %s.\n",namep
);
569 delete_jobs(argc
, argv
);
573 timer
= parsetime(argc
, argv
);
575 struct tm
*tm
= localtime(&timer
);
577 fprintf(stderr
, "%s\n", asctime(tm
));
579 writefile(timer
, queue
);
583 writefile(time(NULL
), 'b');
587 panic("Internal error");