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) 05/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 } 407