1 1.25 mrg /* $NetBSD: cmds.c,v 1.25 2016/12/16 04:45:04 mrg Exp $ */ 2 1.1 cgd /* 3 1.4 cgd * Copyright (c) 1983, 1993 4 1.4 cgd * The Regents of the University of California. All rights reserved. 5 1.4 cgd * 6 1.1 cgd * 7 1.1 cgd * Redistribution and use in source and binary forms, with or without 8 1.1 cgd * modification, are permitted provided that the following conditions 9 1.1 cgd * are met: 10 1.1 cgd * 1. Redistributions of source code must retain the above copyright 11 1.1 cgd * notice, this list of conditions and the following disclaimer. 12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 cgd * notice, this list of conditions and the following disclaimer in the 14 1.1 cgd * documentation and/or other materials provided with the distribution. 15 1.16 agc * 3. Neither the name of the University nor the names of its contributors 16 1.1 cgd * may be used to endorse or promote products derived from this software 17 1.1 cgd * without specific prior written permission. 18 1.1 cgd * 19 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 cgd * SUCH DAMAGE. 30 1.1 cgd */ 31 1.1 cgd 32 1.12 mrg #include <sys/cdefs.h> 33 1.1 cgd #ifndef lint 34 1.20 lukem __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 35 1.20 lukem The Regents of the University of California. All rights reserved."); 36 1.10 mikel #if 0 37 1.11 mrg static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95"; 38 1.10 mikel #else 39 1.25 mrg __RCSID("$NetBSD: cmds.c,v 1.25 2016/12/16 04:45:04 mrg Exp $"); 40 1.10 mikel #endif 41 1.1 cgd #endif /* not lint */ 42 1.1 cgd 43 1.1 cgd /* 44 1.1 cgd * lpc -- line printer control program -- commands: 45 1.1 cgd */ 46 1.1 cgd 47 1.4 cgd #include <sys/param.h> 48 1.4 cgd #include <sys/time.h> 49 1.4 cgd #include <sys/stat.h> 50 1.11 mrg #include <sys/file.h> 51 1.4 cgd 52 1.4 cgd #include <signal.h> 53 1.4 cgd #include <fcntl.h> 54 1.4 cgd #include <errno.h> 55 1.4 cgd #include <dirent.h> 56 1.4 cgd #include <unistd.h> 57 1.4 cgd #include <stdlib.h> 58 1.4 cgd #include <stdio.h> 59 1.4 cgd #include <ctype.h> 60 1.4 cgd #include <string.h> 61 1.1 cgd #include "lp.h" 62 1.4 cgd #include "lp.local.h" 63 1.4 cgd #include "lpc.h" 64 1.4 cgd #include "extern.h" 65 1.1 cgd #include "pathnames.h" 66 1.1 cgd 67 1.5 hpeyerl extern uid_t uid, euid; 68 1.5 hpeyerl 69 1.14 wiz static void abortpr(int); 70 1.14 wiz static void cleanpr(void); 71 1.14 wiz static void disablepr(void); 72 1.18 christos static int doarg(const char *); 73 1.14 wiz static int doselect(const struct dirent *); 74 1.14 wiz static void enablepr(void); 75 1.14 wiz static void prstat(void); 76 1.14 wiz static void putmsg(int, char **); 77 1.25 mrg static int sortq(const struct dirent **, const struct dirent **); 78 1.14 wiz static void startpr(int); 79 1.14 wiz static void stoppr(void); 80 1.14 wiz static int touch(struct queue *); 81 1.18 christos static void unlinkf(const char *); 82 1.18 christos static void upstat(const char *); 83 1.18 christos static int getcapdesc(void); 84 1.18 christos static void getcaps(void); 85 1.4 cgd 86 1.1 cgd /* 87 1.1 cgd * kill an existing daemon and disable printing. 88 1.1 cgd */ 89 1.4 cgd void 90 1.14 wiz doabort(int argc, char *argv[]) 91 1.1 cgd { 92 1.18 christos int c; 93 1.12 mrg char *cp1, *cp2; 94 1.1 cgd char prbuf[100]; 95 1.1 cgd 96 1.1 cgd if (argc == 1) { 97 1.1 cgd printf("Usage: abort {all | printer ...}\n"); 98 1.1 cgd return; 99 1.1 cgd } 100 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 101 1.1 cgd printer = prbuf; 102 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 103 1.1 cgd cp1 = prbuf; 104 1.4 cgd cp2 = bp; 105 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 106 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 107 1.1 cgd *cp1++ = c; 108 1.1 cgd *cp1 = '\0'; 109 1.1 cgd abortpr(1); 110 1.1 cgd } 111 1.1 cgd return; 112 1.1 cgd } 113 1.1 cgd while (--argc) { 114 1.1 cgd printer = *++argv; 115 1.18 christos if (!getcapdesc()) 116 1.1 cgd continue; 117 1.1 cgd abortpr(1); 118 1.1 cgd } 119 1.1 cgd } 120 1.1 cgd 121 1.4 cgd static void 122 1.14 wiz abortpr(int dis) 123 1.1 cgd { 124 1.12 mrg FILE *fp; 125 1.1 cgd struct stat stbuf; 126 1.12 mrg int pid, fd; 127 1.1 cgd 128 1.18 christos getcaps(); 129 1.1 cgd printf("%s:\n", printer); 130 1.1 cgd 131 1.1 cgd /* 132 1.1 cgd * Turn on the owner execute bit of the lock file to disable printing. 133 1.1 cgd */ 134 1.1 cgd if (dis) { 135 1.5 hpeyerl seteuid(euid); 136 1.1 cgd if (stat(line, &stbuf) >= 0) { 137 1.1 cgd if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 138 1.1 cgd printf("\tcannot disable printing\n"); 139 1.1 cgd else { 140 1.1 cgd upstat("printing disabled\n"); 141 1.1 cgd printf("\tprinting disabled\n"); 142 1.1 cgd } 143 1.1 cgd } else if (errno == ENOENT) { 144 1.1 cgd if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 145 1.1 cgd printf("\tcannot create lock file\n"); 146 1.1 cgd else { 147 1.8 mrg (void)close(fd); 148 1.1 cgd upstat("printing disabled\n"); 149 1.1 cgd printf("\tprinting disabled\n"); 150 1.1 cgd printf("\tno daemon to abort\n"); 151 1.1 cgd } 152 1.5 hpeyerl goto out; 153 1.1 cgd } else { 154 1.1 cgd printf("\tcannot stat lock file\n"); 155 1.5 hpeyerl goto out; 156 1.1 cgd } 157 1.1 cgd } 158 1.1 cgd /* 159 1.1 cgd * Kill the current daemon to stop printing now. 160 1.1 cgd */ 161 1.1 cgd if ((fp = fopen(line, "r")) == NULL) { 162 1.1 cgd printf("\tcannot open lock file\n"); 163 1.5 hpeyerl goto out; 164 1.1 cgd } 165 1.22 roy if (!get_line(fp) || flock(fileno(fp), LOCK_SH|LOCK_NB) == 0) { 166 1.8 mrg (void)fclose(fp); /* unlocks as well */ 167 1.1 cgd printf("\tno daemon to abort\n"); 168 1.5 hpeyerl goto out; 169 1.1 cgd } 170 1.8 mrg (void)fclose(fp); 171 1.12 mrg if (kill(pid = atoi(line), SIGTERM) < 0) { 172 1.12 mrg if (errno == ESRCH) 173 1.12 mrg printf("\tno daemon to abort\n"); 174 1.12 mrg else 175 1.12 mrg printf("\tWarning: daemon (pid %d) not killed\n", pid); 176 1.12 mrg } else 177 1.1 cgd printf("\tdaemon (pid %d) killed\n", pid); 178 1.5 hpeyerl out: 179 1.5 hpeyerl seteuid(uid); 180 1.1 cgd } 181 1.1 cgd 182 1.1 cgd /* 183 1.1 cgd * Write a message into the status file. 184 1.1 cgd */ 185 1.4 cgd static void 186 1.18 christos upstat(const char *msg) 187 1.1 cgd { 188 1.12 mrg int fd; 189 1.12 mrg char statfile[MAXPATHLEN]; 190 1.1 cgd 191 1.18 christos getcaps(); 192 1.8 mrg (void)snprintf(statfile, sizeof(statfile), "%s/%s", SD, ST); 193 1.1 cgd umask(0); 194 1.1 cgd fd = open(statfile, O_WRONLY|O_CREAT, 0664); 195 1.1 cgd if (fd < 0 || flock(fd, LOCK_EX) < 0) { 196 1.1 cgd printf("\tcannot create status file\n"); 197 1.19 christos if (fd >= 0) 198 1.19 christos (void)close(fd); 199 1.1 cgd return; 200 1.1 cgd } 201 1.8 mrg (void)ftruncate(fd, 0); 202 1.24 plunky if (msg == NULL) 203 1.8 mrg (void)write(fd, "\n", 1); 204 1.1 cgd else 205 1.8 mrg (void)write(fd, msg, strlen(msg)); 206 1.8 mrg (void)close(fd); 207 1.1 cgd } 208 1.1 cgd 209 1.1 cgd /* 210 1.1 cgd * Remove all spool files and temporaries from the spooling area. 211 1.1 cgd */ 212 1.4 cgd void 213 1.14 wiz clean(int argc, char *argv[]) 214 1.1 cgd { 215 1.18 christos int c; 216 1.12 mrg char *cp1, *cp2; 217 1.1 cgd char prbuf[100]; 218 1.1 cgd 219 1.1 cgd if (argc == 1) { 220 1.1 cgd printf("Usage: clean {all | printer ...}\n"); 221 1.1 cgd return; 222 1.1 cgd } 223 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 224 1.1 cgd printer = prbuf; 225 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 226 1.1 cgd cp1 = prbuf; 227 1.4 cgd cp2 = bp; 228 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 229 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 230 1.1 cgd *cp1++ = c; 231 1.1 cgd *cp1 = '\0'; 232 1.1 cgd cleanpr(); 233 1.1 cgd } 234 1.1 cgd return; 235 1.1 cgd } 236 1.1 cgd while (--argc) { 237 1.1 cgd printer = *++argv; 238 1.18 christos if (!getcapdesc()) 239 1.1 cgd continue; 240 1.1 cgd cleanpr(); 241 1.1 cgd } 242 1.1 cgd } 243 1.1 cgd 244 1.4 cgd static int 245 1.14 wiz doselect(const struct dirent *d) 246 1.1 cgd { 247 1.1 cgd int c = d->d_name[0]; 248 1.1 cgd 249 1.1 cgd if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f') 250 1.1 cgd return(1); 251 1.1 cgd return(0); 252 1.1 cgd } 253 1.1 cgd 254 1.1 cgd /* 255 1.1 cgd * Comparison routine for scandir. Sort by job number and machine, then 256 1.1 cgd * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z. 257 1.1 cgd */ 258 1.4 cgd static int 259 1.25 mrg sortq(const struct dirent **d1, const struct dirent **d2) 260 1.1 cgd { 261 1.1 cgd int c1, c2; 262 1.1 cgd 263 1.9 mikel if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0) 264 1.1 cgd return(c1); 265 1.1 cgd c1 = (*d1)->d_name[0]; 266 1.1 cgd c2 = (*d2)->d_name[0]; 267 1.1 cgd if (c1 == c2) 268 1.1 cgd return((*d1)->d_name[2] - (*d2)->d_name[2]); 269 1.1 cgd if (c1 == 'c') 270 1.1 cgd return(-1); 271 1.1 cgd if (c1 == 'd' || c2 == 'c') 272 1.1 cgd return(1); 273 1.1 cgd return(-1); 274 1.1 cgd } 275 1.1 cgd 276 1.1 cgd /* 277 1.1 cgd * Remove incomplete jobs from spooling area. 278 1.1 cgd */ 279 1.4 cgd static void 280 1.14 wiz cleanpr(void) 281 1.1 cgd { 282 1.12 mrg int i, n; 283 1.18 christos char *cp1, *lp, *ep; 284 1.18 christos const char *cp; 285 1.3 jtc struct dirent **queue; 286 1.1 cgd int nitems; 287 1.1 cgd 288 1.18 christos getcaps(); 289 1.1 cgd printf("%s:\n", printer); 290 1.1 cgd 291 1.8 mrg /* XXX depends on SD being non nul */ 292 1.15 itojun ep = line + sizeof(line); 293 1.21 lukem for (lp = line, cp = SD; (size_t)(lp - line) < sizeof(line) && 294 1.12 mrg (*lp++ = *cp++) != '\0'; ) 295 1.1 cgd ; 296 1.1 cgd lp[-1] = '/'; 297 1.1 cgd 298 1.5 hpeyerl seteuid(euid); 299 1.4 cgd nitems = scandir(SD, &queue, doselect, sortq); 300 1.5 hpeyerl seteuid(uid); 301 1.1 cgd if (nitems < 0) { 302 1.1 cgd printf("\tcannot examine spool directory\n"); 303 1.1 cgd return; 304 1.1 cgd } 305 1.1 cgd if (nitems == 0) 306 1.1 cgd return; 307 1.1 cgd i = 0; 308 1.1 cgd do { 309 1.1 cgd cp = queue[i]->d_name; 310 1.1 cgd if (*cp == 'c') { 311 1.1 cgd n = 0; 312 1.1 cgd while (i + 1 < nitems) { 313 1.1 cgd cp1 = queue[i + 1]->d_name; 314 1.1 cgd if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3)) 315 1.1 cgd break; 316 1.1 cgd i++; 317 1.1 cgd n++; 318 1.1 cgd } 319 1.1 cgd if (n == 0) { 320 1.15 itojun strlcpy(lp, cp, ep - lp); 321 1.1 cgd unlinkf(line); 322 1.1 cgd } 323 1.1 cgd } else { 324 1.1 cgd /* 325 1.1 cgd * Must be a df with no cf (otherwise, it would have 326 1.1 cgd * been skipped above) or a tf file (which can always 327 1.1 cgd * be removed). 328 1.1 cgd */ 329 1.15 itojun strlcpy(lp, cp, ep - lp); 330 1.1 cgd unlinkf(line); 331 1.1 cgd } 332 1.1 cgd } while (++i < nitems); 333 1.1 cgd } 334 1.1 cgd 335 1.4 cgd static void 336 1.18 christos unlinkf(const char *name) 337 1.1 cgd { 338 1.5 hpeyerl seteuid(euid); 339 1.1 cgd if (unlink(name) < 0) 340 1.1 cgd printf("\tcannot remove %s\n", name); 341 1.1 cgd else 342 1.1 cgd printf("\tremoved %s\n", name); 343 1.5 hpeyerl seteuid(uid); 344 1.1 cgd } 345 1.1 cgd 346 1.1 cgd /* 347 1.1 cgd * Enable queuing to the printer (allow lpr's). 348 1.1 cgd */ 349 1.4 cgd void 350 1.14 wiz enable(int argc, char *argv[]) 351 1.1 cgd { 352 1.18 christos int c; 353 1.12 mrg char *cp1, *cp2; 354 1.1 cgd char prbuf[100]; 355 1.1 cgd 356 1.1 cgd if (argc == 1) { 357 1.1 cgd printf("Usage: enable {all | printer ...}\n"); 358 1.1 cgd return; 359 1.1 cgd } 360 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 361 1.1 cgd printer = prbuf; 362 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 363 1.1 cgd cp1 = prbuf; 364 1.4 cgd cp2 = bp; 365 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 366 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 367 1.1 cgd *cp1++ = c; 368 1.1 cgd *cp1 = '\0'; 369 1.1 cgd enablepr(); 370 1.1 cgd } 371 1.1 cgd return; 372 1.1 cgd } 373 1.1 cgd while (--argc) { 374 1.1 cgd printer = *++argv; 375 1.18 christos if (!getcapdesc()) 376 1.1 cgd continue; 377 1.1 cgd enablepr(); 378 1.1 cgd } 379 1.1 cgd } 380 1.1 cgd 381 1.18 christos static int 382 1.18 christos getcapdesc(void) 383 1.18 christos { 384 1.18 christos int st; 385 1.18 christos if ((st = cgetent(&bp, printcapdb, printer)) == -2) { 386 1.18 christos printf("cannot open printer description file\n"); 387 1.18 christos return 0; 388 1.18 christos } else if (st == -1) { 389 1.18 christos printf("unknown printer %s\n", printer); 390 1.18 christos return 0; 391 1.18 christos } else if (st == -3) 392 1.18 christos fatal("potential reference loop detected in printcap file"); 393 1.18 christos return 1; 394 1.18 christos } 395 1.18 christos 396 1.4 cgd static void 397 1.14 wiz enablepr(void) 398 1.1 cgd { 399 1.1 cgd struct stat stbuf; 400 1.1 cgd 401 1.18 christos getcaps(); 402 1.1 cgd printf("%s:\n", printer); 403 1.1 cgd 404 1.1 cgd /* 405 1.1 cgd * Turn off the group execute bit of the lock file to enable queuing. 406 1.1 cgd */ 407 1.5 hpeyerl seteuid(euid); 408 1.1 cgd if (stat(line, &stbuf) >= 0) { 409 1.1 cgd if (chmod(line, stbuf.st_mode & 0767) < 0) 410 1.1 cgd printf("\tcannot enable queuing\n"); 411 1.1 cgd else 412 1.1 cgd printf("\tqueuing enabled\n"); 413 1.1 cgd } 414 1.5 hpeyerl seteuid(uid); 415 1.1 cgd } 416 1.1 cgd 417 1.1 cgd /* 418 1.1 cgd * Disable queuing. 419 1.1 cgd */ 420 1.4 cgd void 421 1.14 wiz disable(int argc, char *argv[]) 422 1.1 cgd { 423 1.18 christos int c; 424 1.12 mrg char *cp1, *cp2; 425 1.1 cgd char prbuf[100]; 426 1.1 cgd 427 1.1 cgd if (argc == 1) { 428 1.1 cgd printf("Usage: disable {all | printer ...}\n"); 429 1.1 cgd return; 430 1.1 cgd } 431 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 432 1.1 cgd printer = prbuf; 433 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 434 1.1 cgd cp1 = prbuf; 435 1.4 cgd cp2 = bp; 436 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 437 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 438 1.1 cgd *cp1++ = c; 439 1.1 cgd *cp1 = '\0'; 440 1.1 cgd disablepr(); 441 1.1 cgd } 442 1.1 cgd return; 443 1.1 cgd } 444 1.1 cgd while (--argc) { 445 1.1 cgd printer = *++argv; 446 1.18 christos if (!getcapdesc()) 447 1.1 cgd continue; 448 1.1 cgd disablepr(); 449 1.1 cgd } 450 1.1 cgd } 451 1.1 cgd 452 1.4 cgd static void 453 1.14 wiz disablepr(void) 454 1.1 cgd { 455 1.12 mrg int fd; 456 1.1 cgd struct stat stbuf; 457 1.1 cgd 458 1.18 christos getcaps(); 459 1.1 cgd printf("%s:\n", printer); 460 1.1 cgd /* 461 1.1 cgd * Turn on the group execute bit of the lock file to disable queuing. 462 1.1 cgd */ 463 1.5 hpeyerl seteuid(euid); 464 1.1 cgd if (stat(line, &stbuf) >= 0) { 465 1.1 cgd if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0) 466 1.1 cgd printf("\tcannot disable queuing\n"); 467 1.1 cgd else 468 1.1 cgd printf("\tqueuing disabled\n"); 469 1.1 cgd } else if (errno == ENOENT) { 470 1.1 cgd if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0) 471 1.1 cgd printf("\tcannot create lock file\n"); 472 1.1 cgd else { 473 1.8 mrg (void)close(fd); 474 1.1 cgd printf("\tqueuing disabled\n"); 475 1.1 cgd } 476 1.1 cgd } else 477 1.1 cgd printf("\tcannot stat lock file\n"); 478 1.5 hpeyerl seteuid(uid); 479 1.1 cgd } 480 1.1 cgd 481 1.1 cgd /* 482 1.1 cgd * Disable queuing and printing and put a message into the status file 483 1.1 cgd * (reason for being down). 484 1.1 cgd */ 485 1.4 cgd void 486 1.14 wiz down(int argc, char *argv[]) 487 1.1 cgd { 488 1.18 christos int c; 489 1.12 mrg char *cp1, *cp2; 490 1.1 cgd char prbuf[100]; 491 1.1 cgd 492 1.1 cgd if (argc == 1) { 493 1.1 cgd printf("Usage: down {all | printer} [message ...]\n"); 494 1.1 cgd return; 495 1.1 cgd } 496 1.1 cgd if (!strcmp(argv[1], "all")) { 497 1.1 cgd printer = prbuf; 498 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 499 1.1 cgd cp1 = prbuf; 500 1.4 cgd cp2 = bp; 501 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 502 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 503 1.1 cgd *cp1++ = c; 504 1.1 cgd *cp1 = '\0'; 505 1.1 cgd putmsg(argc - 2, argv + 2); 506 1.1 cgd } 507 1.1 cgd return; 508 1.1 cgd } 509 1.1 cgd printer = argv[1]; 510 1.18 christos if (!getcapdesc()) 511 1.1 cgd return; 512 1.18 christos putmsg(argc - 2, argv + 2); 513 1.18 christos } 514 1.4 cgd 515 1.18 christos static void 516 1.18 christos getcaps(void) 517 1.18 christos { 518 1.18 christos char *cp; 519 1.18 christos SD = cgetstr(bp, "sd", &cp) == -1 ? _PATH_DEFSPOOL : cp; 520 1.18 christos LO = cgetstr(bp, "lo", &cp) == -1 ? DEFLOCK : cp; 521 1.18 christos ST = cgetstr(bp, "st", &cp) == -1 ? DEFSTAT : cp; 522 1.18 christos (void)snprintf(line, sizeof(line), "%s/%s", SD, LO); 523 1.1 cgd } 524 1.1 cgd 525 1.4 cgd static void 526 1.14 wiz putmsg(int argc, char **argv) 527 1.1 cgd { 528 1.12 mrg int fd; 529 1.12 mrg char *cp1, *cp2; 530 1.1 cgd char buf[1024]; 531 1.1 cgd struct stat stbuf; 532 1.1 cgd 533 1.1 cgd printf("%s:\n", printer); 534 1.1 cgd /* 535 1.1 cgd * Turn on the group execute bit of the lock file to disable queuing and 536 1.1 cgd * turn on the owner execute bit of the lock file to disable printing. 537 1.1 cgd */ 538 1.5 hpeyerl seteuid(euid); 539 1.1 cgd if (stat(line, &stbuf) >= 0) { 540 1.1 cgd if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0) 541 1.1 cgd printf("\tcannot disable queuing\n"); 542 1.1 cgd else 543 1.1 cgd printf("\tprinter and queuing disabled\n"); 544 1.1 cgd } else if (errno == ENOENT) { 545 1.1 cgd if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0) 546 1.1 cgd printf("\tcannot create lock file\n"); 547 1.1 cgd else { 548 1.8 mrg (void)close(fd); 549 1.1 cgd printf("\tprinter and queuing disabled\n"); 550 1.1 cgd } 551 1.5 hpeyerl seteuid(uid); 552 1.1 cgd return; 553 1.1 cgd } else 554 1.1 cgd printf("\tcannot stat lock file\n"); 555 1.1 cgd /* 556 1.1 cgd * Write the message into the status file. 557 1.1 cgd */ 558 1.8 mrg (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 559 1.1 cgd fd = open(line, O_WRONLY|O_CREAT, 0664); 560 1.1 cgd if (fd < 0 || flock(fd, LOCK_EX) < 0) { 561 1.1 cgd printf("\tcannot create status file\n"); 562 1.5 hpeyerl seteuid(uid); 563 1.23 wiz if (fd >= 0) 564 1.23 wiz (void)close(fd); 565 1.1 cgd return; 566 1.1 cgd } 567 1.5 hpeyerl seteuid(uid); 568 1.8 mrg (void)ftruncate(fd, 0); 569 1.1 cgd if (argc <= 0) { 570 1.8 mrg (void)write(fd, "\n", 1); 571 1.8 mrg (void)close(fd); 572 1.1 cgd return; 573 1.1 cgd } 574 1.1 cgd cp1 = buf; 575 1.1 cgd while (--argc >= 0) { 576 1.1 cgd cp2 = *argv++; 577 1.21 lukem while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++)) 578 1.1 cgd ; 579 1.1 cgd cp1[-1] = ' '; 580 1.1 cgd } 581 1.1 cgd cp1[-1] = '\n'; 582 1.1 cgd *cp1 = '\0'; 583 1.8 mrg (void)write(fd, buf, strlen(buf)); 584 1.8 mrg (void)close(fd); 585 1.1 cgd } 586 1.1 cgd 587 1.1 cgd /* 588 1.1 cgd * Exit lpc 589 1.1 cgd */ 590 1.4 cgd void 591 1.14 wiz quit(int argc, char *argv[]) 592 1.1 cgd { 593 1.1 cgd exit(0); 594 1.1 cgd } 595 1.1 cgd 596 1.1 cgd /* 597 1.1 cgd * Kill and restart the daemon. 598 1.1 cgd */ 599 1.4 cgd void 600 1.14 wiz restart(int argc, char *argv[]) 601 1.1 cgd { 602 1.18 christos int c; 603 1.12 mrg char *cp1, *cp2; 604 1.1 cgd char prbuf[100]; 605 1.1 cgd 606 1.1 cgd if (argc == 1) { 607 1.1 cgd printf("Usage: restart {all | printer ...}\n"); 608 1.1 cgd return; 609 1.1 cgd } 610 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 611 1.1 cgd printer = prbuf; 612 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 613 1.1 cgd cp1 = prbuf; 614 1.4 cgd cp2 = bp; 615 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 616 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 617 1.1 cgd *cp1++ = c; 618 1.1 cgd *cp1 = '\0'; 619 1.1 cgd abortpr(0); 620 1.1 cgd startpr(0); 621 1.1 cgd } 622 1.1 cgd return; 623 1.1 cgd } 624 1.1 cgd while (--argc) { 625 1.1 cgd printer = *++argv; 626 1.18 christos if (!getcapdesc()) 627 1.1 cgd continue; 628 1.1 cgd abortpr(0); 629 1.1 cgd startpr(0); 630 1.1 cgd } 631 1.1 cgd } 632 1.1 cgd 633 1.1 cgd /* 634 1.1 cgd * Enable printing on the specified printer and startup the daemon. 635 1.1 cgd */ 636 1.4 cgd void 637 1.14 wiz startcmd(int argc, char *argv[]) 638 1.1 cgd { 639 1.18 christos int c; 640 1.12 mrg char *cp1, *cp2; 641 1.1 cgd char prbuf[100]; 642 1.1 cgd 643 1.1 cgd if (argc == 1) { 644 1.1 cgd printf("Usage: start {all | printer ...}\n"); 645 1.1 cgd return; 646 1.1 cgd } 647 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 648 1.1 cgd printer = prbuf; 649 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 650 1.1 cgd cp1 = prbuf; 651 1.4 cgd cp2 = bp; 652 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 653 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 654 1.1 cgd *cp1++ = c; 655 1.1 cgd *cp1 = '\0'; 656 1.1 cgd startpr(1); 657 1.1 cgd } 658 1.1 cgd return; 659 1.1 cgd } 660 1.1 cgd while (--argc) { 661 1.1 cgd printer = *++argv; 662 1.18 christos if (!getcapdesc()) 663 1.1 cgd continue; 664 1.1 cgd startpr(1); 665 1.1 cgd } 666 1.1 cgd } 667 1.1 cgd 668 1.4 cgd static void 669 1.18 christos startpr(int ena) 670 1.1 cgd { 671 1.1 cgd struct stat stbuf; 672 1.1 cgd 673 1.18 christos getcaps(); 674 1.1 cgd printf("%s:\n", printer); 675 1.1 cgd 676 1.1 cgd /* 677 1.1 cgd * Turn off the owner execute bit of the lock file to enable printing. 678 1.1 cgd */ 679 1.5 hpeyerl seteuid(euid); 680 1.18 christos if (ena && stat(line, &stbuf) >= 0) { 681 1.18 christos if (chmod(line, stbuf.st_mode & (ena == 2 ? 0666 : 0677)) < 0) 682 1.1 cgd printf("\tcannot enable printing\n"); 683 1.1 cgd else 684 1.1 cgd printf("\tprinting enabled\n"); 685 1.1 cgd } 686 1.1 cgd if (!startdaemon(printer)) 687 1.1 cgd printf("\tcouldn't start daemon\n"); 688 1.1 cgd else 689 1.1 cgd printf("\tdaemon started\n"); 690 1.5 hpeyerl seteuid(uid); 691 1.1 cgd } 692 1.1 cgd 693 1.1 cgd /* 694 1.1 cgd * Print the status of each queue listed or all the queues. 695 1.1 cgd */ 696 1.4 cgd void 697 1.14 wiz status(int argc, char *argv[]) 698 1.1 cgd { 699 1.18 christos int c; 700 1.12 mrg char *cp1, *cp2; 701 1.1 cgd char prbuf[100]; 702 1.1 cgd 703 1.12 mrg if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) { 704 1.1 cgd printer = prbuf; 705 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 706 1.1 cgd cp1 = prbuf; 707 1.4 cgd cp2 = bp; 708 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 709 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 710 1.1 cgd *cp1++ = c; 711 1.1 cgd *cp1 = '\0'; 712 1.1 cgd prstat(); 713 1.1 cgd } 714 1.1 cgd return; 715 1.1 cgd } 716 1.1 cgd while (--argc) { 717 1.1 cgd printer = *++argv; 718 1.18 christos if (!getcapdesc()) 719 1.1 cgd continue; 720 1.1 cgd prstat(); 721 1.1 cgd } 722 1.1 cgd } 723 1.1 cgd 724 1.1 cgd /* 725 1.1 cgd * Print the status of the printer queue. 726 1.1 cgd */ 727 1.4 cgd static void 728 1.14 wiz prstat(void) 729 1.1 cgd { 730 1.1 cgd struct stat stbuf; 731 1.12 mrg int fd, i; 732 1.12 mrg struct dirent *dp; 733 1.1 cgd DIR *dirp; 734 1.1 cgd 735 1.18 christos getcaps(); 736 1.1 cgd printf("%s:\n", printer); 737 1.1 cgd if (stat(line, &stbuf) >= 0) { 738 1.1 cgd printf("\tqueuing is %s\n", 739 1.1 cgd (stbuf.st_mode & 010) ? "disabled" : "enabled"); 740 1.1 cgd printf("\tprinting is %s\n", 741 1.1 cgd (stbuf.st_mode & 0100) ? "disabled" : "enabled"); 742 1.1 cgd } else { 743 1.1 cgd printf("\tqueuing is enabled\n"); 744 1.1 cgd printf("\tprinting is enabled\n"); 745 1.1 cgd } 746 1.1 cgd if ((dirp = opendir(SD)) == NULL) { 747 1.1 cgd printf("\tcannot examine spool directory\n"); 748 1.1 cgd return; 749 1.1 cgd } 750 1.1 cgd i = 0; 751 1.1 cgd while ((dp = readdir(dirp)) != NULL) { 752 1.1 cgd if (*dp->d_name == 'c' && dp->d_name[1] == 'f') 753 1.1 cgd i++; 754 1.1 cgd } 755 1.1 cgd closedir(dirp); 756 1.1 cgd if (i == 0) 757 1.1 cgd printf("\tno entries\n"); 758 1.1 cgd else if (i == 1) 759 1.1 cgd printf("\t1 entry in spool area\n"); 760 1.1 cgd else 761 1.1 cgd printf("\t%d entries in spool area\n", i); 762 1.1 cgd fd = open(line, O_RDONLY); 763 1.1 cgd if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) { 764 1.19 christos if (fd >= 0) 765 1.19 christos (void)close(fd); /* unlocks as well */ 766 1.7 hpeyerl printf("\tprinter idle\n"); 767 1.1 cgd return; 768 1.1 cgd } 769 1.8 mrg (void)close(fd); 770 1.8 mrg (void)snprintf(line, sizeof(line), "%s/%s", SD, ST); 771 1.1 cgd fd = open(line, O_RDONLY); 772 1.1 cgd if (fd >= 0) { 773 1.8 mrg (void)flock(fd, LOCK_SH); 774 1.12 mrg (void)fstat(fd, &stbuf); 775 1.12 mrg if (stbuf.st_size > 0) { 776 1.12 mrg putchar('\t'); 777 1.12 mrg while ((i = read(fd, line, sizeof(line))) > 0) 778 1.12 mrg (void)fwrite(line, 1, i, stdout); 779 1.12 mrg } 780 1.8 mrg (void)close(fd); /* unlocks as well */ 781 1.1 cgd } 782 1.1 cgd } 783 1.1 cgd 784 1.1 cgd /* 785 1.1 cgd * Stop the specified daemon after completing the current job and disable 786 1.1 cgd * printing. 787 1.1 cgd */ 788 1.4 cgd void 789 1.14 wiz stop(int argc, char *argv[]) 790 1.1 cgd { 791 1.18 christos int c; 792 1.12 mrg char *cp1, *cp2; 793 1.1 cgd char prbuf[100]; 794 1.1 cgd 795 1.1 cgd if (argc == 1) { 796 1.1 cgd printf("Usage: stop {all | printer ...}\n"); 797 1.1 cgd return; 798 1.1 cgd } 799 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 800 1.1 cgd printer = prbuf; 801 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 802 1.1 cgd cp1 = prbuf; 803 1.4 cgd cp2 = bp; 804 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 805 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 806 1.1 cgd *cp1++ = c; 807 1.1 cgd *cp1 = '\0'; 808 1.1 cgd stoppr(); 809 1.1 cgd } 810 1.1 cgd return; 811 1.1 cgd } 812 1.1 cgd while (--argc) { 813 1.1 cgd printer = *++argv; 814 1.18 christos if (!getcapdesc()) 815 1.1 cgd continue; 816 1.1 cgd stoppr(); 817 1.1 cgd } 818 1.1 cgd } 819 1.1 cgd 820 1.4 cgd static void 821 1.14 wiz stoppr(void) 822 1.1 cgd { 823 1.12 mrg int fd; 824 1.1 cgd struct stat stbuf; 825 1.1 cgd 826 1.18 christos getcaps(); 827 1.1 cgd printf("%s:\n", printer); 828 1.1 cgd 829 1.1 cgd /* 830 1.1 cgd * Turn on the owner execute bit of the lock file to disable printing. 831 1.1 cgd */ 832 1.5 hpeyerl seteuid(euid); 833 1.1 cgd if (stat(line, &stbuf) >= 0) { 834 1.1 cgd if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0) 835 1.1 cgd printf("\tcannot disable printing\n"); 836 1.1 cgd else { 837 1.1 cgd upstat("printing disabled\n"); 838 1.1 cgd printf("\tprinting disabled\n"); 839 1.1 cgd } 840 1.1 cgd } else if (errno == ENOENT) { 841 1.1 cgd if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0) 842 1.1 cgd printf("\tcannot create lock file\n"); 843 1.1 cgd else { 844 1.8 mrg (void)close(fd); 845 1.1 cgd upstat("printing disabled\n"); 846 1.1 cgd printf("\tprinting disabled\n"); 847 1.1 cgd } 848 1.1 cgd } else 849 1.1 cgd printf("\tcannot stat lock file\n"); 850 1.5 hpeyerl seteuid(uid); 851 1.1 cgd } 852 1.1 cgd 853 1.1 cgd struct queue **queue; 854 1.1 cgd int nitems; 855 1.1 cgd time_t mtime; 856 1.1 cgd 857 1.1 cgd /* 858 1.1 cgd * Put the specified jobs at the top of printer queue. 859 1.1 cgd */ 860 1.4 cgd void 861 1.14 wiz topq(int argc, char *argv[]) 862 1.1 cgd { 863 1.12 mrg int i; 864 1.1 cgd struct stat stbuf; 865 1.18 christos int changed; 866 1.1 cgd 867 1.1 cgd if (argc < 3) { 868 1.1 cgd printf("Usage: topq printer [jobnum ...] [user ...]\n"); 869 1.1 cgd return; 870 1.1 cgd } 871 1.1 cgd 872 1.1 cgd --argc; 873 1.1 cgd printer = *++argv; 874 1.18 christos if (!getcapdesc()) 875 1.1 cgd return; 876 1.4 cgd 877 1.18 christos getcaps(); 878 1.1 cgd printf("%s:\n", printer); 879 1.1 cgd 880 1.5 hpeyerl seteuid(euid); 881 1.1 cgd if (chdir(SD) < 0) { 882 1.1 cgd printf("\tcannot chdir to %s\n", SD); 883 1.5 hpeyerl goto out; 884 1.1 cgd } 885 1.5 hpeyerl seteuid(uid); 886 1.1 cgd nitems = getq(&queue); 887 1.1 cgd if (nitems == 0) 888 1.1 cgd return; 889 1.1 cgd changed = 0; 890 1.1 cgd mtime = queue[0]->q_time; 891 1.1 cgd for (i = argc; --i; ) { 892 1.1 cgd if (doarg(argv[i]) == 0) { 893 1.1 cgd printf("\tjob %s is not in the queue\n", argv[i]); 894 1.1 cgd continue; 895 1.1 cgd } else 896 1.1 cgd changed++; 897 1.1 cgd } 898 1.1 cgd for (i = 0; i < nitems; i++) 899 1.1 cgd free(queue[i]); 900 1.1 cgd free(queue); 901 1.1 cgd if (!changed) { 902 1.1 cgd printf("\tqueue order unchanged\n"); 903 1.1 cgd return; 904 1.1 cgd } 905 1.1 cgd /* 906 1.1 cgd * Turn on the public execute bit of the lock file to 907 1.1 cgd * get lpd to rebuild the queue after the current job. 908 1.1 cgd */ 909 1.5 hpeyerl seteuid(euid); 910 1.1 cgd if (changed && stat(LO, &stbuf) >= 0) 911 1.8 mrg (void)chmod(LO, (stbuf.st_mode & 0777) | 01); 912 1.5 hpeyerl 913 1.5 hpeyerl out: 914 1.5 hpeyerl seteuid(uid); 915 1.1 cgd } 916 1.1 cgd 917 1.1 cgd /* 918 1.1 cgd * Reposition the job by changing the modification time of 919 1.1 cgd * the control file. 920 1.1 cgd */ 921 1.4 cgd static int 922 1.14 wiz touch(struct queue *q) 923 1.1 cgd { 924 1.1 cgd struct timeval tvp[2]; 925 1.5 hpeyerl int ret; 926 1.1 cgd 927 1.1 cgd tvp[0].tv_sec = tvp[1].tv_sec = --mtime; 928 1.1 cgd tvp[0].tv_usec = tvp[1].tv_usec = 0; 929 1.5 hpeyerl seteuid(euid); 930 1.5 hpeyerl ret = utimes(q->q_name, tvp); 931 1.5 hpeyerl seteuid(uid); 932 1.5 hpeyerl return (ret); 933 1.1 cgd } 934 1.1 cgd 935 1.1 cgd /* 936 1.1 cgd * Checks if specified job name is in the printer's queue. 937 1.1 cgd * Returns: negative (-1) if argument name is not in the queue. 938 1.1 cgd */ 939 1.4 cgd static int 940 1.18 christos doarg(const char *job) 941 1.1 cgd { 942 1.12 mrg struct queue **qq; 943 1.12 mrg int jobnum, n; 944 1.18 christos char *cp; 945 1.18 christos const char *machine; 946 1.1 cgd int cnt = 0; 947 1.1 cgd FILE *fp; 948 1.1 cgd 949 1.1 cgd /* 950 1.1 cgd * Look for a job item consisting of system name, colon, number 951 1.1 cgd * (example: ucbarpa:114) 952 1.1 cgd */ 953 1.12 mrg if ((cp = strchr(job, ':')) != NULL) { 954 1.1 cgd machine = job; 955 1.1 cgd *cp++ = '\0'; 956 1.1 cgd job = cp; 957 1.1 cgd } else 958 1.1 cgd machine = NULL; 959 1.1 cgd 960 1.1 cgd /* 961 1.1 cgd * Check for job specified by number (example: 112 or 235ucbarpa). 962 1.1 cgd */ 963 1.17 dsl if (isdigit((unsigned char)*job)) { 964 1.1 cgd jobnum = 0; 965 1.1 cgd do 966 1.1 cgd jobnum = jobnum * 10 + (*job++ - '0'); 967 1.17 dsl while (isdigit((unsigned char)*job)); 968 1.1 cgd for (qq = queue + nitems; --qq >= queue; ) { 969 1.1 cgd n = 0; 970 1.17 dsl for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); ) 971 1.1 cgd n = n * 10 + (*cp++ - '0'); 972 1.1 cgd if (jobnum != n) 973 1.1 cgd continue; 974 1.1 cgd if (*job && strcmp(job, cp) != 0) 975 1.1 cgd continue; 976 1.1 cgd if (machine != NULL && strcmp(machine, cp) != 0) 977 1.1 cgd continue; 978 1.1 cgd if (touch(*qq) == 0) { 979 1.1 cgd printf("\tmoved %s\n", (*qq)->q_name); 980 1.1 cgd cnt++; 981 1.1 cgd } 982 1.1 cgd } 983 1.1 cgd return(cnt); 984 1.1 cgd } 985 1.1 cgd /* 986 1.1 cgd * Process item consisting of owner's name (example: henry). 987 1.1 cgd */ 988 1.1 cgd for (qq = queue + nitems; --qq >= queue; ) { 989 1.5 hpeyerl seteuid(euid); 990 1.5 hpeyerl fp = fopen((*qq)->q_name, "r"); 991 1.5 hpeyerl seteuid(uid); 992 1.5 hpeyerl if (fp == NULL) 993 1.1 cgd continue; 994 1.22 roy while (get_line(fp) > 0) 995 1.1 cgd if (line[0] == 'P') 996 1.1 cgd break; 997 1.8 mrg (void)fclose(fp); 998 1.1 cgd if (line[0] != 'P' || strcmp(job, line+1) != 0) 999 1.1 cgd continue; 1000 1.1 cgd if (touch(*qq) == 0) { 1001 1.1 cgd printf("\tmoved %s\n", (*qq)->q_name); 1002 1.1 cgd cnt++; 1003 1.1 cgd } 1004 1.1 cgd } 1005 1.1 cgd return(cnt); 1006 1.1 cgd } 1007 1.1 cgd 1008 1.1 cgd /* 1009 1.1 cgd * Enable everything and start printer (undo `down'). 1010 1.1 cgd */ 1011 1.4 cgd void 1012 1.14 wiz up(int argc, char *argv[]) 1013 1.1 cgd { 1014 1.18 christos int c; 1015 1.12 mrg char *cp1, *cp2; 1016 1.1 cgd char prbuf[100]; 1017 1.1 cgd 1018 1.1 cgd if (argc == 1) { 1019 1.1 cgd printf("Usage: up {all | printer ...}\n"); 1020 1.1 cgd return; 1021 1.1 cgd } 1022 1.1 cgd if (argc == 2 && !strcmp(argv[1], "all")) { 1023 1.1 cgd printer = prbuf; 1024 1.4 cgd while (cgetnext(&bp, printcapdb) > 0) { 1025 1.1 cgd cp1 = prbuf; 1026 1.4 cgd cp2 = bp; 1027 1.12 mrg while ((c = *cp2++) && c != '|' && c != ':' && 1028 1.21 lukem (size_t)(cp1 - prbuf) < sizeof(prbuf)) 1029 1.1 cgd *cp1++ = c; 1030 1.1 cgd *cp1 = '\0'; 1031 1.1 cgd startpr(2); 1032 1.1 cgd } 1033 1.1 cgd return; 1034 1.1 cgd } 1035 1.1 cgd while (--argc) { 1036 1.1 cgd printer = *++argv; 1037 1.18 christos if (!getcapdesc()) 1038 1.1 cgd continue; 1039 1.1 cgd startpr(2); 1040 1.1 cgd } 1041 1.1 cgd } 1042