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