xref: /illumos-gate/usr/src/cmd/lp/cmd/lpadmin/do_printer.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 
26 /*
27  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include <stdio.h>
34 #include <string.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <sys/types.h>
38 #include <stdlib.h>
39 #include <libintl.h>
40 
41 #include "lp.h"
42 #include "class.h"
43 #include "printers.h"
44 #include "msgs.h"
45 
46 #define	WHO_AM_I	I_AM_LPADMIN
47 #include	"oam.h"
48 
49 #include "lpadmin.h"
50 
51 extern	void	fromallclasses();
52 
53 #if     !defined(PATH_MAX)
54 # define PATH_MAX       1024
55 #endif
56 #if     PATH_MAX < 1024
57 # undef PATH_MAX
58 # define PATH_MAX       1024
59 #endif
60 
61 extern char		*label;
62 static void		configure_printer();
63 static char		*fullpath();
64 char			*nameit();
65 
66 /**
67  ** do_printer() - CREATE OR CHANGE PRINTER
68  **/
69 
70 void			do_printer ()
71 {
72 	int			rc;
73 
74 	/*
75 	 * Set or change the printer configuration.
76 	 */
77 	if (strlen(modifications))
78 		configure_printer (modifications);
79 
80 	/*
81 	 * Allow/deny forms.
82 	 */
83 	BEGIN_CRITICAL
84 		if (!oldp)
85 			if (allow_form_printer(getlist(NAME_NONE, "", ","), p) == -1) {
86 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
87 				done(1);
88 			}
89 
90 		if (f_allow || f_deny) {
91 			if (f_allow && allow_form_printer(f_allow, p) == -1) {
92 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
93 				done(1);
94 			}
95 
96 			if (f_deny && deny_form_printer(f_deny, p) == -1) {
97 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
98 				done(1);
99 			}
100 		}
101 	END_CRITICAL
102 
103 	/* Add/remove types of paper */
104 
105 	BEGIN_CRITICAL
106 		if (!oldp)
107 			if (add_paper_to_printer(getlist(NAME_NONE, "", ","),p) == -1) {
108 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
109 				done(1);
110 			}
111 
112 
113 			if (p_add && add_paper_to_printer(p_add, p) == -1) {
114 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
115 				done(1);
116 			}
117 
118 			if (p_remove && remove_paper_from_printer(p_remove, p) == -1) {
119 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
120 				done(1);
121 			}
122 	END_CRITICAL
123 
124 	/*
125 	 * Allow/deny users.
126 	 */
127 	BEGIN_CRITICAL
128 		if (!oldp)
129 			if (allow_user_printer(getlist(NAME_ALL, "", ","), p) == -1) {
130 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
131 				done(1);
132 			}
133 
134 		if (u_allow || u_deny) {
135 			if (u_allow && allow_user_printer(u_allow, p) == -1) {
136 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
137 				done(1);
138 			}
139 
140 			if (u_deny && deny_user_printer(u_deny, p) == -1) {
141 				LP_ERRMSG1 (ERROR, E_ADM_ACCESSINFO, PERROR);
142 				done(1);
143 			}
144 		}
145 	END_CRITICAL
146 
147 	/*
148 	 * Tell the Spooler about the printer
149 	 */
150 	send_message(S_LOAD_PRINTER, p, "", "");
151 	rc = output(R_LOAD_PRINTER);
152 
153 	switch (rc) {
154 	case MOK:
155 		break;
156 
157 	case MNODEST:
158 	case MERRDEST:
159 		LP_ERRMSG (ERROR, E_ADM_ERRDEST);
160 		done (1);
161 		/*NOTREACHED*/
162 
163 	case MNOSPACE:
164 		LP_ERRMSG (WARNING, E_ADM_NOPSPACE);
165 		break;
166 
167 	case MNOPERM:	/* taken care of up front */
168 	default:
169 		LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
170 		done (1);
171 		/*NOTREACHED*/
172 	}
173 
174 	/*
175 	 * Now that the Spooler knows about the printer,
176 	 * we can do the balance of the changes.
177 	 */
178 
179 	/*
180 	 * Mount or unmount form, print-wheel.
181 	 */
182 	if (M)
183 		do_mount(p, (f? f : (char *)0), (S? *S : (char *)0));
184 	else if (t) do_max_trays(p);
185 
186 	/*
187 	 * Display the alert type.
188 	 */
189 	if (A && STREQU(A, NAME_LIST)) {
190 		if (label)
191 			(void) printf(gettext("Printer %s: "), label);
192 		printalert (stdout, &(oldp->fault_alert), 1);
193 	}
194 
195 	/*
196 	 * -A quiet.
197 	 */
198 	if (A && STREQU(A, NAME_QUIET)) {
199 
200 		send_message(S_QUIET_ALERT, p, (char *)QA_PRINTER, "");
201 		rc = output(R_QUIET_ALERT);
202 
203 		switch(rc) {
204 		case MOK:
205 			break;
206 
207 		case MNODEST:	/* not quite, but not a lie either */
208 		case MERRDEST:
209 			LP_ERRMSG1 (WARNING, E_LP_NOQUIET, p);
210 			break;
211 
212 		case MNOPERM:	/* taken care of up front */
213 		default:
214 			LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
215 			done (1);
216 			/*NOTREACHED*/
217 		}
218 	}
219 
220 	/*
221 	 * Add printer p to class c
222 	 */
223 	if (c)  {
224 		CLASS			*pc,
225 					clsbuf;
226 
227 		if (STREQU(c, NAME_ANY))
228 			c = NAME_ALL;
229 
230 Loop:		if (!(pc = getclass(c))) {
231 			if (STREQU(c, NAME_ALL))
232 				goto Done;
233 
234 			if (errno != ENOENT) {
235 				LP_ERRMSG2 (
236 					ERROR,
237 					E_LP_GETCLASS,
238 					c,
239 					PERROR
240 				);
241 				done (1);
242 			}
243 
244 			/*
245 			 * Create the class
246 			 */
247 			clsbuf.name = strdup(c);
248 			clsbuf.members = 0;
249 			if (addlist(&clsbuf.members, p) == -1) {
250 				LP_ERRMSG (ERROR, E_LP_MALLOC);
251 				done (1);
252 			}
253 			pc = &clsbuf;
254 
255 		} else if (searchlist(p, pc->members))
256 			LP_ERRMSG2 (WARNING, E_ADM_INCLASS, p, pc->name);
257 
258 		else if (addlist(&pc->members, p) == -1) {
259 			LP_ERRMSG (ERROR, E_LP_MALLOC);
260 			done (1);
261 		}
262 
263 		BEGIN_CRITICAL
264 			if (putclass(pc->name, pc) == -1) {
265 				LP_ERRMSG2 (
266 					ERROR,
267 					E_LP_PUTCLASS,
268 					pc->name,
269 					PERROR
270 				);
271 				done(1);
272 			}
273 		END_CRITICAL
274 
275 		send_message (S_LOAD_CLASS, pc->name);
276 		rc = output(R_LOAD_CLASS);
277 
278 		switch(rc) {
279 		case MOK:
280 			break;
281 
282 		case MNODEST:
283 		case MERRDEST:
284 			LP_ERRMSG (ERROR, E_ADM_ERRDEST);
285 			done (1);
286 			/*NOTREACHED*/
287 
288 		case MNOSPACE:
289 			LP_ERRMSG (WARNING, E_ADM_NOCSPACE);
290 			break;
291 
292 		case MNOPERM:	/* taken care of up front */
293 		default:
294 			LP_ERRMSG1 (ERROR, E_LP_BADSTATUS, rc);
295 			done (1);
296 			/*NOTREACHED*/
297 		}
298 
299 		if (STREQU(c, NAME_ALL))
300 			goto Loop;
301 	}
302 Done:
303 	/*
304 	 * Remove printer p from class r
305 	 */
306 	if (r) {
307 		if (STREQU(r, NAME_ALL) || STREQU(r, NAME_ANY))
308 			fromallclasses(p);
309 		else
310 			fromclass(p, r);
311 	}
312 
313 	return;
314 }
315 
316 /**
317  ** configure_printer() - SET OR CHANGE CONFIGURATION OF PRINTER
318  **/
319 
320 static void		configure_printer (list)
321 	char			*list;
322 {
323 	register PRINTER	*prbufp;
324 
325 	PRINTER			printer_struct;
326 
327 	char			type;
328 	char *	infile_opts = NULL;
329 
330 
331 	if (oldp) {
332 
333 		prbufp = oldp;
334 
335 		if (!T)
336 			T = prbufp->printer_types;
337 
338 		if (!i && !e && !m)
339 			/*
340 			 * Don't copy the original interface program
341 			 * again, but do keep the name of the original.
342 			 */
343 			ignprinter = BAD_INTERFACE;
344 		else
345 			ignprinter = 0;
346 
347 		/*
348 		 * If we are making this a remote printer,
349 		 * make sure that local-only attributes are
350 		 * cleared.
351 		 */
352 		if (s) {
353 			prbufp->banner = 0;
354 			prbufp->cpi.val = 0;
355 			prbufp->cpi.sc = 0;
356 			prbufp->device = 0;
357 			prbufp->dial_info = 0;
358 			prbufp->fault_rec = 0;
359 			prbufp->interface = 0;
360 			prbufp->lpi.val = 0;
361 			prbufp->lpi.sc = 0;
362 			prbufp->plen.val = 0;
363 			prbufp->plen.sc = 0;
364 			prbufp->login = 0;
365 			prbufp->speed = 0;
366 			prbufp->stty = 0;
367 			prbufp->pwid.val = 0;
368 			prbufp->pwid.sc = 0;
369 			prbufp->fault_alert.shcmd = strdup(NAME_NONE);
370 			prbufp->fault_alert.Q = 0;
371 			prbufp->fault_alert.W = 0;
372 #if	defined(CAN_DO_MODULES)
373 			prbufp->modules = 0;
374 #endif
375 
376 		/*
377 		 * If we are making this a local printer, make
378 		 * sure that some local-only attributes are set.
379 		 * (If the user has specified these as well, his/her
380 		 * values will overwrite what we set here.)
381 		 */
382 		} else if (oldp->remote) {
383 			prbufp->banner = BAN_ALWAYS;
384 			prbufp->interface = makepath(Lp_Model, STANDARD, (char *)0);
385 			prbufp->fault_alert.shcmd = nameit(NAME_MAIL);
386 
387 			/*
388 			 * Being here means "!s && oldp->remote" is true,
389 			 * i.e. this printer never had an interface pgm
390 			 * before. Thus we can safely clear the following.
391 			 * This is needed to let "putprinter()" copy the
392 			 * (default) interface program.
393 			 */
394 			ignprinter = 0;
395 		}
396 
397 	} else {
398 		/*
399 		 * The following takes care of the lion's share
400 		 * of the initialization of a new printer structure.
401 		 * However, special initialization (e.g. non-zero,
402 		 * or substructure members) needs to be considered
403 		 * for EACH NEW MEMBER added to the structure.
404 		 */
405 		(void)memset (&printer_struct, 0, sizeof(printer_struct));
406 
407 		prbufp = &printer_struct;
408 		prbufp->banner = BAN_ALWAYS;
409 		prbufp->cpi.val = 0;
410 		prbufp->cpi.sc = 0;
411 		if (!s)
412 			prbufp->interface = makepath(Lp_Model, m, (char *)0);
413 		prbufp->lpi.val = 0;
414 		prbufp->lpi.sc = 0;
415 		prbufp->plen.val = 0;
416 		prbufp->plen.sc = 0;
417 		prbufp->pwid.val = 0;
418 		prbufp->pwid.sc = 0;
419 		if (!s && !A)
420 			prbufp->fault_alert.shcmd = nameit(NAME_MAIL);
421 		prbufp->fault_alert.Q = 0;
422 		prbufp->fault_alert.W = 0;
423 		prbufp->options = NULL;
424 	}
425 
426 	while ((type = *list++) != '\0')  switch(type) {
427 
428 	case 'A':
429 		if (!s) {
430 			if (STREQU(A, NAME_MAIL) || STREQU(A, NAME_WRITE))
431 				prbufp->fault_alert.shcmd = nameit(A);
432 			else if (!STREQU(A, NAME_QUIET))
433 				prbufp->fault_alert.shcmd = A;
434 		}
435 		break;
436 
437 	case 'b':
438 		if (!s)
439 			prbufp->banner = banner;
440 		break;
441 
442 	case 'c':
443 		if (!s)
444 			prbufp->cpi = cpi_sdn;
445 		break;
446 
447 	case 'D':
448 		prbufp->description = D;
449 		break;
450 
451 	case 'e':
452 		if (!s) {
453 			prbufp->interface = makepath(
454 				Lp_A_Interfaces,
455 				e,
456 				(char *)0
457 			);
458 		}
459 		break;
460 
461 	case 'F':
462 		if (!s)
463 			prbufp->fault_rec = F;
464 		break;
465 
466 #if	defined(CAN_DO_MODULES)
467 	case 'H':
468 		if (!s)
469 			prbufp->modules = H;
470 		break;
471 #endif
472 
473 	case 'h':
474 		if (!s)
475 			prbufp->login = 0;
476 		break;
477 
478 	case 'i':
479 		if (!s)
480 			prbufp->interface = fullpath(i);
481 		break;
482 
483 	case 'I':
484 		prbufp->input_types = I;
485 		break;
486 
487 	case 'l':
488 		if (!s)
489 			prbufp->login = 1;
490 		break;
491 
492 	case 'L':
493 		if (!s)
494 			prbufp->plen = length_sdn;
495 		break;
496 
497 	case 'm':
498 		if (!s)
499 			prbufp->interface = makepath(Lp_Model, m, (char *)0);
500 		break;
501 
502 	case 'M':
503 		if (!s)
504 			prbufp->lpi = lpi_sdn;
505 		break;
506 
507 #ifdef LP_USE_PAPI_ATTR
508 	case 'n':
509 	{
510 		if (n_opt != NULL)
511 		{
512 			if (*n_opt == '/')
513 			{
514 				prbufp->ppd = fullpath(n_opt);
515 			}
516 			else
517 			{
518 				prbufp->ppd =
519 				    makepath(Lp_Model, "ppd", n_opt, (char *)0);
520 			}
521 			ppdopt = 1;
522 		}
523 		break;
524 	}
525 #endif
526 
527 	case 'o':
528 		/*
529 		 * The "undefined" key-value -o options
530 		 *
531 		 * Options requires special handling. It is a
532 		 * list whose members are to be handled
533 		 * individually.
534 		 *
535 		 * Need to: set new options, keep old options if not
536 		 * redefined, remove old options if defined as "key=".
537 		 *
538 		 *
539 		 * "p" is a global containing the printer name
540 		 */
541 
542 		if (!s) {
543 
544 			if ((infile_opts = getpentry(p, PR_OPTIONS)) == NULL)
545 				prbufp->options = o_options;
546 			else {
547 				prbufp->options =
548 					pick_opts(infile_opts, o_options);
549 			}
550 		}
551 		break;
552 
553 	case 'R':
554 		if (s) {
555 			prbufp->remote = s;
556 			prbufp->dial_info = 0;
557 			prbufp->device = 0;
558 		} else
559 			prbufp->remote = 0;
560 		break;
561 
562 	case 's':
563 		if (!s) {
564 			/*
565 			 * lpadmin always defers to stty
566 			 */
567 			prbufp->speed = 0;
568 			prbufp->stty = stty_opt;
569 		}
570 		break;
571 
572 	case 'S':
573 		if (!M)
574 			if (STREQU(*S, NAME_NONE))
575 				prbufp->char_sets = 0;
576 			else
577 				prbufp->char_sets = S;
578 		break;
579 
580 	case 'T':
581 		prbufp->printer_types = T;
582 		break;
583 
584 	case 'U':
585 		if (!s) {
586 			prbufp->dial_info = U;
587 			prbufp->device = 0;
588 			prbufp->remote = 0;
589 		}
590 		break;
591 
592 	case 'v':
593 		if (!s) {
594 			prbufp->device = v;
595 			prbufp->dial_info = 0;
596 			prbufp->remote = 0;
597 		}
598 		break;
599 
600 	case 'w':
601 		if (!s)
602 			prbufp->pwid = width_sdn;
603 		break;
604 
605 	case 'W':
606 		if (!s)
607 			prbufp->fault_alert.W = W;
608 		break;
609 
610 	}
611 
612 
613 	BEGIN_CRITICAL
614 		if (putprinter(p, prbufp) == -1) {
615 			if (
616 				errno == EINVAL
617 			     && (badprinter & BAD_INTERFACE)
618 			)
619 				LP_ERRMSG1 (
620 					ERROR,
621 					E_ADM_BADINTF,
622 					prbufp->interface
623 				);
624 			else
625 				LP_ERRMSG2 (
626 					ERROR,
627 					E_LP_PUTPRINTER,
628 					p,
629 					PERROR
630 				);
631 			done(1);
632 		}
633 	END_CRITICAL
634 
635 	return;
636 }
637 
638 /**
639  ** fullpath()
640  **/
641 
642 static char		*fullpath (str)
643 	char			*str;
644 {
645 	register char		*cur_dir,
646 				*path;
647 
648 
649 	while (*str && *str == ' ')
650 		str++;
651 	if (*str == '/')
652 		return (str);
653 
654 	if (!(cur_dir = malloc(PATH_MAX + 1)))
655 		return (str);
656 
657 	getcwd (cur_dir, PATH_MAX);
658 	path = makepath(cur_dir, str, (char *)0);
659 
660 	/*
661 	 * Here we could be nice and strip out /./ and /../
662 	 * stuff, but it isn't necessary.
663 	 */
664 
665 	return (path);
666 }
667 
668 /**
669  ** nameit() - ADD USER NAME TO COMMAND
670  **/
671 
672 char			*nameit (cmd)
673 	char			*cmd;
674 {
675 	register char		*nm = getname(),
676 				*copy = malloc(
677 					(unsigned) (strlen(cmd) + 1 +
678 					strlen(nm) + 1)
679 	);
680 
681 	(void) strcpy (copy, cmd);
682 	(void) strcat (copy, " ");
683 	(void) strcat (copy, nm);
684 	return (copy);
685 }
686