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