1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 #include "ctype.h" 31 #include "stdio.h" 32 #include "string.h" 33 #include "stdlib.h" 34 #include <libintl.h> 35 36 #include "lp.h" 37 #include "printers.h" 38 39 #define WHO_AM_I I_AM_LPADMIN 40 #include "oam.h" 41 42 #include "lpadmin.h" 43 44 #ifdef LP_USE_PAPI_ATTR 45 #if defined(CAN_DO_MODULES) 46 #define OPT_LIST "A:ac:d:D:e:f:F:H:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:" 47 #else 48 #define OPT_LIST "A:ac:d:D:e:f:F:hi:I:lm:Mn:o:p:Q:r:S:s:T:u:U:v:W:x:t:P:" 49 #endif 50 51 #else 52 #if defined(CAN_DO_MODULES) 53 #define OPT_LIST "A:ac:d:D:e:f:F:H:hi:I:lm:Mo:p:Q:r:S:s:T:u:U:v:W:x:t:P:" 54 #else 55 #define OPT_LIST "A:ac:d:D:e:f:F:hi:I:lm:Mo:p:Q:r:S:s:T:u:U:v:W:x:t:P:" 56 #endif 57 #endif 58 59 #define MALLOC(pointer) \ 60 if (!(pointer = strdup(optarg))) { \ 61 LP_ERRMSG (ERROR, E_LP_MALLOC); \ 62 done (1); \ 63 } else 64 65 #define REALLOC(pointer) \ 66 if (!(pointer = realloc(pointer, (unsigned) (strlen(pointer) + 1 + strlen(optarg) + 1)))) { \ 67 LP_ERRMSG (ERROR, E_LP_MALLOC); \ 68 done (1); \ 69 } else if (strcat(pointer, " ")) \ 70 (void)strcat (pointer, optarg); \ 71 else 72 73 extern char *optarg; 74 75 extern int optind, 76 opterr, 77 optopt; 78 79 extern double strtod(); 80 81 extern long strtol(); 82 83 int a = 0, /* alignment needed for mount */ 84 banner = -1, /* allow/don't-allow nobanner */ 85 #if defined(DIRECT_ACCESS) 86 C = 0, /* direct a.o.t. normal access */ 87 #endif 88 filebreak = 0, 89 h = 0, /* hardwired terminal */ 90 j = 0, /* do -F just for current job */ 91 l = 0, /* login terminal */ 92 M = 0, /* do mount */ 93 t = 0, /* tray number*/ 94 o = 0, /* some -o options given */ 95 Q = -1, /* queue threshold for alert */ 96 W = -1; /* alert interval */ 97 98 char *A = 0, /* alert type */ 99 *c = 0, /* class name */ 100 *cpi = 0, /* string value of -o cpi= */ 101 *d = 0, /* default destination */ 102 *D = 0, /* description */ 103 *e = 0, /* copy existing interface */ 104 *f = 0, /* forms list - allow/deny */ 105 *P = 0, /* paper list */ 106 *F = 0, /* fault recovery */ 107 **H = 0, /* list of modules to push */ 108 *i = 0, /* interface pathname */ 109 **I = 0, /* content-type-list */ 110 *length = 0, /* string value of -o length= */ 111 *lpi = 0, /* string value of -o lpi= */ 112 *m = 0, /* model name */ 113 modifications[128], /* list of mods to make */ 114 #ifdef LP_USE_PAPI_ATTR 115 *n_opt = NULL, /* PPD file name */ 116 #endif 117 *p = 0, /* printer name */ 118 *r = 0, /* class to remove printer from */ 119 *s = 0, /* system printer is on */ 120 *stty_opt= 0, /* string value of -o stty= */ 121 **o_options = 0,/* undefined lpadmin -o options */ 122 **S = 0, /* -set/print-wheel list */ 123 **T = 0, /* terminfo names */ 124 *u = 0, /* user allow/deny list */ 125 *U = 0, /* dialer_info */ 126 *v = 0, /* device pathname */ 127 *width = 0, /* string value of -o width= */ 128 *x = 0; /* destination to be deleted */ 129 130 SCALED cpi_sdn = { 0, 0 }, 131 length_sdn = { 0, 0 }, 132 lpi_sdn = { 0, 0 }, 133 width_sdn = { 0, 0 }; 134 135 static char *modp = modifications; 136 137 static void oparse(); 138 139 static char * empty_list[] = { 0 }; 140 141 /** 142 ** options() - PARSE COMMAND LINE ARGUMENTS INTO OPTIONS 143 **/ 144 145 void options (argc, argv) 146 int argc; 147 char *argv[]; 148 { 149 int optsw, 150 ac, 151 Aflag = 0; 152 153 char *cp, 154 *rest, 155 **av; 156 char stroptsw[] = "-X"; 157 158 #if defined(__STDC__) 159 typedef char * const * stupid; /* dumb-ass ANSI C */ 160 #else 161 typedef char ** stupid; 162 #endif 163 164 165 /* 166 * Add a fake value to the end of the "argv" list, to 167 * catch the case that a valued-option comes last. 168 */ 169 av = malloc((argc + 2) * sizeof(char *)); 170 for (ac = 0; ac < argc; ac++) 171 av[ac] = argv[ac]; 172 av[ac++] = "--"; 173 174 opterr = 0; 175 while ((optsw = getopt(ac, (stupid)av, OPT_LIST)) != EOF) { 176 177 switch (optsw) { 178 179 /* 180 * These options MAY take a value. Check the value; 181 * if it begins with a '-', assume it's really the next 182 * option. 183 */ 184 case 'd': 185 case 'p': /* MR bl87-27863 */ 186 case 'I': 187 #if defined(CAN_DO_MODULES) 188 case 'H': 189 #endif 190 if (*optarg == '-') { 191 /* 192 * This will work if we were given 193 * 194 * -x -foo 195 * 196 * but would fail if we were given 197 * 198 * -x-foo 199 */ 200 optind--; 201 switch (optsw) { 202 case 'd': 203 #if defined(CAN_DO_MODULES) 204 case 'H': 205 #endif 206 optarg = NAME_NONE; 207 break; 208 case 'p': 209 optarg = NAME_ALL; 210 break; 211 case 'I': 212 optarg = 0; 213 break; 214 } 215 } 216 break; 217 218 /* 219 * These options MUST have a value. Check the value; 220 * if it begins with a dash or is null, complain. 221 */ 222 case 'Q': 223 case 'W': 224 case 't': 225 /* 226 * These options take numeric values, which might 227 * be negative. Negative values are handled later, 228 * but here we just screen them. 229 */ 230 (void)strtol(optarg, &rest, 10); 231 if (!rest || !*rest) 232 break; 233 /*FALLTHROUGH*/ 234 case 'A': 235 case 'c': 236 case 'e': 237 case 'f': 238 case 'P': 239 case 'F': 240 case 'i': 241 case 'm': 242 #ifdef LP_USE_PAPI_ATTR 243 case 'n': 244 #endif 245 case 'o': 246 /* case 'p': */ /* MR bl87-27863 */ 247 case 'r': 248 case 'S': 249 case 's': 250 case 'T': 251 case 'u': 252 case 'U': 253 case 'v': 254 case 'x': 255 /* 256 * These options also must have non-null args. 257 */ 258 if (!*optarg) { 259 stroptsw[1] = optsw; 260 LP_ERRMSG1 (ERROR, E_LP_NULLARG, stroptsw); 261 done (1); 262 } 263 if (*optarg == '-') { 264 stroptsw[1] = optsw; 265 LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw); 266 done (1); 267 } 268 if (optsw == 'A') 269 Aflag++; 270 break; 271 case 'D': 272 /* 273 * These options can have a null arg. 274 */ 275 if (*optarg == '-') { 276 stroptsw[1] = optsw; 277 LP_ERRMSG1 (ERROR, E_LP_OPTARG, stroptsw); 278 done (1); 279 } 280 break; 281 } 282 283 switch (optsw) { 284 285 case 'a': /* alignment pattern needed for mount */ 286 a = 1; 287 break; 288 289 case 'A': /* alert type */ 290 if (A) 291 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'A'); 292 MALLOC(A); 293 Aflag++; 294 if (!STREQU(A, NAME_QUIET) && !STREQU(A, NAME_LIST)) 295 *modp++ = 'A'; 296 break; 297 298 case 'c': /* class to insert printer p */ 299 if (c) 300 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'c'); 301 MALLOC(c); 302 break; 303 304 #if defined(DIRECT_ACCESS) 305 case 'C': 306 C = 1; 307 break; 308 #endif 309 310 case 'd': /* system default destination */ 311 if (d) 312 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'd'); 313 MALLOC(d); 314 break; 315 316 case 'D': /* description */ 317 if (D) 318 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'D'); 319 MALLOC(D); 320 *modp++ = 'D'; 321 break; 322 323 case 'e': /* existing printer interface */ 324 if (e) 325 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'e'); 326 MALLOC(e); 327 *modp++ = 'e'; 328 break; 329 330 case 'f': /* set up forms allow/deny */ 331 if (f) 332 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'f'); 333 MALLOC(f); 334 break; 335 336 case 'P': /* set up forms allow/deny */ 337 if (P) 338 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'P'); 339 MALLOC(P); 340 break; 341 342 case 'F': /* fault recovery */ 343 if (F) 344 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'F'); 345 MALLOC(F); 346 *modp++ = 'F'; 347 break; 348 349 #if defined(CAN_DO_MODULES) 350 case 'H': 351 if (H) 352 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'H'); 353 if (!optarg || !*optarg || STREQU(NAME_NONE, optarg)) 354 H = empty_list; 355 if (!(H = getlist(optarg, LP_WS, LP_SEP))) { 356 LP_ERRMSG (ERROR, E_LP_MALLOC); 357 done(1); 358 } 359 *modp++ = 'H'; 360 break; 361 #endif 362 363 case 'h': /* hardwired terminal */ 364 h = 1; 365 *modp++ = 'h'; 366 break; 367 368 case 'i': /* interface pathname */ 369 if (i) 370 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'i'); 371 MALLOC(i); 372 *modp++ = 'i'; 373 break; 374 375 case 'I': /* content-type-list */ 376 if (I) 377 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'I'); 378 if (!optarg || !*optarg || STREQU(NAME_NONE, optarg)) 379 I = empty_list; 380 else if (!(I = getlist(optarg, LP_WS, LP_SEP))) { 381 LP_ERRMSG (ERROR, E_LP_MALLOC); 382 done (1); 383 } 384 *modp++ = 'I'; 385 break; 386 387 #if defined(J_OPTION) 388 case 'j': /* fault recovery just for current job */ 389 j = 1; 390 (void) printf (gettext("Sorry, the -j option is currently broken\n")); 391 break; 392 #endif 393 394 case 'l': /* login terminal */ 395 l = 1; 396 *modp++ = 'l'; 397 break; 398 399 case 'm': /* model interface */ 400 if (m) 401 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'm'); 402 MALLOC(m); 403 *modp++ = 'm'; 404 break; 405 406 #ifdef LP_USE_PAPI_ATTR 407 case 'n': /* PPD file */ 408 if (n_opt) 409 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'n'); 410 MALLOC(n_opt); 411 *modp++ = 'n'; 412 break; 413 #endif 414 415 case 'M': /* a mount request */ 416 M = 1; 417 break; 418 419 case 'o': /* several different options */ 420 oparse (optarg); 421 o = 1; 422 break; 423 424 case 'p': /* printer name */ 425 if (p) 426 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'p'); 427 MALLOC(p); 428 break; 429 430 case 'Q': 431 if (Q != -1) 432 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'Q'); 433 if (STREQU(NAME_ANY, optarg)) 434 Q = 1; 435 else { 436 Q = strtol(optarg, &rest, 10); 437 if (Q < 0) { 438 LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'Q'); 439 done (1); 440 } 441 if (rest && *rest) { 442 LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'Q'); 443 done (1); 444 } 445 if (Q == 0) { 446 LP_ERRMSG1 (ERROR, E_ADM_ZEROARG, 'Q'); 447 done (1); 448 } 449 } 450 *modp++ = 'Q'; 451 break; 452 453 case 'r': /* class to remove p from */ 454 if (r) 455 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'r'); 456 MALLOC(r); 457 break; 458 459 case 'S': /* char_set/print-wheels */ 460 if (S) 461 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'S'); 462 if (!(S = getlist(optarg, LP_WS, LP_SEP))) { 463 LP_ERRMSG (ERROR, E_LP_MALLOC); 464 done (1); 465 } 466 *modp++ = 'S'; 467 break; 468 469 case 's': 470 if (s) 471 LP_ERRMSG1 (WARNING, E_LP_2MANY, 's'); 472 473 if ((cp = strchr(optarg, '!'))) 474 *cp = '\0'; 475 476 if ((STREQU(optarg, NAME_NONE)) || 477 (STREQU(optarg, "localhost"))) 478 479 s = Local_System; 480 else if (STREQU(optarg, Local_System)) { 481 if (cp) { 482 LP_ERRMSG (ERROR, E_ADM_NAMEONLOCAL); 483 done(1); 484 } else 485 s = Local_System; 486 } else { 487 if (cp) 488 *cp = '!'; 489 490 MALLOC(s); 491 } 492 493 /* 's' already used for stty 'R' for remote? */ 494 *modp++ = 'R'; 495 break; 496 497 case 't': /* tray number*/ 498 if (t != 0) LP_ERRMSG1 (WARNING, E_LP_2MANY, 't'); 499 t = strtol(optarg, &rest, 10); 500 if (t <= 0) { 501 LP_ERRMSG1 (ERROR, E_LP_NEGARG, 't'); 502 done (1); 503 } 504 if (rest && *rest) { 505 LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 't'); 506 done (1); 507 } 508 break; 509 510 case 'T': /* terminfo names for p */ 511 if (T) 512 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'T'); 513 if (!(T = getlist(optarg, LP_WS, LP_SEP))) { 514 LP_ERRMSG (ERROR, E_LP_MALLOC); 515 done (1); 516 } 517 *modp++ = 'T'; 518 break; 519 520 case 'u': /* user allow/deny list */ 521 if (u) 522 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'u'); 523 MALLOC(u); 524 break; 525 526 case 'U': /* dialer_info */ 527 if (U) 528 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'U'); 529 MALLOC(U); 530 *modp++ = 'U'; 531 break; 532 533 case 'v': /* device pathname */ 534 if (v) 535 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'v'); 536 MALLOC(v); 537 *modp++ = 'v'; 538 break; 539 540 case 'W': /* alert interval */ 541 if (W != -1) 542 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'W'); 543 if (STREQU(NAME_ONCE, optarg)) 544 W = 0; 545 else { 546 W = strtol(optarg, &rest, 10); 547 if (W < 0) { 548 LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'W'); 549 done (1); 550 } 551 if (rest && *rest) { 552 LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'W'); 553 done (1); 554 } 555 } 556 *modp++ = 'W'; 557 break; 558 559 case 'x': /* destination to be deleted */ 560 if (x) 561 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'x'); 562 MALLOC(x); 563 break; 564 565 default: 566 if (optopt == '?') { 567 usage (); 568 done (0); 569 570 } else { 571 stroptsw[1] = optsw; 572 573 if (strchr(OPT_LIST, optopt)) 574 LP_ERRMSG1 (ERROR, E_LP_OPTARG, 575 stroptsw); 576 else 577 LP_ERRMSG1 (ERROR, E_LP_OPTION, 578 stroptsw); 579 done (1); 580 } 581 } 582 } 583 584 if (optind < argc) 585 LP_ERRMSG1 (WARNING, E_LP_EXTRA, argv[optind]); 586 587 if ((v) && (!Aflag)) { 588 if (!(A = strdup("write"))) { 589 LP_ERRMSG (ERROR, E_LP_MALLOC); 590 done (1); 591 } 592 *modp++ = 'A'; 593 } 594 595 return; 596 } 597 598 /** 599 ** oparse() - PARSE -o OPTION 600 **/ 601 602 static void oparse (optarg) 603 char *optarg; 604 { 605 register char **list = dashos(optarg); 606 607 608 if (!list) 609 return; 610 611 for ( ; (optarg = *list); list++) 612 613 if (STREQU(optarg, "banner")) { 614 if (banner != -1) 615 LP_ERRMSG1 ( 616 WARNING, 617 E_ADM_2MANY, 618 "banner/nobanner" 619 ); 620 banner = BAN_ALWAYS; 621 *modp++ = 'b'; 622 623 } else if (STREQU(optarg, "nobanner")) { 624 if (banner != -1) 625 LP_ERRMSG1 ( 626 WARNING, 627 E_ADM_2MANY, 628 "banner/nobanner" 629 ); 630 banner = BAN_OPTIONAL; 631 *modp++ = 'b'; 632 633 /* handle banner=(always|optional|never) */ 634 } else if (STRNEQU(optarg, "banner=", 7)) { 635 char *ptr; 636 637 ptr = (optarg += 7); 638 if (banner != -1) 639 LP_ERRMSG1 ( WARNING, E_ADM_2MANY, 640 "banner/nobanner/banner=(always|optional|never)" 641 ); 642 643 /* like "banner", always print a banner */ 644 if (strcasecmp(ptr, "always") == 0) 645 banner = BAN_ALWAYS; 646 /* like "nobanner", print a banner unless requested */ 647 if (strcasecmp(ptr, "optional") == 0) 648 banner = BAN_OPTIONAL; 649 /* never print a banner */ 650 if (strcasecmp(ptr, "never") == 0) 651 banner = BAN_NEVER; 652 *modp++ = 'b'; 653 654 } else if (STRNEQU(optarg, "length=", 7)) { 655 if (length) 656 LP_ERRMSG1 ( 657 WARNING, 658 E_ADM_2MANY, 659 "length=" 660 ); 661 length = (optarg += 7); 662 663 if (!*optarg) { 664 length_sdn.val = 0; 665 length_sdn.sc = 0; 666 667 } else { 668 length_sdn = _getsdn(optarg, &optarg, 0); 669 if (errno == EINVAL) { 670 LP_ERRMSG (ERROR, E_LP_BADSCALE); 671 done (1); 672 } 673 } 674 *modp++ = 'L'; 675 676 } else if (STRNEQU(optarg, "width=", 6)) { 677 if (width) 678 LP_ERRMSG1 ( 679 WARNING, 680 E_ADM_2MANY, 681 "width=" 682 ); 683 width = (optarg += 6); 684 685 if (!*optarg) { 686 width_sdn.val = 0; 687 width_sdn.sc = 0; 688 689 } else { 690 width_sdn = _getsdn(optarg, &optarg, 0); 691 if (errno == EINVAL) { 692 LP_ERRMSG (ERROR, E_LP_BADSCALE); 693 done (1); 694 } 695 } 696 *modp++ = 'w'; 697 698 } else if (STRNEQU(optarg, "cpi=", 4)) { 699 if (cpi) 700 LP_ERRMSG1 (WARNING, E_ADM_2MANY, "cpi="); 701 702 cpi = (optarg += 4); 703 704 if (!*optarg) { 705 cpi_sdn.val = 0; 706 cpi_sdn.sc = 0; 707 708 } else { 709 cpi_sdn = _getsdn(optarg, &optarg, 1); 710 if (errno == EINVAL) { 711 LP_ERRMSG (ERROR, E_LP_BADSCALE); 712 done (1); 713 } 714 } 715 *modp++ = 'c'; 716 717 } else if (STRNEQU(optarg, "lpi=", 4)) { 718 if (lpi) 719 LP_ERRMSG1 (WARNING, E_ADM_2MANY, "lpi="); 720 lpi = (optarg += 4); 721 722 if (!*optarg) { 723 lpi_sdn.val = 0; 724 lpi_sdn.sc = 0; 725 726 } else { 727 lpi_sdn = _getsdn(optarg, &optarg, 0); 728 if (errno == EINVAL) { 729 LP_ERRMSG (ERROR, E_LP_BADSCALE); 730 done (1); 731 } 732 } 733 *modp++ = 'M'; 734 735 } else if (STRNEQU(optarg, "stty=", 5)) { 736 737 optarg += 5; 738 if (!*optarg) 739 stty_opt = 0; 740 741 else { 742 if (strchr(LP_QUOTES, *optarg)) { 743 register int len 744 = strlen(optarg); 745 746 if (optarg[len - 1] == *optarg) 747 optarg[len - 1] = 0; 748 optarg++; 749 } 750 if (stty_opt) 751 REALLOC (stty_opt); 752 else 753 MALLOC (stty_opt); 754 } 755 *modp++ = 's'; 756 757 } else if (STREQU(optarg, "filebreak")) { 758 filebreak = 1; 759 760 } else if (STREQU(optarg, "nofilebreak")) { 761 filebreak = 0; 762 763 /* added support for using -o to pass any key=value pair */ 764 } else if (*optarg) { 765 766 if ((addlist(&o_options, optarg)) != 0) { 767 fprintf(stderr, gettext("System Error %d\n"), errno); 768 } 769 770 *modp++ = 'o'; 771 optarg++; 772 } 773 774 return; 775 } 776