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 /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */
34
35 #include "sys/types.h"
36 #include "sys/stat.h"
37 #include "stdio.h"
38 #include "string.h"
39 #include "errno.h"
40 #include "stdlib.h"
41
42 #include "lp.h"
43 #include "printers.h"
44
45 #include <unistd.h>
46 #include <sys/wait.h>
47
48 #define SHELL "/bin/sh"
49 #define PPDZIP ".gz"
50
51 extern struct {
52 char *v;
53 short len,
54 okremote;
55 } prtrheadings[];
56
57 #if defined(__STDC__)
58
59 static void print_sdn (int, char *, SCALED);
60 static void print_l (int, char *, char **);
61 static void print_str (int, char *, char *);
62
63 #ifdef LP_USE_PAPI_ATTR
64 static int addPrintersPPD(char *name, PRINTER *prbufp);
65 static int copyPPDFile(char *ppd, char *printersPPD);
66 static int unzipPPDFile(char *ppd, char *printersPPD);
67 #endif
68
69 #else
70
71 static void print_sdn(),
72 print_l(),
73 print_str();
74
75 #ifdef LP_USE_PAPI_ATTR
76 static int addPrintersPPD();
77 static int copyPPDFile();
78 static int unzipPPDFile();
79 #endif
80
81 #endif
82
83 unsigned long ignprinter = 0;
84 int ppdopt = 0;
85
86 /**
87 ** putprinter() - WRITE PRINTER STRUCTURE TO DISK FILES
88 **/
89
90 int
putprinter(char * name,PRINTER * prbufp)91 putprinter(char *name, PRINTER *prbufp)
92 {
93 register char * path;
94 register char * stty;
95 register char * speed;
96
97 int fdin, fdout;
98
99 int fld;
100
101 char buf[BUFSIZ];
102
103 struct stat statbuf1,
104 statbuf2;
105
106
107 badprinter = 0;
108
109 if (!name || !*name) {
110 errno = EINVAL;
111 return (-1);
112 }
113
114 if (STREQU(NAME_ALL, name)) {
115 errno = EINVAL;
116 return (-1);
117 }
118
119 /*
120 * First go through the structure and see if we have
121 * anything strange.
122 */
123 if (!okprinter(name, prbufp, 1)) {
124 errno = EINVAL;
125 return (-1);
126 }
127
128 if (!Lp_A_Printers || !Lp_A_Interfaces) {
129 getadminpaths (LPUSER);
130 if (!Lp_A_Printers || !Lp_A_Interfaces)
131 return (0);
132 }
133
134 /*
135 * Create the parent directory for this printer
136 * if it doesn't yet exist.
137 */
138 if (!(path = getprinterfile(name, (char *)0)))
139 return (-1);
140 if (Stat(path, &statbuf1) == 0) {
141 if (!S_ISDIR(statbuf1.st_mode)) {
142 Free (path);
143 errno = ENOTDIR;
144 return (-1);
145 }
146 } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) {
147 Free (path);
148 return (-1);
149 }
150 Free (path);
151
152 /*
153 * Create the copy of the interface program, unless
154 * that would be silly or not desired.
155 * Conversely, make sure the interface program doesn't
156 * exist for a remote printer.
157 */
158 if (prbufp->remote) {
159 if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
160 return (-1);
161 (void)rmfile (path);
162 Free (path);
163 }
164 if (prbufp->interface && (ignprinter & BAD_INTERFACE) == 0) {
165 if (Stat(prbufp->interface, &statbuf1) == -1)
166 return (-1);
167 if (!(path = makepath(Lp_A_Interfaces, name, (char *)0)))
168 return (-1);
169 if (
170 Stat(path, &statbuf2) == -1
171 || statbuf1.st_dev != statbuf2.st_dev
172 || statbuf1.st_ino != statbuf2.st_ino
173 ) {
174 register int n;
175
176 if ((fdin = open_locked(prbufp->interface, "r", 0)) < 0) {
177 Free (path);
178 return (-1);
179 }
180 if ((fdout = open_locked(path, "w", MODE_EXEC)) < 0) {
181 Free (path);
182 close(fdin);
183 return (-1);
184 }
185 while ((n = read(fdin, buf, BUFSIZ)) > 0)
186 write (fdout, buf, n);
187 close(fdout);
188 close(fdin);
189 }
190 Free (path);
191 }
192
193 #ifdef LP_USE_PAPI_ATTR
194 /*
195 * Handle PPD (Postscript Printer Definition) file for printer
196 * if this printer has been configured with one
197 */
198 if ((prbufp->ppd != NULL) && (ppdopt))
199 {
200 if (addPrintersPPD(name, prbufp) != 0)
201 {
202 /* failed to added the printers PPD file */
203 return (-1);
204 }
205 }
206 #endif
207
208 /*
209 * If this printer is dialed up, remove any baud rates
210 * from the stty option list and move the last one to
211 * the ".speed" member if the ".speed" member isn't already
212 * set. Conversely, if this printer is directly connected,
213 * move any value from the ".speed" member to the stty list.
214 */
215
216 stty = (prbufp->stty? Strdup(prbufp->stty) : 0);
217 if (prbufp->speed)
218 speed = Strdup(prbufp->speed);
219 else
220 speed = 0;
221
222 if (prbufp->dial_info && stty) {
223 register char *newstty,
224 *p,
225 *q;
226
227 register int len;
228
229 if (!(q = newstty = Malloc(strlen(stty) + 1))) {
230 Free (stty);
231 errno = ENOMEM;
232 return (-1);
233 }
234 newstty[0] = 0; /* start with empty copy */
235
236 for (
237 p = strtok(stty, " ");
238 p;
239 p = strtok((char *)0, " ")
240 ) {
241 len = strlen(p);
242 if (strspn(p, "0123456789") == len) {
243 /*
244 * If "prbufp->speed" isn't set, then
245 * use the speed we just found. Don't
246 * check "speed", because if more than
247 * one speed was given in the list, we
248 * want the last one.
249 */
250 if (!prbufp->speed) {
251 if (speed)
252 Free (speed);
253 speed = Strdup(p);
254 }
255
256 } else {
257 /*
258 * Not a speed, so copy it to the
259 * new stty string.
260 */
261 if (q != newstty)
262 *q++ = ' ';
263 strcpy (q, p);
264 q += len;
265 }
266 }
267
268 Free (stty);
269 stty = newstty;
270
271 } else if (!prbufp->dial_info && speed) {
272 register char *newstty;
273
274 newstty = Malloc(strlen(stty) + 1 + strlen(speed) + 1);
275 if (!newstty) {
276 if (stty)
277 Free (stty);
278 errno = ENOMEM;
279 return (-1);
280 }
281
282 if (stty) {
283 strcpy (newstty, stty);
284 strcat (newstty, " ");
285 strcat (newstty, speed);
286 Free (stty);
287 } else
288 strcpy (newstty, speed);
289 Free (speed);
290 speed = 0;
291
292 stty = newstty;
293
294 }
295
296 /*
297 * Open the configuration file and write out the printer
298 * configuration.
299 */
300
301 if (!(path = getprinterfile(name, CONFIGFILE))) {
302 if (stty)
303 Free (stty);
304 if (speed)
305 Free (speed);
306 return (-1);
307 }
308 if ((fdout = open_locked(path, "w", MODE_READ)) < 0) {
309 Free (path);
310 if (stty)
311 Free (stty);
312 if (speed)
313 Free (speed);
314 return (-1);
315 }
316 Free (path);
317
318 errno = 0;
319 for (fld = 0; fld < PR_MAX; fld++) {
320 if (prbufp->remote && !prtrheadings[fld].okremote)
321 continue;
322
323 switch (fld) {
324
325 #define HEAD prtrheadings[fld].v
326
327 case PR_BAN:
328 {
329 char *ptr = NAME_ON;
330
331 switch (prbufp->banner) {
332 case BAN_ALWAYS:
333 ptr = NAME_ON;
334 break;
335 case BAN_NEVER:
336 ptr = NAME_OFF;
337 break;
338 case BAN_OPTIONAL:
339 ptr = NAME_OPTIONAL;
340 break;
341 }
342 (void)fdprintf(fdout, "%s %s\n", HEAD, ptr);
343 }
344 break;
345
346 case PR_CPI:
347 print_sdn(fdout, HEAD, prbufp->cpi);
348 break;
349
350 case PR_CS:
351 if (!emptylist(prbufp->char_sets))
352 print_l(fdout, HEAD, prbufp->char_sets);
353 break;
354
355 case PR_ITYPES:
356 /*
357 * Put out the header even if the list is empty,
358 * to distinguish no input types from the default.
359 */
360 print_l(fdout, HEAD, prbufp->input_types);
361 break;
362
363 case PR_DEV:
364 print_str(fdout, HEAD, prbufp->device);
365 break;
366
367 case PR_DIAL:
368 print_str(fdout, HEAD, prbufp->dial_info);
369 break;
370
371 case PR_RECOV:
372 print_str(fdout, HEAD, prbufp->fault_rec);
373 break;
374
375 case PR_INTFC:
376 print_str(fdout, HEAD, prbufp->interface);
377 break;
378
379 case PR_LPI:
380 print_sdn(fdout, HEAD, prbufp->lpi);
381 break;
382
383 case PR_LEN:
384 print_sdn(fdout, HEAD, prbufp->plen);
385 break;
386
387 case PR_LOGIN:
388 if (prbufp->login & LOG_IN)
389 (void)fdprintf(fdout, "%s\n", HEAD);
390 break;
391
392 case PR_PTYPE:
393 {
394 char **printer_types;
395
396 /*
397 * For backward compatibility for those who
398 * use only "->printer_type", we have to play
399 * some games here.
400 */
401 if (prbufp->printer_type && !prbufp->printer_types)
402 printer_types = getlist(
403 prbufp->printer_type,
404 LP_WS,
405 LP_SEP
406 );
407 else
408 printer_types = prbufp->printer_types;
409
410 if (!printer_types || !*printer_types)
411 print_str(fdout, HEAD, NAME_UNKNOWN);
412 else
413 print_l(fdout, HEAD, printer_types);
414
415 if (printer_types != prbufp->printer_types)
416 freelist (printer_types);
417 break;
418 }
419
420 case PR_REMOTE:
421 print_str(fdout, HEAD, prbufp->remote);
422 break;
423
424 case PR_SPEED:
425 print_str(fdout, HEAD, speed);
426 break;
427
428 case PR_STTY:
429 print_str(fdout, HEAD, stty);
430 break;
431
432 case PR_WIDTH:
433 print_sdn(fdout, HEAD, prbufp->pwid);
434 break;
435
436 #if defined(CAN_DO_MODULES)
437 case PR_MODULES:
438 /*
439 * Put out the header even if the list is empty,
440 * to distinguish no modules from the default.
441 */
442 print_l(fdout, HEAD, prbufp->modules);
443 break;
444 #endif
445
446 case PR_OPTIONS:
447 print_l(fdout, HEAD, prbufp->options);
448 break;
449
450 case PR_PPD:
451 {
452 print_str(fdout, HEAD, prbufp->ppd);
453 break;
454 }
455 }
456
457 }
458 if (stty)
459 Free (stty);
460 if (speed)
461 Free (speed);
462 if (errno != 0) {
463 close(fdout);
464 return (-1);
465 }
466 close(fdout);
467
468 /*
469 * If we have a description of the printer,
470 * write it out to a separate file.
471 */
472 if (prbufp->description) {
473
474 if (!(path = getprinterfile(name, COMMENTFILE)))
475 return (-1);
476
477 if (dumpstring(path, prbufp->description) == -1) {
478 Free (path);
479 return (-1);
480 }
481 Free (path);
482
483 }
484
485 /*
486 * Now write out the alert condition.
487 */
488 if (
489 prbufp->fault_alert.shcmd
490 && putalert(Lp_A_Printers, name, &(prbufp->fault_alert)) == -1
491 )
492 return (-1);
493
494 return (0);
495 }
496
497 /**
498 ** print_sdn() - PRINT SCALED DECIMAL NUMBER WITH HEADER
499 ** print_l() - PRINT (char **) LIST WITH HEADER
500 ** print_str() - PRINT STRING WITH HEADER
501 **/
502
503 static void
print_sdn(int fd,char * head,SCALED sdn)504 print_sdn(int fd, char *head, SCALED sdn)
505 {
506 if (sdn.val <= 0)
507 return;
508
509 (void)fdprintf (fd, "%s ", head);
510 fdprintsdn (fd, sdn);
511
512 return;
513 }
514
515 static void
print_l(int fd,char * head,char ** list)516 print_l(int fd, char *head, char **list)
517 {
518 (void)fdprintf (fd, "%s ", head);
519 printlist_setup (0, 0, LP_SEP, 0);
520 fdprintlist (fd, list);
521 printlist_unsetup ();
522
523 return;
524 }
525
526 static void
print_str(int fd,char * head,char * str)527 print_str(int fd, char *head, char *str)
528 {
529 if (!str || !*str)
530 return;
531
532 (void)fdprintf (fd, "%s %s\n", head, str);
533
534 return;
535 }
536
537
538 #ifdef LP_USE_PAPI_ATTR
539 /*
540 * Function: addPrintersPPD()
541 *
542 * Description: Handle PPD (Postscript Printer Definition) file for this
543 * printer if it has been configured with one
544 *
545 */
546
547 static int
addPrintersPPD(char * name,PRINTER * prbufp)548 addPrintersPPD(char *name, PRINTER *prbufp)
549
550 {
551 int result = 0;
552 char *path = NULL;
553 char *ppd = NULL;
554 char buf[BUFSIZ];
555 struct stat statbuf;
556
557 (void) snprintf(buf, sizeof (buf), "%s.ppd", name);
558 if (prbufp->remote)
559 {
560 /* make sure the PPD file doesn't exist for a remote printer */
561 if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0)))
562 {
563 result = -1;
564 }
565 else
566 {
567 (void) rmfile(path);
568 }
569 }
570
571 if ((result == 0) && (prbufp->ppd != NULL))
572 {
573 ppd = strdup(prbufp->ppd);
574
575 if (ppd == NULL)
576 {
577 result = -1;
578 }
579 else
580 {
581 /* Check the PPD file given exists */
582
583 if (Stat(ppd, &statbuf) == -1)
584 {
585 /*
586 * The given ppd files does not exist, but
587 * check if there is a zipped version of the
588 * file that we can use instead
589 */
590 if (strstr(ppd, PPDZIP) != NULL)
591 {
592 /* this is a zipped file so exit */
593 result = -1;
594 }
595 else
596 {
597 ppd = Realloc(ppd,
598 strlen(ppd)+strlen(PPDZIP)+2);
599 if (ppd != NULL)
600 {
601 ppd = strcat(ppd, PPDZIP);
602 if (Stat(ppd, &statbuf) == -1)
603 {
604 /*
605 * this zipped version
606 * of the file does not
607 * exist either
608 */
609 result = -1;
610 }
611 }
612 else
613 {
614 result = -1;
615 }
616 }
617 }
618 }
619
620 /*
621 * Create the copy of the PPD file for this printer
622 * unless that would be silly or not desired
623 */
624
625 if (result == 0)
626 {
627 if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0)))
628 {
629 result = -1;
630 }
631 }
632
633 /*
634 * At this point we may have a zipped or unzipped ppd file, if
635 * it's unzipped just copy it otherwise unzip it to the
636 * printer's ppd file (/etc/lp/ppd/<printer>.ppd)
637 */
638
639 if (result == 0)
640 {
641 if (strstr(ppd, PPDZIP) == NULL)
642 {
643 result = copyPPDFile(ppd, path);
644 }
645 else
646 {
647 result = unzipPPDFile(ppd, path);
648 }
649
650 (void) chown_lppath(path);
651 (void) chmod(path, 0644);
652 }
653
654 if (ppd != NULL)
655 {
656 Free(ppd);
657 }
658 if (path != NULL)
659 {
660 Free(path);
661 }
662 }
663
664 return (result);
665 } /* addPrintersPPD() */
666
667
668 /*
669 * Function: copyPPDFile()
670 *
671 * Description: Copy the given ppd file to the printer's file in /etc/lp/ppd
672 *
673 */
674
675 static int
copyPPDFile(char * ppd,char * printersPPD)676 copyPPDFile(char *ppd, char *printersPPD)
677
678 {
679 int result = 0;
680 register int n = 0;
681 int fdin = 0;
682 int fdout = 0;
683 char buf[BUFSIZ];
684
685 if ((ppd != NULL) && (printersPPD != NULL))
686 {
687 if ((fdin = open_locked(ppd, "r", 0)) < 0)
688 {
689 result = -1;
690 }
691 else
692 {
693 fdout = open_locked(printersPPD, "w", MODE_EXEC);
694 if (fdout < 0)
695 {
696 close(fdin);
697 result = -1;
698 }
699 }
700
701 if (result == 0)
702 {
703 while ((n = read(fdin, buf, BUFSIZ)) > 0)
704 {
705 write(fdout, buf, n);
706 }
707 close(fdout);
708 close(fdin);
709 }
710 }
711 else
712 {
713 result = -1;
714 }
715
716 return (result);
717 } /* copyPPDFile() */
718
719
720
721 /*
722 * Function: unzipPPDFile()
723 *
724 * Description: Unzip the given ppd file to the printer's file in /etc/lp/ppd.
725 * This is done by forking and running the unzip utility on the
726 * zipped ppd file.
727 *
728 */
729
730 static int
unzipPPDFile(char * ppd,char * printersPPD)731 unzipPPDFile(char *ppd, char *printersPPD)
732
733 {
734 int result = -1;
735 char *cmdLine = NULL;
736 pid_t childPID = 0;
737 int stat = 0;
738 int clSize = 0;
739
740
741 if ((ppd != NULL) && (printersPPD != NULL))
742 {
743 childPID = fork();
744
745 switch (childPID)
746 {
747 case -1:
748 {
749 /* return error */
750 break;
751 }
752
753 case 0:
754 {
755 /* child process - so execute something */
756
757 clSize = strlen("/usr/bin/rm -f ") +
758 strlen(printersPPD) +
759 strlen("/usr/bin/gzip -dc ") +
760 strlen(ppd) +
761 strlen(printersPPD) + 20;
762 cmdLine = malloc(clSize);
763 if (cmdLine != NULL)
764 {
765
766 (void) snprintf(cmdLine, clSize,
767 "/usr/bin/rm -f %s; /usr/bin/gzip -dc %s > %s",
768 printersPPD, ppd,
769 printersPPD);
770 result = execl(SHELL, SHELL, "-c",
771 cmdLine, NULL);
772 exit(result);
773 }
774 break;
775 }
776
777 default:
778 {
779 /* parent process, child pid is in childPID */
780
781 while (wait(&stat) != childPID);
782
783 if ((stat & 0xff00) == 0)
784 {
785 result = 0;
786 }
787 break;
788 }
789 }
790 }
791
792 return (result);
793 } /* unzipPPDFile() */
794 #endif
795