1: /* lpdrestart.c 1.3 81/10/21 */ 2: 3: #include "lp.local.h" 4: #include <sys/types.h> 5: #include <signal.h> 6: #include <stdio.h> 7: #include <ctype.h> 8: #include "local/uparm.h" 9: #include <sys/stat.h> 10: #include <whoami.h> 11: #include <errno.h> 12: 13: /* 14: * Restart line printer daemons after a reboot 15: */ 16: 17: #define MAXHOP 32 /* max number of tc= indirections */ 18: 19: #define tgetent pgetent 20: #define tskip pskip 21: #define tgetstr pgetstr 22: #define tdecode pdecode 23: #define tgetnum pgetnum 24: #define tgetflag pgetflag 25: #define tdecode pdecode 26: #define tnchktc pnchktc 27: #define tnamatch pnamatch 28: #undef E_TERMCAP 29: #define E_TERMCAP "/etc/printcap" 30: 31: char *DN; /* daemon name */ 32: char *LP; /* printer device */ 33: char *SD; /* spooling directory */ 34: char *LF; /* log file */ 35: char *name; /* name of current printer being worked on */ 36: char *rindex(); /* ZZZZZZZZZZZZZZZZZ */ 37: int DU; /* we will need the daemon uid */ 38: int fd, i, cur_daemon; 39: extern int errno; 40: char *LO; /* use the lockfile name in /etc/printcap */ 41: 42: FILE *lfd; /* open file descriptor for LF */ 43: 44: char *tskip(); 45: char *tgetstr(); 46: char *tdecode(); 47: 48: main(argc, argv) 49: char *argv[]; 50: { 51: char buf[BUFSIZ/2], b[BUFSIZ], *bp, lbuf[256]; 52: register char *Bp; 53: char namebuf[30]; 54: struct stat statb; 55: register int pid; 56: 57: while (getpr(b)) { 58: bp = buf; 59: if ((DN = pgetstr("dn", &bp)) == NULL) 60: DN = DEFDAEMON; 61: if ((LP = pgetstr("lp", &bp)) == NULL) 62: LP = DEFDEVLP; 63: if ((SD = pgetstr("sd", &bp)) == NULL) 64: SD = DEFSPOOL; 65: if ((LF = pgetstr("lf", &bp)) == NULL) 66: LF = DEFLOGF; 67: if ((LO = pgetstr("lo", &bp)) == NULL) 68: LO = DEFLOCK; 69: if ((DU = pgetnum("du", &bp)) == -1) 70: DU = DEFUID; 71: for (name = namebuf, Bp = b; *Bp && *Bp != ':' && *Bp != '|';) 72: *name++ = *Bp++; 73: *name = '\0'; 74: name = namebuf; 75: if ((lfd = fopen(LF, "a")) == NULL) 76: lfd = stderr; /* expected to be console? */ 77: /* 78: * First check if device is down (mode 0) 79: */ 80: if (stat(LP, (char *)&statb) < 0) { 81: log("%s: can't stat %s", name, LP); 82: continue; 83: } 84: if (statb.st_mode == 0) { 85: log("%s: printer marked down", name); 86: continue; 87: } 88: 89: /* 90: * Remove a lock file if it's present, then 91: * restart the daemon 92: */ 93: sprintf(lbuf, "%s/%s", SD, (bp = rindex(LO,'/')) ? bp+1 : LO); 94: if (stat(lbuf, (char *)&statb) >= 0) { 95: /* 96: * Unskilled people may be using this command 97: * and it would not be kind to allow two daemons 98: * to do battle in their midst 99: */ 100: 101: if ((fd = open(lbuf, 0)) < 0) { 102: if (errno == EACCES) 103: log("%s: can't access %s", name, lbuf); 104: } else { 105: if (read(fd, (char *)&cur_daemon, sizeof(int)) != sizeof(int)) 106: fatal("bad lock file (daemon pid)"); 107: close(fd); 108: setuid(DU); 109: kill(cur_daemon,SIGTERM); /* This could be bad... */ 110: } 111: if (unlink(lbuf)) { 112: log("%s: can't unlink %s in %s", name, lbuf, SD); 113: continue; 114: } 115: } 116: if ((pid = fork()) < 0) 117: log("%s: can't fork", name); 118: else if (!pid) { 119: execl(DN, (bp = rindex(DN, '/')) ? bp+1 : DN, name, 0); 120: log("%s: can't execl %s", name, DN); 121: exit(1); 122: } else 123: fclose(lfd); 124: } 125: } 126: 127: /*VARARGS1*/ 128: log(message, a1, a2, a3) 129: char *message; 130: { 131: short console = isatty(fileno(lfd)); 132: 133: fprintf(lfd, console ? "\r\n%s: " : "%s: ", name); 134: fprintf(lfd, message, a1, a2, a3); 135: if (console) 136: putc('\r', lfd); 137: putc('\n', lfd); 138: fclose(lfd); 139: } 140: 141: /*VARARGS*/ 142: fatal(fmt, arg) 143: char *fmt; 144: { 145: fprintf(stderr, "lpdrestart: "); 146: fprintf(stderr, fmt, arg); 147: putc('\n', stderr); 148: exit(1); 149: } 150: 151: /* 152: * Routines to perform a sequential pass through the printer 153: * data base. Things are slightly complicated by interactions 154: * with the printcap routines. 155: */ 156: 157: static int pfd = -1; /* for reading from data base */ 158: static long nextloc = -1L; /* seek offset */ 159: static char *tbuf; 160: static int hopcount; 161: 162: setpr() 163: { 164: if ((pfd = open(E_TERMCAP, 0)) < 0) 165: fatal("can't open %s", E_TERMCAP); 166: nextloc = 0L; 167: } 168: 169: endpr() 170: { 171: close(pfd); 172: nextloc = 0L; 173: } 174: 175: getpr(bp) 176: char *bp; 177: { 178: register char *cp, *Bp; 179: register int i = 0, cnt = 0, c; 180: char ibuf[BUFSIZ]; 181: 182: if (pfd < 0) 183: setpr(); 184: else 185: lseek(pfd, nextloc, 0); /* move sequentially */ 186: /* 187: * This code is (for the most part) taken from tgetent() 188: */ 189: tbuf = bp; 190: for (;;) { 191: cp = bp; 192: for (;;) { 193: if (i == cnt) { 194: cnt = read(pfd, ibuf, BUFSIZ); 195: if (cnt <= 0) { 196: endpr(); 197: return(NULL); 198: } 199: i = 0; 200: } 201: c = ibuf[i++]; 202: if (c == '\n') { 203: if (cp > bp && cp[-1] == '\\') { 204: cp--; 205: continue; 206: } 207: break; 208: } 209: if (cp >= bp+BUFSIZ) 210: fatal("printcap entry too long"); 211: *cp++ = c; 212: } 213: *cp = 0; 214: /* 215: * Interpret the printer description and adjust 216: * nextloc so that we'll start scanning again 217: * after this record. 218: */ 219: nextloc += i; /* amount taken from read buffer */ 220: Bp = tbuf; 221: if (*Bp != '#' && *Bp != '\0') { 222: /* 223: * For now, we won't support "tc" chaining 224: */ 225: return(1); 226: } 227: } 228: } 229: 230: /* 231: * Skip to the next field. Notice that this is very dumb, not 232: * knowing about \: escapes or any such. If necessary, :'s can be put 233: * into the termcap file in octal. 234: */ 235: static char * 236: tskip(bp) 237: register char *bp; 238: { 239: 240: while (*bp && *bp != ':') 241: bp++; 242: if (*bp == ':') 243: bp++; 244: return (bp); 245: } 246: 247: /* 248: * Get a string valued option. 249: * These are given as 250: * cl=^Z 251: * Much decoding is done on the strings, and the strings are 252: * placed in area, which is a ref parameter which is updated. 253: * No checking on area overflow. 254: */ 255: char * 256: tgetstr(id, area) 257: char *id, **area; 258: { 259: register char *bp = tbuf; 260: 261: for (;;) { 262: bp = tskip(bp); 263: if (!*bp) 264: return (0); 265: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 266: continue; 267: if (*bp == '@') 268: return(0); 269: if (*bp != '=') 270: continue; 271: bp++; 272: return (tdecode(bp, area)); 273: } 274: } 275: 276: /* 277: * Tdecode does the grung work to decode the 278: * string capability escapes. 279: */ 280: static char * 281: tdecode(str, area) 282: register char *str; 283: char **area; 284: { 285: register char *cp; 286: register int c; 287: register char *dp; 288: int i; 289: 290: cp = *area; 291: while ((c = *str++) && c != ':') { 292: switch (c) { 293: 294: case '^': 295: c = *str++ & 037; 296: break; 297: 298: case '\\': 299: dp = "E\033^^\\\\::n\nr\rt\tb\bf\f"; 300: c = *str++; 301: nextc: 302: if (*dp++ == c) { 303: c = *dp++; 304: break; 305: } 306: dp++; 307: if (*dp) 308: goto nextc; 309: if (isdigit(c)) { 310: c -= '0', i = 2; 311: do 312: c <<= 3, c |= *str++ - '0'; 313: while (--i && isdigit(*str)); 314: } 315: break; 316: } 317: *cp++ = c; 318: } 319: *cp++ = 0; 320: str = *area; 321: *area = cp; 322: return (str); 323: } 324: 325: /* 326: * Return the (numeric) option id. 327: * Numeric options look like 328: * li#80 329: * i.e. the option string is separated from the numeric value by 330: * a # character. If the option is not found we return -1. 331: * Note that we handle octal numbers beginning with 0. 332: */ 333: pgetnum(id) 334: char *id; 335: { 336: register int i, base; 337: register char *bp = tbuf; 338: 339: for (;;) { 340: bp = tskip(bp); 341: if (*bp == 0) 342: return (-1); 343: if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) 344: continue; 345: if (*bp == '@') 346: return(-1); 347: if (*bp != '#') 348: continue; 349: bp++; 350: base = 10; 351: if (*bp == '0') 352: base = 8; 353: i = 0; 354: while (isdigit(*bp)) 355: i *= base, i += *bp++ - '0'; 356: return (i); 357: } 358: }