|
|
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.3 (Berkeley) 1/18/87";
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 <stdio.h>
31: #include <pwd.h>
32: #include <ctype.h>
33: #include <sys/types.h>
34: #include <sys/dir.h>
35: #include <sys/file.h>
36: #include <sys/stat.h>
37:
38: #define SUPERUSER 0 /* is user super-user? */
39: #define MAXENTRIES 1000 /* max # of entries allowed */
40: #define ATDIR "/usr/spool/at" /* spooling area */
41:
42:
43: int user; /* person requesting removal */
44: int fflag = 0; /* suppress announcements? */
45: int iflag = 0; /* run interactively? */
46:
47: main(argc,argv)
48: int argc;
49: char **argv;
50:
51: {
52: register int i; /* for loop index */
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? */
57: int jobno;
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? */
61: char *myname, *getname(); /* current user's name */
62: char *owner, *fowner();
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.
79: * Special case the "-" option so that others may be grouped.
80: */
81: while (argc > 0 && **argv == '-') {
82: if (*(++(*argv)) == '\0') {
83: ++allflag;
84: } else while (**argv) switch (*(*argv)++) {
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: */
121: if (chdir(ATDIR) == -1) {
122: perror(ATDIR);
123: exit(1);
124: }
125: user = getuid();
126: myname = getname(user);
127:
128: /*
129: * Get a list of the files in the spooling area.
130: */
131: if ((numjobs = scandir(".",&namelist,filewanted,alphasort)) < 0) {
132: perror(ATDIR);
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) {
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);
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);
187: if (!isuname)
188: jobno = atoi(*argv);
189: for (i = 0; i < numjobs; ++i) {
190:
191: /* if the inode number is 0, this entry was removed */
192: if (stbuf[i]->st_ino == 0)
193: continue;
194:
195: owner = fowner(namelist[i]->d_name);
196: /*
197: * if argv is a username, compare it to
198: * the owner of the file......
199: * otherwise, we assume that the argv is a job # and
200: * thus compare argv to the inode (job #) of the file.
201: */
202: if (isuname) {
203: if (strcmp(*argv, owner))
204: continue;
205: } else {
206: if (stbuf[i]->st_ino != jobno)
207: continue;
208: }
209: ++jobexists;
210: /*
211: * if the entry is removed, don't
212: * try to remove it again later.
213: */
214: if (user == SUPERUSER || isowner(myname, owner)) {
215: removentry(namelist[i]->d_name,
216: (int)stbuf[i]->st_ino, owner);
217: stbuf[i]->st_ino = 0;
218: } else if (!fflag)
219: printf("%6d: permission denied\n",
220: stbuf[i]->st_ino);
221: if (!isuname)
222: break;
223: }
224:
225: /*
226: * If a requested argument doesn't exist, print a message.
227: */
228: if (!jobexists && !fflag && !isuname) {
229: fprintf(stderr, "%6s: no such job number\n", *argv);
230: }
231: ++argv;
232: }
233: exit(0);
234: }
235:
236: /*
237: * Print usage info and exit.
238: */
239: usage()
240: {
241: fprintf(stderr,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n");
242: exit(1);
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: */
251: filewanted(direntry)
252: struct direct *direntry;
253: {
254: int numdot = 0; /* number of dots in a filename */
255: char *filename; /* filename we are looking at */
256:
257: filename = direntry->d_name;
258: while (*filename)
259: numdot += (*(filename++) == '.');
260: return(numdot == 3);
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: */
270: isusername(string)
271: char *string;
272: {
273: char *ptr; /* pointer used for scanning string */
274:
275: ptr = string;
276: while (isdigit(*ptr))
277: ++ptr;
278: return((*ptr == '\0') ? 0 : 1);
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
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
289: * it is removed.
290: */
291: removentry(filename, inode, owner)
292: char *filename;
293: int inode;
294: char *owner;
295: {
296:
297: if (!fflag)
298: printf("%6d: ",inode);
299:
300: if (iflag) {
301: if (user == SUPERUSER && owner)
302: printf("\t(owned by %s) ", owner);
303: printf("remove? ");
304: if (!yes())
305: return;
306: }
307: if (unlink(filename) < 0)
308: perror(filename);
309: else if (!fflag && !iflag)
310: printf("removed\n");
311: }
312:
313: /*
314: * See if "name" owns job owned by "jobname".
315: */
316: isowner(name,jobname)
317: char *name;
318: char *jobname;
319: {
320:
321: return (strcmp(name,jobname) == 0);
322: }
323:
324: /*
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 "???".
327: */
328: char *
329: fowner(file)
330: char *file;
331: {
332: static char owner[128]; /* the owner */
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) {
340: perror(file);
341: return ("???");
342: }
343:
344: if (fscanf(infile,"# owner: %127s%*[^\n]\n",owner) != 1) {
345: fclose(infile);
346: return ("???");
347: }
348:
349: fclose(infile);
350: return (owner);
351:
352: }
353:
354: /*
355: * Get answer to interactive prompts, eating all characters beyond the first
356: * one. If a 'y' is typed, return 1.
357: */
358: yes()
359: {
360: char ch; /* dummy variable */
361: char ch1; /* dummy variable */
362:
363: ch = ch1 = getchar();
364: while (ch1 != '\n' && ch1 != EOF)
365: ch1 = getchar();
366: if (isupper(ch))
367: ch = tolower(ch);
368: return(ch == 'y');
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: */
375: getid(name)
376: char *name;
377: {
378:
379: struct passwd *pwdinfo; /* password info structure */
380:
381: if ((pwdinfo = getpwnam(name)) == 0)
382: return(-1);
383:
384: return(pwdinfo->pw_uid);
385: }
386:
387: /*
388: * Get the full login name of a person using his/her user id.
389: */
390: char *
391: getname(uid)
392: int uid;
393: {
394: struct passwd *pwdinfo; /* password info structure */
395: char *logname, *getlogin();
396:
397:
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: }
406: return(pwdinfo->pw_name);
407: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.