* Copyright (c) 1983 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
"@(#) Copyright (c) 1983 Regents of the University of California.\n\
static char sccsid
[] = "@(#)atrm.c 5.5 (Berkeley) %G%";
* synopsis: atrm [-f] [-i] [-] [[job #] [user] ...]
* Remove files from the directory /usr/spool/at. These files
* represent jobs to be run at a later date.
* Computer Systems Research Group
* University of California @ Berkeley
#define SUPERUSER 0 /* is user super-user? */
#define MAXENTRIES 1000 /* max # of entries allowed */
int user
; /* person requesting removal */
int fflag
= 0; /* suppress announcements? */
int iflag
= 0; /* run interactively? */
register int i
; /* for loop index */
int isuname
; /* is a command line argv a user name?*/
int numjobs
; /* # of jobs in spooling area */
int usage(); /* print usage info and exit */
int allflag
= 0; /* remove all jobs belonging to user? */
int jobexists
; /* does a requested job exist? */
int alphasort(); /* sort jobs by date of execution */
int filewanted(); /* should a file be listed in queue? */
char *myname
, *getname(); /* current user's name */
struct stat
*statptr
; /* pointer to file stat structure */
struct stat
*stbuf
[MAXENTRIES
]; /* array of pointers to stat structs */
struct direct
**namelist
; /* names of jobs in spooling area */
* If job number, user name, or "-" is not specified, just print
* Process command line flags.
* Special case the "-" option so that others may be grouped.
while (argc
> 0 && **argv
== '-') {
if (*(++(*argv
)) == '\0') {
} else while (**argv
) switch (*(*argv
)++) {
* If all jobs are to be removed and extra command line arguments
* are given, print usage info and exit.
* If only certain jobs are to be removed and no job #'s or user
* names are specified, print usage info and exit.
* If interactive removal and quiet removal are requested, override
* quiet removal and run interactively.
* Move to spooling area and get user id of person requesting removal.
if (chdir(_PATH_ATDIR
) == -1) {
* Get a list of the files in the spooling area.
if ((numjobs
= scandir(".",&namelist
,filewanted
,alphasort
)) < 0) {
* Build an array of pointers to the file stats for all jobs in
for (i
= 0; i
< numjobs
; ++i
) {
statptr
= (struct stat
*) malloc(sizeof(struct stat
));
if (stat(namelist
[i
]->d_name
,statptr
) < 0) {
* If all jobs belonging to the user are to be removed, compare
* the user's id to the owner of the file. If they match, remove
* the file. If the user is the super-user, don't bother comparing
* the id's. After all files are removed, exit (status 0).
for (i
= 0; i
< numjobs
; ++i
) {
owner
= fowner(namelist
[i
]->d_name
);
if (isowner(myname
, owner
))
removentry(namelist
[i
]->d_name
,
(int)stbuf
[i
]->st_ino
, NULL
);
* If only certain jobs are to be removed, interpret each command
* line argument. A check is done to see if it is a user's name or
* a job number (inode #). If it's a user's name, compare the argument
* to the files owner. If it's a job number, compare the argument to
* the inode number of the file. In either case, if a match occurs,
* try to remove the file. (The function "isusername" scans the
* argument to see if it is all digits which we will assume means
* that it's a job number (a fairly safe assumption?). This is done
* because we have to determine whether we are dealing with a user
* name or a job number. By assuming that only arguments that are
* all digits is a job number, we allow users to have digits in
* their login name i.e. "johndoe2").
isuname
= isusername(*argv
);
for (i
= 0; i
< numjobs
; ++i
) {
/* if the inode number is 0, this entry was removed */
if (stbuf
[i
]->st_ino
== 0)
owner
= fowner(namelist
[i
]->d_name
);
* if argv is a username, compare it to
* the owner of the file......
* otherwise, we assume that the argv is a job # and
* thus compare argv to the inode (job #) of the file.
if (strcmp(*argv
, owner
))
if (stbuf
[i
]->st_ino
!= jobno
)
* if the entry is removed, don't
* try to remove it again later.
if (user
== SUPERUSER
|| isowner(myname
, owner
)) {
removentry(namelist
[i
]->d_name
,
(int)stbuf
[i
]->st_ino
, owner
);
printf("%6d: permission denied\n",
* If a requested argument doesn't exist, print a message.
if (!jobexists
&& !fflag
&& !isuname
) {
fprintf(stderr
, "%6s: no such job number\n", *argv
);
* Print usage info and exit.
fprintf(stderr
,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n");
* Do we want to include a file in the queue? (used by "scandir") We are looking
* for files with following syntax: yy.ddd.hhhh. so the test is made to see if
* the file name has three dots in it. This test will suffice since the only
* other files in /usr/spool/at don't have any dots in their name.
int numdot
= 0; /* number of dots in a filename */
char *filename
; /* filename we are looking at */
filename
= direntry
->d_name
;
numdot
+= (*(filename
++) == '.');
* Is a command line argument a username? As noted above we will assume
* that an argument that is all digits means that it's a job number, not
* a user's name. We choose to determine whether an argument is a user name
* in this manner because then it's ok for someone to have digits in their
char *ptr
; /* pointer used for scanning string */
return((*ptr
== '\0') ? 0 : 1);
* Remove an entry from the queue. The access of the file is checked for
* write permission (since all jobs are mode 644). If access is granted,
* unlink the file. If the fflag (suppress announcements) is not set,
* print the job number that we are removing and the result of the access
* check (either "permission denied" or "removed"). If we are running
* interactively (iflag), prompt the user before we unlink the file. If
* the super-user is removing jobs, inform him/her who owns each file before
removentry(filename
, inode
, owner
)
if (user
== SUPERUSER
&& owner
)
printf("\t(owned by %s) ", owner
);
if (unlink(filename
) < 0)
else if (!fflag
&& !iflag
)
* See if "name" owns job owned by "jobname".
return (strcmp(name
,jobname
) == 0);
* Return the owner of the job. This is stored on the first line of the
* spoolfile. If we run into trouble getting the name, we'll just return "???".
static char owner
[128]; /* the owner */
FILE *infile
; /* I/O stream to spoolfile */
* Open the job file and grab the first line.
if ((infile
= fopen(file
,"r")) == NULL
) {
if (fscanf(infile
,"# owner: %127s%*[^\n]\n",owner
) != 1) {
* Get answer to interactive prompts, eating all characters beyond the first
* one. If a 'y' is typed, return 1.
char ch
; /* dummy variable */
char ch1
; /* dummy variable */
while (ch1
!= '\n' && ch1
!= EOF
)
* Get the uid of a person using his/her login name. Return -1 if no
* such account name exists.
struct passwd
*pwdinfo
; /* password info structure */
if ((pwdinfo
= getpwnam(name
)) == 0)
* Get the full login name of a person using his/her user id.
struct passwd
*pwdinfo
; /* password info structure */
char *logname
, *getlogin();
if (logname
== NULL
|| (pwdinfo
= getpwnam(logname
)) == NULL
||
fprintf(stderr
, "no name for uid %d?\n", uid
);
return(pwdinfo
->pw_name
);