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
options(argc,argv)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
oparse(optarg)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