/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef lint char copyright[] = "@(#) Copyright (c) 1983 Regents of the University of California.\n\ All rights reserved.\n"; #endif not lint #ifndef lint static char sccsid[] = "@(#)atrm.c 5.2 (Berkeley) 5/28/86"; #endif not lint /* * 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. * * Author: Steve Wall * Computer Systems Research Group * University of California @ Berkeley * */ #include #include #include #include #include #include #include #define SUPERUSER 0 /* is user super-user? */ #define MAXENTRIES 1000 /* max # of entries allowed */ #define ATDIR "/usr/spool/at" /* spooling area */ int user; /* person requesting removal */ int fflag = 0; /* suppress announcements? */ int iflag = 0; /* run interactively? */ main(argc,argv) int argc; char **argv; { int i; /* for loop index */ int userid; /* uid of owner of file */ 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 *getname(); /* get a user name from a uid */ 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 * usage info and exit. */ if (argc < 2) usage(); --argc; ++argv; /* * Process command line flags. * Special case the "-" option so that others may be grouped. */ while (argc > 0 && **argv == '-') { if (*(++(*argv)) == '\0') { ++allflag; } else while (**argv) switch (*(*argv)++) { case 'f': ++fflag; break; case 'i': ++iflag; break; default: usage(); } ++argv; --argc; } /* * If all jobs are to be removed and extra command line arguments * are given, print usage info and exit. */ if (allflag && argc) usage(); /* * If only certain jobs are to be removed and no job #'s or user * names are specified, print usage info and exit. */ if (!allflag && !argc) usage(); /* * If interactive removal and quiet removal are requested, override * quiet removal and run interactively. */ if (iflag && fflag) fflag = 0; /* * Move to spooling area and get user id of person requesting removal. */ if (chdir(ATDIR) == -1) { perror(ATDIR); exit(1); } user = getuid(); /* * Get a list of the files in the spooling area. */ if ((numjobs = scandir(".",&namelist,filewanted,alphasort)) < 0) { perror(ATDIR); exit(1); } /* * Build an array of pointers to the file stats for all jobs in * the spooling area. */ for (i = 0; i < numjobs; ++i) { statptr = (struct stat *) malloc(sizeof(struct stat)); if (statptr == NULL) { perror("malloc"); exit(1); } if (stat(namelist[i]->d_name,statptr) < 0) { perror("stat"); continue; } stbuf[i] = statptr; } /* * 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). */ if (allflag) { for (i = 0; i < numjobs; ++i) { if (user == SUPERUSER || isowner(getname(user), namelist[i]->d_name)) (void) removentry(namelist[i]->d_name, (int)stbuf[i]->st_ino, user); } exit(0); } /* * 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"). */ while (argc--) { jobexists = 0; 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) continue; /* * if argv is a username, compare his/her uid to * the uid of the owner of the file...... */ if (isuname) { if (!isowner(*argv,namelist[i]->d_name)) continue; /* * otherwise, we assume that the argv is a job # and * thus compare argv to the inode (job #) of the file. */ } else { if (stbuf[i]->st_ino != atoi(*argv)) continue; } ++jobexists; /* * if the entry is ultimately removed, don't * try to remove it again later. */ if (removentry(namelist[i]->d_name, (int)stbuf[i]->st_ino, user)) { stbuf[i]->st_ino = 0; } } /* * If a requested argument doesn't exist, print a message. */ if (!jobexists && !fflag && !isuname) { fprintf(stderr, "%6s: no such job number\n", *argv); } ++argv; } exit(0); } /* * Print usage info and exit. */ usage() { fprintf(stderr,"usage: atrm [-f] [-i] [-] [[job #] [user] ...]\n"); exit(1); } /* * 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. */ filewanted(direntry) struct direct *direntry; { int numdot = 0; /* number of dots in a filename */ char *filename; /* filename we are looking at */ filename = direntry->d_name; while (*filename) numdot += (*(filename++) == '.'); return(numdot == 3); } /* * 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 * user name. */ isusername(string) char *string; { char *ptr; /* pointer used for scanning string */ ptr = string; while (isdigit(*ptr)) ++ptr; 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 * it is removed. Return TRUE if file removed, else FALSE. */ int removentry(filename,inode,user) char *filename; int inode; int user; { if (!fflag) printf("%6d: ",inode); if (!isowner(getname(user),filename) && user != SUPERUSER) { if (!fflag) { printf("permission denied\n"); } return (0); } else { if (iflag) { if (user == SUPERUSER) { printf("\t(owned by "); powner(filename); printf(") "); } printf("remove it? "); if (!yes()) return (0); } if (unlink(filename) < 0) { if (!fflag) { fputs("could not remove\n", stdout); perror(filename); } return (0); } if (!fflag && !iflag) printf("removed\n"); return (1); } } /* * See if "name" owns "job". */ isowner(name,job) char *name; char *job; { char buf[128]; /* buffer for 1st line of spoolfile header */ FILE *infile; /* I/O stream to spoolfile */ if ((infile = fopen(job,"r")) == NULL) { fprintf(stderr,"Couldn't open spoolfile "); perror(job); return(0); } if (fscanf(infile,"# owner: %127s%*[^\n]\n",buf) != 1) { fclose(infile); return(0); } fclose(infile); return((strcmp(name,buf) == 0) ? 1 : 0); } /* * Print 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 print "???". */ powner(file) char *file; { 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) { printf("%s","???"); perror(file); return; } if (fscanf(infile,"# owner: %127s%*[^\n]\n",owner) != 1) { printf("%s","???"); fclose(infile); return; } fclose(infile); printf("%s",owner); } /* * Get answer to interactive prompts, eating all characters beyond the first * one. If a 'y' is typed, return 1. */ yes() { char ch; /* dummy variable */ char ch1; /* dummy variable */ ch = ch1 = getchar(); while (ch1 != '\n' && ch1 != EOF) ch1 = getchar(); if (isupper(ch)) ch = tolower(ch); return(ch == 'y'); } /* * Get the uid of a person using his/her login name. Return -1 if no * such account name exists. */ getid(name) char *name; { struct passwd *pwdinfo; /* password info structure */ if ((pwdinfo = getpwnam(name)) == 0) return(-1); return(pwdinfo->pw_uid); } /* * Get the full login name of a person using his/her user id. */ char * getname(uid) int uid; { struct passwd *pwdinfo; /* password info structure */ if ((pwdinfo = getpwuid(uid)) == 0) return("???"); return(pwdinfo->pw_name); }