1: /* lprm.c 4.3 81/08/06 */ 2: /* 3: * lprm - dequeue the current user's spool entry 4: * 5: * lprm [-] [pid] [user] 6: * 7: * Using information in the lock file, lprm will kill the 8: * currently active daemon (if necessary), remove the associated files, 9: * startup a new daemon. Priviledged users may remove anyone's spool 10: * entries, otherwise one can only remove their own. 11: * 12: */ 13: 14: #include <stdio.h> 15: #include <signal.h> 16: #include <sys/types.h> 17: #include <sys/dir.h> 18: #include <pwd.h> 19: #include <sys/stat.h> 20: #include <ctype.h> 21: #include <errno.h> 22: #include "lp.local.h" 23: 24: #define MAXUSERS 50 25: #define MAXREQUESTS 30 26: 27: /* 28: * Stuff for handling lprm specifications 29: */ 30: struct passwd user[MAXUSERS]; /* users to process */ 31: struct direct *pdir; /* used in perusing SPOOLDIR */ 32: int users; /* # of users in user array */ 33: int cur_daemon; /* daemon's pid */ 34: int cur_pid; /* active daemon file pid */ 35: int requ[MAXREQUESTS]; /* pid of spool entries */ 36: int requests; /* # of spool requests */ 37: int all = 0; /* eliminate everything ? */ 38: 39: /* 40: * Stuff for printcap (a la termcap) description 41: */ 42: char *SD; 43: char *LO; 44: char *DN; 45: char *AF; 46: char *printer; 47: char *pgetstr(); 48: 49: struct passwd *getpwnam(), *getpwuid(); 50: char *malloc(); 51: char *realloc(); 52: char *getenv(); 53: char *malloc(); 54: char *rindex(); 55: 56: main(argc, argv) 57: char *argv[]; 58: { 59: register int nitems, garbage = 0; 60: register struct passwd *p; 61: register int nargs = argc; 62: int assasinated = 0; 63: 64: argv++; 65: while (argc > 1) { 66: if (argv[0][0] == '-') { 67: if (argv[0][1] == 'P') { 68: if (!chkprinter(&argv[0][2])) 69: fatal("%s: unknown printer", &argv[0][2]); 70: printer = &argv[0][2]; 71: } else { 72: if (users) 73: usage(); 74: users = -1; 75: } 76: } else { 77: if (users < 0) 78: usage(); 79: if (isdigit(argv[0][0])) { 80: if (requests >= MAXREQUESTS) 81: fatal("too many requests to lprm"); 82: requ[requests++] = atoi(*argv); 83: } else { 84: if (users >= MAXUSERS) 85: fatal("too many users"); 86: p = getpwnam(*argv); 87: if (p) 88: user[users++] = *p; 89: else 90: fatal("%s: unknown user", *argv); 91: } 92: } 93: argc--; 94: argv++; 95: } 96: /* 97: * If the format was `lprm -' and the user isn't super-user, 98: * then fake things to look like he said `lprm user'. 99: */ 100: if (users < 0) { 101: int uid; 102: 103: if ((uid = getuid()) != 0) { 104: if ((p = getpwuid(uid)) == NULL) 105: fatal("who are you?"); 106: user[0] = *p; 107: users = 1; 108: } else 109: all = 1; 110: } 111: /* 112: * Build a picture of the spool q 113: */ 114: if (printer == NULL) { 115: if ((printer = getenv("PRINTER")) == NULL) 116: printer = DEFLP; 117: if (!chkprinter(printer)) 118: fatal("%s: unknown printer", printer); 119: } 120: if (chdir(SD) < 0) 121: fatal("can't chdir to spooling area"); 122: if ((nitems = collect()) == 0) { 123: printf("no entries\n"); 124: exit(0); 125: } 126: garbage = lockchk(LO); 127: /* 128: * If we have garbage, then just remove the files, 129: * otherwise check first for an active daemon 130: * (in which case we kill it off it is reading our file) 131: * then remove stuff (after which we have to restart the 132: * daemon). 133: */ 134: if (!garbage) { 135: char file[15]; 136: 137: sprintf(file, "dfA%05d", cur_pid); 138: #ifndef UNM 139: if ((nargs == 1 && access(file, 4) == 0) || chk(file, cur_pid)) { 140: #else UNM 141: if ((nargs == 1 && access(file, 2) == 0) || chk(file, cur_pid)) { 142: #endif UNM 143: requ[requests++] = cur_pid; 144: assasinated = (kill(cur_daemon, SIGTERM) == 0); 145: if (!assasinated) 146: fatal("can't kill daemon"); 147: } 148: } 149: for (nargs = 0; nargs < nitems; nargs++) 150: process(&pdir[nargs]); 151: if (!garbage && assasinated) { 152: unlink(LO); 153: execl(DN, rindex(DN, '/') ? rindex(DN, '/')+1 : DN, printer, 0); 154: fatal("can't restart daemon"); 155: } 156: } 157: 158: /* 159: * Process a lock file: collect the pid of the active 160: * daemon and the pid of the active spool entry. 161: * Return boolean indicating non-existence of a lock file. 162: */ 163: lockchk(s) 164: char *s; 165: { 166: register int fd; 167: register int i; 168: extern int errno; 169: 170: if ((fd = open(s, 0)) < 0) 171: if (errno == EACCES) 172: fatal("can't access lock file"); 173: else 174: return(1); 175: if (read(fd, (char *)&cur_daemon, sizeof(int)) != sizeof(int)) 176: fatal("bad lock file (daemon pid)"); 177: for (i = 1; read(fd, (char *)&cur_pid, sizeof(int)) != sizeof(int); i++) { 178: if (i > 20) { 179: cur_pid = -1; /* choose impossible pid */ 180: break; 181: } 182: sleep(i); 183: } 184: close(fd); 185: return(0); 186: } 187: 188: /* 189: * Process the spool q: build an in-core table of the directory 190: * for use in deciding what gets removed. 191: */ 192: collect() 193: { 194: register int fd, items = 0; 195: register char c1, c2; 196: struct direct proto; 197: 198: if ((fd = open(".", 0)) < 0) 199: fatal("can't access spooling directory"); 200: /* 201: * skip . and .. 202: */ 203: lseek(fd, (long)(2*sizeof(struct direct)), 0); 204: pdir = (struct direct *)malloc(sizeof(struct direct)); 205: while(1) { 206: register struct direct *proto; 207: 208: proto = &pdir[items]; 209: if (read(fd, (char *)proto, sizeof(*proto)) != sizeof(*proto)) 210: break; 211: if (proto->d_ino == 0) 212: continue; 213: c1 = proto->d_name[0], c2 = proto->d_name[1]; 214: if (c1 != 't' && c1 != 'c' && c1 != 'd' && c1 != 'l') 215: continue; 216: if (c2 != 'f') 217: continue; 218: items++; 219: proto = (struct direct *)realloc((char *)pdir, (items+1)*sizeof(struct direct)); 220: if (proto == NULL) { 221: printf("out of memory, only handling %d items\n", items); 222: break; 223: } 224: pdir = proto; 225: } 226: return(items); 227: } 228: 229: /* 230: * Check through the requests and users to see if this 231: * directory entry should be removed. 232: */ 233: process(p) 234: register struct direct *p; 235: { 236: if (all || chk(p->d_name, atoi(p->d_name+3))) 237: printf(unlink(p->d_name) ? "can't dequeue %s\n" : "%s dequeued\n", 238: p->d_name); 239: } 240: /* 241: * Do the dirty work in checking 242: */ 243: chk(file, pid) 244: char *file; 245: int pid; 246: { 247: struct stat buf; 248: register struct passwd *q; 249: register int *r; 250: 251: /* 252: * Check the request list 253: */ 254: for (r = requ; r < &requ[requests]; r++) 255: #ifndef UNM 256: if (*r == pid && access(file, 4) == 0) 257: #else UNM 258: if (*r == pid && access(file, 2) == 0) 259: #endif UNM 260: return(1); 261: if (stat(file, &buf) < 0) 262: return(0); 263: /* 264: * Check to see if it's in the user list 265: */ 266: for (q = user; q < &user[users]; q++) 267: #ifndef UNM 268: if (q->pw_uid == buf.st_uid && access(file, 4) == 0) 269: #else UNM 270: if (q->pw_uid == buf.st_uid && access(file, 2) == 0) 271: #endif UNM 272: return(1); 273: return(0); 274: } 275: 276: fatal(s, a) 277: char *s, *a; 278: { 279: fprintf(stderr, "lprm: fatal error: "); 280: fprintf(stderr, s, a); 281: fputc('\n', stderr); 282: exit(1); 283: } 284: 285: usage() 286: { 287: printf("usage: lprm [-] [-Pprinter] [[job #] [user] ...]\n"); 288: exit(2); 289: } 290: 291: chkprinter(s) 292: char *s; 293: { 294: static char buf[BUFSIZ/2]; 295: char b[BUFSIZ]; 296: int stat; 297: char *bp = buf; 298: 299: if ((stat = pgetent(b, s)) < 0) 300: fatal("can't open description file"); 301: else if (stat == 0) 302: return(0); 303: if ((DN = pgetstr("dn", &bp)) == NULL) 304: DN = DEFDAEMON; 305: if ((SD = pgetstr("sd", &bp)) == NULL) 306: SD = DEFSPOOL; 307: if ((LO = pgetstr("lo", &bp)) == NULL) 308: LO = DEFLOCK; 309: AF = pgetstr("af", &bp); 310: return(1); 311: }