1 /*- 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.proprietary.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1983, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)atrm.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 /* 19 * synopsis: atrm [-f] [-i] [-] [[job #] [user] ...] 20 * 21 * 22 * Remove files from the directory /usr/spool/at. These files 23 * represent jobs to be run at a later date. 24 * 25 * Author: Steve Wall 26 * Computer Systems Research Group 27 * University of California @ Berkeley 28 * 29 */ 30 31 #include <sys/types.h> 32 #include <sys/dir.h> 33 #include <sys/file.h> 34 #include <sys/stat.h> 35 #include <stdio.h> 36 #include <pwd.h> 37 #include <ctype.h> 38 #include "pathnames.h" 39 40 #define SUPERUSER 0 /* is user super-user? */ 41 #define MAXENTRIES 1000 /* max # of entries allowed */ 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(_PATH_ATDIR) == -1) { 122 perror(_PATH_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(_PATH_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 } 408