|
|
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.2 (Berkeley) 5/28/86";
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: int i; /* for loop index */
53: int userid; /* uid of owner of file */
54: int isuname; /* is a command line argv a user name?*/
55: int numjobs; /* # of jobs in spooling area */
56: int usage(); /* print usage info and exit */
57: int allflag = 0; /* remove all jobs belonging to user? */
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 *getname(); /* get a user name from a uid */
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(ATDIR) == -1) {
121: perror(ATDIR);
122: exit(1);
123: }
124: user = getuid();
125:
126: /*
127: * Get a list of the files in the spooling area.
128: */
129: if ((numjobs = scandir(".",&namelist,filewanted,alphasort)) < 0) {
130: perror(ATDIR);
131: exit(1);
132: }
133:
134: /*
135: * Build an array of pointers to the file stats for all jobs in
136: * the spooling area.
137: */
138: for (i = 0; i < numjobs; ++i) {
139: statptr = (struct stat *) malloc(sizeof(struct stat));
140: if (statptr == NULL) {
141: perror("malloc");
142: exit(1);
143: }
144: if (stat(namelist[i]->d_name,statptr) < 0) {
145: perror("stat");
146: continue;
147: }
148: stbuf[i] = statptr;
149: }
150:
151: /*
152: * If all jobs belonging to the user are to be removed, compare
153: * the user's id to the owner of the file. If they match, remove
154: * the file. If the user is the super-user, don't bother comparing
155: * the id's. After all files are removed, exit (status 0).
156: */
157: if (allflag) {
158: for (i = 0; i < numjobs; ++i) {
159: if (user == SUPERUSER || isowner(getname(user),
160: namelist[i]->d_name))
161: (void) removentry(namelist[i]->d_name,
162: (int)stbuf[i]->st_ino,
163: user);
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: for (i = 0; i < numjobs; ++i) {
187:
188: /* if the inode number is 0, this entry was removed */
189: if (stbuf[i]->st_ino == 0)
190: continue;
191:
192: /*
193: * if argv is a username, compare his/her uid to
194: * the uid of the owner of the file......
195: */
196: if (isuname) {
197: if (!isowner(*argv,namelist[i]->d_name))
198: continue;
199:
200: /*
201: * otherwise, we assume that the argv is a job # and
202: * thus compare argv to the inode (job #) of the file.
203: */
204: } else {
205: if (stbuf[i]->st_ino != atoi(*argv))
206: continue;
207: }
208: ++jobexists;
209: /*
210: * if the entry is ultimately removed, don't
211: * try to remove it again later.
212: */
213: if (removentry(namelist[i]->d_name,
214: (int)stbuf[i]->st_ino, user)) {
215: stbuf[i]->st_ino = 0;
216: }
217: }
218:
219: /*
220: * If a requested argument doesn't exist, print a message.
221: */
222: if (!jobexists && !fflag && !isuname) {
223: fprintf(stderr, "%6s: no such job number\n", *argv);
224: }
225: ++argv;
226: }
227: exit(0);
228: }
229:
230: /*
231: * Print usage info and exit.
232: */
233: usage()
234: {
235: fprintf(stderr,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n");
236: exit(1);
237: }
238:
239: /*
240: * Do we want to include a file in the queue? (used by "scandir") We are looking
241: * for files with following syntax: yy.ddd.hhhh. so the test is made to see if
242: * the file name has three dots in it. This test will suffice since the only
243: * other files in /usr/spool/at don't have any dots in their name.
244: */
245: filewanted(direntry)
246: struct direct *direntry;
247: {
248: int numdot = 0; /* number of dots in a filename */
249: char *filename; /* filename we are looking at */
250:
251: filename = direntry->d_name;
252: while (*filename)
253: numdot += (*(filename++) == '.');
254: return(numdot == 3);
255: }
256:
257: /*
258: * Is a command line argument a username? As noted above we will assume
259: * that an argument that is all digits means that it's a job number, not
260: * a user's name. We choose to determine whether an argument is a user name
261: * in this manner because then it's ok for someone to have digits in their
262: * user name.
263: */
264: isusername(string)
265: char *string;
266: {
267: char *ptr; /* pointer used for scanning string */
268:
269: ptr = string;
270: while (isdigit(*ptr))
271: ++ptr;
272: return((*ptr == '\0') ? 0 : 1);
273: }
274:
275: /*
276: * Remove an entry from the queue. The access of the file is checked for
277: * write permission (since all jobs are mode 644). If access is granted,
278: * unlink the file. If the fflag (suppress announcements) is not set,
279: * print the job number that we are removing and the result of the access
280: * check (either "permission denied" or "removed"). If we are running
281: * interactively (iflag), prompt the user before we unlink the file. If
282: * the super-user is removing jobs, inform him/her who owns each file before
283: * it is removed. Return TRUE if file removed, else FALSE.
284: */
285: int
286: removentry(filename,inode,user)
287: char *filename;
288: int inode;
289: int user;
290: {
291:
292: if (!fflag)
293: printf("%6d: ",inode);
294:
295: if (!isowner(getname(user),filename) && user != SUPERUSER) {
296:
297: if (!fflag) {
298: printf("permission denied\n");
299: }
300: return (0);
301:
302: } else {
303: if (iflag) {
304: if (user == SUPERUSER) {
305: printf("\t(owned by ");
306: powner(filename);
307: printf(") ");
308: }
309: printf("remove it? ");
310: if (!yes())
311: return (0);
312: }
313: if (unlink(filename) < 0) {
314: if (!fflag) {
315: fputs("could not remove\n", stdout);
316: perror(filename);
317: }
318: return (0);
319: }
320: if (!fflag && !iflag)
321: printf("removed\n");
322: return (1);
323: }
324: }
325:
326: /*
327: * See if "name" owns "job".
328: */
329: isowner(name,job)
330: char *name;
331: char *job;
332: {
333: char buf[128]; /* buffer for 1st line of spoolfile
334: header */
335: FILE *infile; /* I/O stream to spoolfile */
336:
337: if ((infile = fopen(job,"r")) == NULL) {
338: fprintf(stderr,"Couldn't open spoolfile ");
339: perror(job);
340: return(0);
341: }
342:
343: if (fscanf(infile,"# owner: %127s%*[^\n]\n",buf) != 1) {
344: fclose(infile);
345: return(0);
346: }
347:
348: fclose(infile);
349: return((strcmp(name,buf) == 0) ? 1 : 0);
350: }
351:
352: /*
353: * Print the owner of the job. This is stored on the first line of the
354: * spoolfile. If we run into trouble getting the name, we'll just print "???".
355: */
356: powner(file)
357: char *file;
358: {
359: char owner[128]; /* the owner */
360: FILE *infile; /* I/O stream to spoolfile */
361:
362: /*
363: * Open the job file and grab the first line.
364: */
365:
366: if ((infile = fopen(file,"r")) == NULL) {
367: printf("%s","???");
368: perror(file);
369: return;
370: }
371:
372: if (fscanf(infile,"# owner: %127s%*[^\n]\n",owner) != 1) {
373: printf("%s","???");
374: fclose(infile);
375: return;
376: }
377:
378: fclose(infile);
379: printf("%s",owner);
380:
381: }
382:
383: /*
384: * Get answer to interactive prompts, eating all characters beyond the first
385: * one. If a 'y' is typed, return 1.
386: */
387: yes()
388: {
389: char ch; /* dummy variable */
390: char ch1; /* dummy variable */
391:
392: ch = ch1 = getchar();
393: while (ch1 != '\n' && ch1 != EOF)
394: ch1 = getchar();
395: if (isupper(ch))
396: ch = tolower(ch);
397: return(ch == 'y');
398: }
399:
400: /*
401: * Get the uid of a person using his/her login name. Return -1 if no
402: * such account name exists.
403: */
404: getid(name)
405: char *name;
406: {
407:
408: struct passwd *pwdinfo; /* password info structure */
409:
410: if ((pwdinfo = getpwnam(name)) == 0)
411: return(-1);
412:
413: return(pwdinfo->pw_uid);
414: }
415:
416: /*
417: * Get the full login name of a person using his/her user id.
418: */
419: char *
420: getname(uid)
421: int uid;
422: {
423: struct passwd *pwdinfo; /* password info structure */
424:
425:
426: if ((pwdinfo = getpwuid(uid)) == 0)
427: return("???");
428: return(pwdinfo->pw_name);
429: }
430:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.