/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* EMACS_MODES: !fill, lnumb, !overwrite, !nodelete, !picture */ #include "sys/types.h" #include "sys/stat.h" #include "stdio.h" #include "string.h" #include "errno.h" #include "stdlib.h" #include "lp.h" #include "printers.h" #include #include #define SHELL "/bin/sh" #define PPDZIP ".gz" extern struct { char *v; short len, okremote; } prtrheadings[]; #if defined(__STDC__) static void print_sdn (int, char *, SCALED); static void print_l (int, char *, char **); static void print_str (int, char *, char *); #ifdef LP_USE_PAPI_ATTR static int addPrintersPPD(char *name, PRINTER *prbufp); static int copyPPDFile(char *ppd, char *printersPPD); static int unzipPPDFile(char *ppd, char *printersPPD); #endif #else static void print_sdn(), print_l(), print_str(); #ifdef LP_USE_PAPI_ATTR static int addPrintersPPD(); static int copyPPDFile(); static int unzipPPDFile(); #endif #endif unsigned long ignprinter = 0; int ppdopt = 0; /** ** putprinter() - WRITE PRINTER STRUCTURE TO DISK FILES **/ int putprinter(char *name, PRINTER *prbufp) { register char * path; register char * stty; register char * speed; int fdin, fdout; int fld; char buf[BUFSIZ]; struct stat statbuf1, statbuf2; badprinter = 0; if (!name || !*name) { errno = EINVAL; return (-1); } if (STREQU(NAME_ALL, name)) { errno = EINVAL; return (-1); } /* * First go through the structure and see if we have * anything strange. */ if (!okprinter(name, prbufp, 1)) { errno = EINVAL; return (-1); } if (!Lp_A_Printers || !Lp_A_Interfaces) { getadminpaths (LPUSER); if (!Lp_A_Printers || !Lp_A_Interfaces) return (0); } /* * Create the parent directory for this printer * if it doesn't yet exist. */ if (!(path = getprinterfile(name, (char *)0))) return (-1); if (Stat(path, &statbuf1) == 0) { if (!S_ISDIR(statbuf1.st_mode)) { Free (path); errno = ENOTDIR; return (-1); } } else if (errno != ENOENT || mkdir_lpdir(path, MODE_DIR) == -1) { Free (path); return (-1); } Free (path); /* * Create the copy of the interface program, unless * that would be silly or not desired. * Conversely, make sure the interface program doesn't * exist for a remote printer. */ if (prbufp->remote) { if (!(path = makepath(Lp_A_Interfaces, name, (char *)0))) return (-1); (void)rmfile (path); Free (path); } if (prbufp->interface && (ignprinter & BAD_INTERFACE) == 0) { if (Stat(prbufp->interface, &statbuf1) == -1) return (-1); if (!(path = makepath(Lp_A_Interfaces, name, (char *)0))) return (-1); if ( Stat(path, &statbuf2) == -1 || statbuf1.st_dev != statbuf2.st_dev || statbuf1.st_ino != statbuf2.st_ino ) { register int n; if ((fdin = open_locked(prbufp->interface, "r", 0)) < 0) { Free (path); return (-1); } if ((fdout = open_locked(path, "w", MODE_EXEC)) < 0) { Free (path); close(fdin); return (-1); } while ((n = read(fdin, buf, BUFSIZ)) > 0) write (fdout, buf, n); close(fdout); close(fdin); } Free (path); } #ifdef LP_USE_PAPI_ATTR /* * Handle PPD (Postscript Printer Definition) file for printer * if this printer has been configured with one */ if ((prbufp->ppd != NULL) && (ppdopt)) { if (addPrintersPPD(name, prbufp) != 0) { /* failed to added the printers PPD file */ return (-1); } } #endif /* * If this printer is dialed up, remove any baud rates * from the stty option list and move the last one to * the ".speed" member if the ".speed" member isn't already * set. Conversely, if this printer is directly connected, * move any value from the ".speed" member to the stty list. */ stty = (prbufp->stty? Strdup(prbufp->stty) : 0); if (prbufp->speed) speed = Strdup(prbufp->speed); else speed = 0; if (prbufp->dial_info && stty) { register char *newstty, *p, *q; register int len; if (!(q = newstty = Malloc(strlen(stty) + 1))) { Free (stty); errno = ENOMEM; return (-1); } newstty[0] = 0; /* start with empty copy */ for ( p = strtok(stty, " "); p; p = strtok((char *)0, " ") ) { len = strlen(p); if (strspn(p, "0123456789") == len) { /* * If "prbufp->speed" isn't set, then * use the speed we just found. Don't * check "speed", because if more than * one speed was given in the list, we * want the last one. */ if (!prbufp->speed) { if (speed) Free (speed); speed = Strdup(p); } } else { /* * Not a speed, so copy it to the * new stty string. */ if (q != newstty) *q++ = ' '; strcpy (q, p); q += len; } } Free (stty); stty = newstty; } else if (!prbufp->dial_info && speed) { register char *newstty; newstty = Malloc(strlen(stty) + 1 + strlen(speed) + 1); if (!newstty) { if (stty) Free (stty); errno = ENOMEM; return (-1); } if (stty) { strcpy (newstty, stty); strcat (newstty, " "); strcat (newstty, speed); Free (stty); } else strcpy (newstty, speed); Free (speed); speed = 0; stty = newstty; } /* * Open the configuration file and write out the printer * configuration. */ if (!(path = getprinterfile(name, CONFIGFILE))) { if (stty) Free (stty); if (speed) Free (speed); return (-1); } if ((fdout = open_locked(path, "w", MODE_READ)) < 0) { Free (path); if (stty) Free (stty); if (speed) Free (speed); return (-1); } Free (path); errno = 0; for (fld = 0; fld < PR_MAX; fld++) { if (prbufp->remote && !prtrheadings[fld].okremote) continue; switch (fld) { #define HEAD prtrheadings[fld].v case PR_BAN: { char *ptr = NAME_ON; switch (prbufp->banner) { case BAN_ALWAYS: ptr = NAME_ON; break; case BAN_NEVER: ptr = NAME_OFF; break; case BAN_OPTIONAL: ptr = NAME_OPTIONAL; break; } (void)fdprintf(fdout, "%s %s\n", HEAD, ptr); } break; case PR_CPI: print_sdn(fdout, HEAD, prbufp->cpi); break; case PR_CS: if (!emptylist(prbufp->char_sets)) print_l(fdout, HEAD, prbufp->char_sets); break; case PR_ITYPES: /* * Put out the header even if the list is empty, * to distinguish no input types from the default. */ print_l(fdout, HEAD, prbufp->input_types); break; case PR_DEV: print_str(fdout, HEAD, prbufp->device); break; case PR_DIAL: print_str(fdout, HEAD, prbufp->dial_info); break; case PR_RECOV: print_str(fdout, HEAD, prbufp->fault_rec); break; case PR_INTFC: print_str(fdout, HEAD, prbufp->interface); break; case PR_LPI: print_sdn(fdout, HEAD, prbufp->lpi); break; case PR_LEN: print_sdn(fdout, HEAD, prbufp->plen); break; case PR_LOGIN: if (prbufp->login & LOG_IN) (void)fdprintf(fdout, "%s\n", HEAD); break; case PR_PTYPE: { char **printer_types; /* * For backward compatibility for those who * use only "->printer_type", we have to play * some games here. */ if (prbufp->printer_type && !prbufp->printer_types) printer_types = getlist( prbufp->printer_type, LP_WS, LP_SEP ); else printer_types = prbufp->printer_types; if (!printer_types || !*printer_types) print_str(fdout, HEAD, NAME_UNKNOWN); else print_l(fdout, HEAD, printer_types); if (printer_types != prbufp->printer_types) freelist (printer_types); break; } case PR_REMOTE: print_str(fdout, HEAD, prbufp->remote); break; case PR_SPEED: print_str(fdout, HEAD, speed); break; case PR_STTY: print_str(fdout, HEAD, stty); break; case PR_WIDTH: print_sdn(fdout, HEAD, prbufp->pwid); break; #if defined(CAN_DO_MODULES) case PR_MODULES: /* * Put out the header even if the list is empty, * to distinguish no modules from the default. */ print_l(fdout, HEAD, prbufp->modules); break; #endif case PR_OPTIONS: print_l(fdout, HEAD, prbufp->options); break; case PR_PPD: { print_str(fdout, HEAD, prbufp->ppd); break; } } } if (stty) Free (stty); if (speed) Free (speed); if (errno != 0) { close(fdout); return (-1); } close(fdout); /* * If we have a description of the printer, * write it out to a separate file. */ if (prbufp->description) { if (!(path = getprinterfile(name, COMMENTFILE))) return (-1); if (dumpstring(path, prbufp->description) == -1) { Free (path); return (-1); } Free (path); } /* * Now write out the alert condition. */ if ( prbufp->fault_alert.shcmd && putalert(Lp_A_Printers, name, &(prbufp->fault_alert)) == -1 ) return (-1); return (0); } /** ** print_sdn() - PRINT SCALED DECIMAL NUMBER WITH HEADER ** print_l() - PRINT (char **) LIST WITH HEADER ** print_str() - PRINT STRING WITH HEADER **/ static void print_sdn(int fd, char *head, SCALED sdn) { if (sdn.val <= 0) return; (void)fdprintf (fd, "%s ", head); fdprintsdn (fd, sdn); return; } static void print_l(int fd, char *head, char **list) { (void)fdprintf (fd, "%s ", head); printlist_setup (0, 0, LP_SEP, 0); fdprintlist (fd, list); printlist_unsetup (); return; } static void print_str(int fd, char *head, char *str) { if (!str || !*str) return; (void)fdprintf (fd, "%s %s\n", head, str); return; } #ifdef LP_USE_PAPI_ATTR /* * Function: addPrintersPPD() * * Description: Handle PPD (Postscript Printer Definition) file for this * printer if it has been configured with one * */ static int addPrintersPPD(char *name, PRINTER *prbufp) { int result = 0; char *path = NULL; char *ppd = NULL; char buf[BUFSIZ]; struct stat statbuf; (void) snprintf(buf, sizeof (buf), "%s.ppd", name); if (prbufp->remote) { /* make sure the PPD file doesn't exist for a remote printer */ if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0))) { result = -1; } else { (void) rmfile(path); } } if ((result == 0) && (prbufp->ppd != NULL)) { ppd = strdup(prbufp->ppd); if (ppd == NULL) { result = -1; } else { /* Check the PPD file given exists */ if (Stat(ppd, &statbuf) == -1) { /* * The given ppd files does not exist, but * check if there is a zipped version of the * file that we can use instead */ if (strstr(ppd, PPDZIP) != NULL) { /* this is a zipped file so exit */ result = -1; } else { ppd = Realloc(ppd, strlen(ppd)+strlen(PPDZIP)+2); if (ppd != NULL) { ppd = strcat(ppd, PPDZIP); if (Stat(ppd, &statbuf) == -1) { /* * this zipped version * of the file does not * exist either */ result = -1; } } else { result = -1; } } } } /* * Create the copy of the PPD file for this printer * unless that would be silly or not desired */ if (result == 0) { if (!(path = makepath(ETCDIR, "ppd", buf, (char *)0))) { result = -1; } } /* * At this point we may have a zipped or unzipped ppd file, if * it's unzipped just copy it otherwise unzip it to the * printer's ppd file (/etc/lp/ppd/.ppd) */ if (result == 0) { if (strstr(ppd, PPDZIP) == NULL) { result = copyPPDFile(ppd, path); } else { result = unzipPPDFile(ppd, path); } (void) chown_lppath(path); (void) chmod(path, 0644); } if (ppd != NULL) { Free(ppd); } if (path != NULL) { Free(path); } } return (result); } /* addPrintersPPD() */ /* * Function: copyPPDFile() * * Description: Copy the given ppd file to the printer's file in /etc/lp/ppd * */ static int copyPPDFile(char *ppd, char *printersPPD) { int result = 0; register int n = 0; int fdin = 0; int fdout = 0; char buf[BUFSIZ]; if ((ppd != NULL) && (printersPPD != NULL)) { if ((fdin = open_locked(ppd, "r", 0)) < 0) { result = -1; } else { fdout = open_locked(printersPPD, "w", MODE_EXEC); if (fdout < 0) { close(fdin); result = -1; } } if (result == 0) { while ((n = read(fdin, buf, BUFSIZ)) > 0) { write(fdout, buf, n); } close(fdout); close(fdin); } } else { result = -1; } return (result); } /* copyPPDFile() */ /* * Function: unzipPPDFile() * * Description: Unzip the given ppd file to the printer's file in /etc/lp/ppd. * This is done by forking and running the unzip utility on the * zipped ppd file. * */ static int unzipPPDFile(char *ppd, char *printersPPD) { int result = -1; char *cmdLine = NULL; pid_t childPID = 0; int stat = 0; int clSize = 0; if ((ppd != NULL) && (printersPPD != NULL)) { childPID = fork(); switch (childPID) { case -1: { /* return error */ break; } case 0: { /* child process - so execute something */ clSize = strlen("/usr/bin/rm -f ") + strlen(printersPPD) + strlen("/usr/bin/gzip -dc ") + strlen(ppd) + strlen(printersPPD) + 20; cmdLine = malloc(clSize); if (cmdLine != NULL) { (void) snprintf(cmdLine, clSize, "/usr/bin/rm -f %s; /usr/bin/gzip -dc %s > %s", printersPPD, ppd, printersPPD); result = execl(SHELL, SHELL, "-c", cmdLine, NULL); exit(result); } break; } default: { /* parent process, child pid is in childPID */ while (wait(&stat) != childPID); if ((stat & 0xff00) == 0) { result = 0; } break; } } } return (result); } /* unzipPPDFile() */ #endif