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 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 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 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 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 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 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 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