Home | History | Annotate | Download | only in lpadmin
      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