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