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 (STREQU(optarg, "localhost"))) 483 484 s = Local_System; 485 else if (STREQU(optarg, Local_System)) { 486 if (cp) { 487 LP_ERRMSG (ERROR, E_ADM_NAMEONLOCAL); 488 done(1); 489 } else 490 s = Local_System; 491 } else { 492 if (cp) 493 *cp = '!'; 494 495 MALLOC(s); 496 } 497 498 /* 's' already used for stty 'R' for remote? */ 499 *modp++ = 'R'; 500 break; 501 502 case 't': /* tray number*/ 503 if (t != 0) LP_ERRMSG1 (WARNING, E_LP_2MANY, 't'); 504 t = strtol(optarg, &rest, 10); 505 if (t <= 0) { 506 LP_ERRMSG1 (ERROR, E_LP_NEGARG, 't'); 507 done (1); 508 } 509 if (rest && *rest) { 510 LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 't'); 511 done (1); 512 } 513 break; 514 515 case 'T': /* terminfo names for p */ 516 if (T) 517 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'T'); 518 if (!(T = getlist(optarg, LP_WS, LP_SEP))) { 519 LP_ERRMSG (ERROR, E_LP_MALLOC); 520 done (1); 521 } 522 *modp++ = 'T'; 523 break; 524 525 case 'u': /* user allow/deny list */ 526 if (u) 527 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'u'); 528 MALLOC(u); 529 break; 530 531 case 'U': /* dialer_info */ 532 if (U) 533 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'U'); 534 MALLOC(U); 535 *modp++ = 'U'; 536 break; 537 538 case 'v': /* device pathname */ 539 if (v) 540 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'v'); 541 MALLOC(v); 542 *modp++ = 'v'; 543 break; 544 545 case 'W': /* alert interval */ 546 if (W != -1) 547 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'W'); 548 if (STREQU(NAME_ONCE, optarg)) 549 W = 0; 550 else { 551 W = strtol(optarg, &rest, 10); 552 if (W < 0) { 553 LP_ERRMSG1 (ERROR, E_LP_NEGARG, 'W'); 554 done (1); 555 } 556 if (rest && *rest) { 557 LP_ERRMSG1 (ERROR, E_LP_GARBNMB, 'W'); 558 done (1); 559 } 560 } 561 *modp++ = 'W'; 562 break; 563 564 case 'x': /* destination to be deleted */ 565 if (x) 566 LP_ERRMSG1 (WARNING, E_LP_2MANY, 'x'); 567 MALLOC(x); 568 break; 569 570 default: 571 if (optopt == '?') { 572 usage (); 573 done (0); 574 575 } else { 576 stroptsw[1] = optsw; 577 cp = stroptsw; 578 579 if (strchr(OPT_LIST, optopt)) 580 LP_ERRMSG1 (ERROR, E_LP_OPTARG, cp); 581 else 582 LP_ERRMSG1 (ERROR, E_LP_OPTION, cp); 583 done (1); 584 } 585 } 586 } 587 588 if (optind < argc) 589 LP_ERRMSG1 (WARNING, E_LP_EXTRA, argv[optind]); 590 591 if ((v) && (!Aflag)) { 592 if (!(A = strdup("write"))) { 593 LP_ERRMSG (ERROR, E_LP_MALLOC); 594 done (1); 595 } 596 *modp++ = 'A'; 597 } 598 599 return; 600 } 601 602 /** 603 ** oparse() - PARSE -o OPTION 604 **/ 605 606 static void oparse (optarg) 607 char *optarg; 608 { 609 register char **list = dashos(optarg); 610 611 612 if (!list) 613 return; 614 615 for ( ; (optarg = *list); list++) 616 617 if (STREQU(optarg, "banner")) { 618 if (banner != -1) 619 LP_ERRMSG1 ( 620 WARNING, 621 E_ADM_2MANY, 622 "banner/nobanner" 623 ); 624 banner = BAN_ALWAYS; 625 *modp++ = 'b'; 626 627 } else if (STREQU(optarg, "nobanner")) { 628 if (banner != -1) 629 LP_ERRMSG1 ( 630 WARNING, 631 E_ADM_2MANY, 632 "banner/nobanner" 633 ); 634 banner = BAN_OPTIONAL; 635 *modp++ = 'b'; 636 637 /* handle banner=(always|optional|never) */ 638 } else if (STRNEQU(optarg, "banner=", 7)) { 639 char *ptr; 640 641 ptr = (optarg += 7); 642 if (banner != -1) 643 LP_ERRMSG1 ( WARNING, E_ADM_2MANY, 644 "banner/nobanner/banner=(always|optional|never)" 645 ); 646 647 /* like "banner", always print a banner */ 648 if (strcasecmp(ptr, "always") == 0) 649 banner = BAN_ALWAYS; 650 /* like "nobanner", print a banner unless requested */ 651 if (strcasecmp(ptr, "optional") == 0) 652 banner = BAN_OPTIONAL; 653 /* never print a banner */ 654 if (strcasecmp(ptr, "never") == 0) 655 banner = BAN_NEVER; 656 *modp++ = 'b'; 657 658 } else if (STRNEQU(optarg, "length=", 7)) { 659 if (length) 660 LP_ERRMSG1 ( 661 WARNING, 662 E_ADM_2MANY, 663 "length=" 664 ); 665 length = (optarg += 7); 666 667 if (!*optarg) { 668 length_sdn.val = 0; 669 length_sdn.sc = 0; 670 671 } else { 672 length_sdn = _getsdn(optarg, &optarg, 0); 673 if (errno == EINVAL) { 674 LP_ERRMSG (ERROR, E_LP_BADSCALE); 675 done (1); 676 } 677 } 678 *modp++ = 'L'; 679 680 } else if (STRNEQU(optarg, "width=", 6)) { 681 if (width) 682 LP_ERRMSG1 ( 683 WARNING, 684 E_ADM_2MANY, 685 "width=" 686 ); 687 width = (optarg += 6); 688 689 if (!*optarg) { 690 width_sdn.val = 0; 691 width_sdn.sc = 0; 692 693 } else { 694 width_sdn = _getsdn(optarg, &optarg, 0); 695 if (errno == EINVAL) { 696 LP_ERRMSG (ERROR, E_LP_BADSCALE); 697 done (1); 698 } 699 } 700 *modp++ = 'w'; 701 702 } else if (STRNEQU(optarg, "cpi=", 4)) { 703 if (cpi) 704 LP_ERRMSG1 (WARNING, E_ADM_2MANY, "cpi="); 705 706 cpi = (optarg += 4); 707 708 if (!*optarg) { 709 cpi_sdn.val = 0; 710 cpi_sdn.sc = 0; 711 712 } else { 713 cpi_sdn = _getsdn(optarg, &optarg, 1); 714 if (errno == EINVAL) { 715 LP_ERRMSG (ERROR, E_LP_BADSCALE); 716 done (1); 717 } 718 } 719 *modp++ = 'c'; 720 721 } else if (STRNEQU(optarg, "lpi=", 4)) { 722 if (lpi) 723 LP_ERRMSG1 (WARNING, E_ADM_2MANY, "lpi="); 724 lpi = (optarg += 4); 725 726 if (!*optarg) { 727 lpi_sdn.val = 0; 728 lpi_sdn.sc = 0; 729 730 } else { 731 lpi_sdn = _getsdn(optarg, &optarg, 0); 732 if (errno == EINVAL) { 733 LP_ERRMSG (ERROR, E_LP_BADSCALE); 734 done (1); 735 } 736 } 737 *modp++ = 'M'; 738 739 } else if (STRNEQU(optarg, "stty=", 5)) { 740 741 optarg += 5; 742 if (!*optarg) 743 stty_opt = 0; 744 745 else { 746 if (strchr(LP_QUOTES, *optarg)) { 747 register int len 748 = strlen(optarg); 749 750 if (optarg[len - 1] == *optarg) 751 optarg[len - 1] = 0; 752 optarg++; 753 } 754 if (stty_opt) 755 REALLOC (stty_opt); 756 else 757 MALLOC (stty_opt); 758 } 759 *modp++ = 's'; 760 761 } else if (STREQU(optarg, "filebreak")) { 762 filebreak = 1; 763 764 } else if (STREQU(optarg, "nofilebreak")) { 765 filebreak = 0; 766 767 /* added support for using -o to pass any key=value pair */ 768 } else if (*optarg) { 769 770 if ((addlist(&o_options, optarg)) != 0) { 771 fprintf(stderr, gettext("System Error %d\n"), errno); 772 } 773 774 *modp++ = 'o'; 775 optarg++; 776 } 777 778 return; 779 } 780