new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / at / atrm / atrm.c
CommitLineData
2791ff57
KB
1/*-
2 * Copyright (c) 1983 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
d0aeaf5a
DF
6 */
7
8#ifndef lint
9char copyright[] =
2791ff57 10"@(#) Copyright (c) 1983 The Regents of the University of California.\n\
d0aeaf5a 11 All rights reserved.\n";
2791ff57 12#endif /* not lint */
d0aeaf5a 13
45dbe918 14#ifndef lint
2791ff57
KB
15static char sccsid[] = "@(#)atrm.c 5.6 (Berkeley) %G%";
16#endif /* not lint */
45dbe918
SW
17
18/*
d6fff2c5 19 * synopsis: atrm [-f] [-i] [-] [[job #] [user] ...]
45dbe918
SW
20 *
21 *
d6fff2c5
KM
22 * Remove files from the directory /usr/spool/at. These files
23 * represent jobs to be run at a later date.
45dbe918 24 *
d6fff2c5
KM
25 * Author: Steve Wall
26 * Computer Systems Research Group
27 * University of California @ Berkeley
45dbe918
SW
28 *
29 */
30
45dbe918
SW
31#include <sys/types.h>
32#include <sys/dir.h>
33#include <sys/file.h>
34#include <sys/stat.h>
0006add0
KB
35#include <stdio.h>
36#include <pwd.h>
37#include <ctype.h>
7abf8d65 38#include "pathnames.h"
45dbe918 39
d6fff2c5
KM
40#define SUPERUSER 0 /* is user super-user? */
41#define MAXENTRIES 1000 /* max # of entries allowed */
45dbe918 42
d6fff2c5
KM
43int user; /* person requesting removal */
44int fflag = 0; /* suppress announcements? */
45int iflag = 0; /* run interactively? */
45dbe918
SW
46
47main(argc,argv)
48int argc;
49char **argv;
50
51{
bb994b7d 52 register int i; /* for loop index */
d6fff2c5
KM
53 int isuname; /* is a command line argv a user name?*/
54 int numjobs; /* # of jobs in spooling area */
55 int usage(); /* print usage info and exit */
56 int allflag = 0; /* remove all jobs belonging to user? */
bb994b7d 57 int jobno;
d6fff2c5
KM
58 int jobexists; /* does a requested job exist? */
59 int alphasort(); /* sort jobs by date of execution */
60 int filewanted(); /* should a file be listed in queue? */
bb994b7d
MK
61 char *myname, *getname(); /* current user's name */
62 char *owner, *fowner();
d6fff2c5
KM
63 struct stat *statptr; /* pointer to file stat structure */
64 struct stat *stbuf[MAXENTRIES]; /* array of pointers to stat structs */
65 struct direct **namelist; /* names of jobs in spooling area */
66
67
68 /*
69 * If job number, user name, or "-" is not specified, just print
70 * usage info and exit.
71 */
72 if (argc < 2)
73 usage();
74
75 --argc; ++argv;
76
77 /*
78 * Process command line flags.
e0799b82 79 * Special case the "-" option so that others may be grouped.
d6fff2c5 80 */
e0799b82
KM
81 while (argc > 0 && **argv == '-') {
82 if (*(++(*argv)) == '\0') {
83 ++allflag;
84 } else while (**argv) switch (*(*argv)++) {
d6fff2c5
KM
85
86 case 'f': ++fflag;
87 break;
88
89 case 'i': ++iflag;
90 break;
91
92 default: usage();
93 }
94 ++argv; --argc;
95 }
96
97 /*
98 * If all jobs are to be removed and extra command line arguments
99 * are given, print usage info and exit.
100 */
101 if (allflag && argc)
102 usage();
103
104 /*
105 * If only certain jobs are to be removed and no job #'s or user
106 * names are specified, print usage info and exit.
107 */
108 if (!allflag && !argc)
109 usage();
110
111 /*
112 * If interactive removal and quiet removal are requested, override
113 * quiet removal and run interactively.
114 */
115 if (iflag && fflag)
116 fflag = 0;
117
118 /*
119 * Move to spooling area and get user id of person requesting removal.
120 */
7abf8d65
KB
121 if (chdir(_PATH_ATDIR) == -1) {
122 perror(_PATH_ATDIR);
d6fff2c5
KM
123 exit(1);
124 }
125 user = getuid();
bb994b7d 126 myname = getname(user);
d6fff2c5
KM
127
128 /*
129 * Get a list of the files in the spooling area.
130 */
7e1f2388 131 if ((numjobs = scandir(".",&namelist,filewanted,alphasort)) < 0) {
7abf8d65 132 perror(_PATH_ATDIR);
d6fff2c5
KM
133 exit(1);
134 }
135
136 /*
137 * Build an array of pointers to the file stats for all jobs in
138 * the spooling area.
139 */
140 for (i = 0; i < numjobs; ++i) {
141 statptr = (struct stat *) malloc(sizeof(struct stat));
142 if (statptr == NULL) {
143 perror("malloc");
144 exit(1);
145 }
146 if (stat(namelist[i]->d_name,statptr) < 0) {
147 perror("stat");
148 continue;
149 }
150 stbuf[i] = statptr;
151 }
152
153 /*
154 * If all jobs belonging to the user are to be removed, compare
155 * the user's id to the owner of the file. If they match, remove
156 * the file. If the user is the super-user, don't bother comparing
157 * the id's. After all files are removed, exit (status 0).
158 */
159 if (allflag) {
160 for (i = 0; i < numjobs; ++i) {
bb994b7d
MK
161 owner = fowner(namelist[i]->d_name);
162 if (isowner(myname, owner))
163 removentry(namelist[i]->d_name,
164 (int)stbuf[i]->st_ino, NULL);
d6fff2c5
KM
165 }
166 exit(0);
167 }
168
169 /*
170 * If only certain jobs are to be removed, interpret each command
171 * line argument. A check is done to see if it is a user's name or
172 * a job number (inode #). If it's a user's name, compare the argument
173 * to the files owner. If it's a job number, compare the argument to
174 * the inode number of the file. In either case, if a match occurs,
175 * try to remove the file. (The function "isusername" scans the
176 * argument to see if it is all digits which we will assume means
177 * that it's a job number (a fairly safe assumption?). This is done
178 * because we have to determine whether we are dealing with a user
179 * name or a job number. By assuming that only arguments that are
180 * all digits is a job number, we allow users to have digits in
181 * their login name i.e. "johndoe2").
182 */
183
184 while (argc--) {
185 jobexists = 0;
186 isuname = isusername(*argv);
bb994b7d
MK
187 if (!isuname)
188 jobno = atoi(*argv);
d6fff2c5
KM
189 for (i = 0; i < numjobs; ++i) {
190
e0799b82
KM
191 /* if the inode number is 0, this entry was removed */
192 if (stbuf[i]->st_ino == 0)
193 continue;
194
bb994b7d 195 owner = fowner(namelist[i]->d_name);
d6fff2c5 196 /*
bb994b7d
MK
197 * if argv is a username, compare it to
198 * the owner of the file......
d6fff2c5
KM
199 * otherwise, we assume that the argv is a job # and
200 * thus compare argv to the inode (job #) of the file.
201 */
bb994b7d
MK
202 if (isuname) {
203 if (strcmp(*argv, owner))
204 continue;
d6fff2c5 205 } else {
bb994b7d 206 if (stbuf[i]->st_ino != jobno)
d6fff2c5
KM
207 continue;
208 }
209 ++jobexists;
e0799b82 210 /*
bb994b7d 211 * if the entry is removed, don't
e0799b82
KM
212 * try to remove it again later.
213 */
bb994b7d
MK
214 if (user == SUPERUSER || isowner(myname, owner)) {
215 removentry(namelist[i]->d_name,
216 (int)stbuf[i]->st_ino, owner);
e0799b82 217 stbuf[i]->st_ino = 0;
bb994b7d
MK
218 } else if (!fflag)
219 printf("%6d: permission denied\n",
220 stbuf[i]->st_ino);
221 if (!isuname)
222 break;
d6fff2c5
KM
223 }
224
225 /*
226 * If a requested argument doesn't exist, print a message.
227 */
228 if (!jobexists && !fflag && !isuname) {
e0799b82 229 fprintf(stderr, "%6s: no such job number\n", *argv);
d6fff2c5
KM
230 }
231 ++argv;
232 }
233 exit(0);
45dbe918
SW
234}
235
236/*
237 * Print usage info and exit.
238 */
239usage()
240{
d6fff2c5
KM
241 fprintf(stderr,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n");
242 exit(1);
45dbe918
SW
243}
244
245/*
246 * Do we want to include a file in the queue? (used by "scandir") We are looking
247 * for files with following syntax: yy.ddd.hhhh. so the test is made to see if
248 * the file name has three dots in it. This test will suffice since the only
249 * other files in /usr/spool/at don't have any dots in their name.
250 */
251filewanted(direntry)
252struct direct *direntry;
253{
d6fff2c5
KM
254 int numdot = 0; /* number of dots in a filename */
255 char *filename; /* filename we are looking at */
45dbe918 256
d6fff2c5
KM
257 filename = direntry->d_name;
258 while (*filename)
259 numdot += (*(filename++) == '.');
260 return(numdot == 3);
45dbe918
SW
261}
262
263/*
264 * Is a command line argument a username? As noted above we will assume
265 * that an argument that is all digits means that it's a job number, not
266 * a user's name. We choose to determine whether an argument is a user name
267 * in this manner because then it's ok for someone to have digits in their
268 * user name.
269 */
270isusername(string)
271char *string;
272{
d6fff2c5 273 char *ptr; /* pointer used for scanning string */
45dbe918 274
d6fff2c5
KM
275 ptr = string;
276 while (isdigit(*ptr))
277 ++ptr;
278 return((*ptr == '\0') ? 0 : 1);
45dbe918
SW
279}
280
281/*
282 * Remove an entry from the queue. The access of the file is checked for
283 * write permission (since all jobs are mode 644). If access is granted,
284 * unlink the file. If the fflag (suppress announcements) is not set,
285 * print the job number that we are removing and the result of the access
7e1f2388
SW
286 * check (either "permission denied" or "removed"). If we are running
287 * interactively (iflag), prompt the user before we unlink the file. If
288 * the super-user is removing jobs, inform him/her who owns each file before
bb994b7d 289 * it is removed.
45dbe918 290 */
bb994b7d 291removentry(filename, inode, owner)
45dbe918
SW
292char *filename;
293int inode;
bb994b7d 294char *owner;
45dbe918
SW
295{
296
d6fff2c5
KM
297 if (!fflag)
298 printf("%6d: ",inode);
299
bb994b7d
MK
300 if (iflag) {
301 if (user == SUPERUSER && owner)
302 printf("\t(owned by %s) ", owner);
303 printf("remove? ");
304 if (!yes())
305 return;
d6fff2c5 306 }
bb994b7d
MK
307 if (unlink(filename) < 0)
308 perror(filename);
309 else if (!fflag && !iflag)
310 printf("removed\n");
45dbe918
SW
311}
312
7e1f2388 313/*
bb994b7d 314 * See if "name" owns job owned by "jobname".
7e1f2388 315 */
bb994b7d 316isowner(name,jobname)
7e1f2388 317char *name;
bb994b7d 318char *jobname;
7e1f2388 319{
7e1f2388 320
bb994b7d 321 return (strcmp(name,jobname) == 0);
7e1f2388
SW
322}
323
324/*
bb994b7d
MK
325 * Return the owner of the job. This is stored on the first line of the
326 * spoolfile. If we run into trouble getting the name, we'll just return "???".
7e1f2388 327 */
bb994b7d
MK
328char *
329fowner(file)
7e1f2388
SW
330char *file;
331{
bb994b7d 332 static char owner[128]; /* the owner */
7e1f2388
SW
333 FILE *infile; /* I/O stream to spoolfile */
334
335 /*
336 * Open the job file and grab the first line.
337 */
338
339 if ((infile = fopen(file,"r")) == NULL) {
7e1f2388 340 perror(file);
bb994b7d 341 return ("???");
7e1f2388
SW
342 }
343
e0799b82 344 if (fscanf(infile,"# owner: %127s%*[^\n]\n",owner) != 1) {
7e1f2388 345 fclose(infile);
bb994b7d 346 return ("???");
7e1f2388
SW
347 }
348
349 fclose(infile);
bb994b7d 350 return (owner);
7e1f2388
SW
351
352}
353
45dbe918
SW
354/*
355 * Get answer to interactive prompts, eating all characters beyond the first
356 * one. If a 'y' is typed, return 1.
357 */
358yes()
359{
d6fff2c5
KM
360 char ch; /* dummy variable */
361 char ch1; /* dummy variable */
45dbe918 362
d6fff2c5
KM
363 ch = ch1 = getchar();
364 while (ch1 != '\n' && ch1 != EOF)
365 ch1 = getchar();
e0799b82
KM
366 if (isupper(ch))
367 ch = tolower(ch);
d6fff2c5 368 return(ch == 'y');
45dbe918
SW
369}
370
371/*
372 * Get the uid of a person using his/her login name. Return -1 if no
373 * such account name exists.
374 */
375getid(name)
376char *name;
377{
378
d6fff2c5
KM
379 struct passwd *pwdinfo; /* password info structure */
380
381 if ((pwdinfo = getpwnam(name)) == 0)
382 return(-1);
45dbe918 383
d6fff2c5 384 return(pwdinfo->pw_uid);
45dbe918
SW
385}
386
387/*
388 * Get the full login name of a person using his/her user id.
389 */
390char *
391getname(uid)
392int uid;
393{
d6fff2c5 394 struct passwd *pwdinfo; /* password info structure */
bb994b7d 395 char *logname, *getlogin();
d6fff2c5 396
45dbe918 397
bb994b7d
MK
398 logname = getlogin();
399 if (logname == NULL || (pwdinfo = getpwnam(logname)) == NULL ||
400 pwdinfo->pw_uid != uid)
401 pwdinfo = getpwuid(uid);
402 if (pwdinfo == 0) {
403 fprintf(stderr, "no name for uid %d?\n", uid);
404 exit(1);
405 }
d6fff2c5 406 return(pwdinfo->pw_name);
45dbe918 407}