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