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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * 26 */ 27 28 /* $Id: lpd-job.c 157 2006-04-26 15:07:55Z ktou $ */ 29 30 31 #define __EXTENSIONS__ /* for strtok_r() */ 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <unistd.h> 35 #include <errno.h> 36 #include <limits.h> 37 #include <sys/types.h> 38 #include <sys/stat.h> 39 #include <fcntl.h> 40 #include <string.h> 41 #include <pwd.h> 42 #include <libintl.h> 43 #include <papi_impl.h> 44 45 enum { LPD_RFC, LPD_SVR4 }; 46 47 static char 48 mime_type_to_rfc1179_type(char *mime) 49 { 50 static struct { char *mime; char rfc; } cvt[] = { 51 { "text/plain", 'f' }, 52 { "application/octet-stream", 'l' }, 53 { "application/postscript", 'f' }, /* rfc incorrectly has 'o' */ 54 { "application/x-pr", 'p' }, 55 { "application/x-cif", 'c' }, 56 { "application/x-dvi", 'd' }, 57 { "application/x-fortran", 'r' }, 58 { "application/x-plot", 'g' }, 59 { "application/x-ditroff", 'n' }, 60 { "application/x-troff", 't' }, 61 { "application/x-raster", 'v' }, 62 { NULL, 0} 63 }; 64 char result = '\0'; 65 66 if (mime != NULL) { 67 int i; 68 69 for (i = 0; cvt[i].mime != NULL; i++) 70 if (strcasecmp(cvt[i].mime, mime) == 0) { 71 result = cvt[i].rfc; 72 break; 73 } 74 } 75 76 return (result); 77 } 78 79 static papi_status_t 80 add_lpd_control_line(char **metadata, char code, char *value) 81 { 82 size_t size = 0; 83 char line[BUFSIZ]; 84 85 if ((metadata == NULL) || (value == NULL)) 86 return (PAPI_BAD_REQUEST); 87 88 if (*metadata != NULL) 89 size = strlen(*metadata); 90 size += strlen(value) + 3; 91 92 if (*metadata == NULL) { 93 *metadata = (char *)calloc(1, size); 94 } else { 95 void *tmp; 96 tmp = calloc(1, size); 97 if (tmp) { 98 strlcpy(tmp, *metadata, size); 99 free(*metadata); 100 *metadata = (char *)tmp; 101 } else 102 return (PAPI_TEMPORARY_ERROR); 103 } 104 105 snprintf(line, sizeof (line), "%c%s\n", code, value); 106 strlcat(*metadata, line, size); 107 108 return (PAPI_OK); 109 } 110 111 static papi_status_t 112 add_svr4_control_line(char **metadata, char code, char *value) 113 { 114 115 char line[BUFSIZ]; 116 117 if ((metadata == NULL) || (value == NULL)) 118 return (PAPI_BAD_REQUEST); 119 120 snprintf(line, sizeof (line), "%c%s", code, value); 121 122 return (add_lpd_control_line(metadata, '5', line)); 123 } 124 125 static papi_status_t 126 add_hpux_control_line(char **metadata, char *value) 127 { 128 129 char line[BUFSIZ]; 130 131 if ((metadata == NULL) || (value == NULL)) 132 return (PAPI_BAD_REQUEST); 133 134 snprintf(line, sizeof (line), " O%s", value); 135 136 return (add_lpd_control_line(metadata, 'N', line)); 137 } 138 139 static papi_status_t 140 add_int_control_line(char **metadata, char code, int value, int flag) 141 { 142 char buf[16]; 143 144 snprintf(buf, sizeof (buf), "%d", value); 145 146 if (flag == LPD_SVR4) 147 return (add_svr4_control_line(metadata, code, buf)); 148 else 149 return (add_lpd_control_line(metadata, code, buf)); 150 } 151 152 static papi_status_t 153 lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes, 154 char **metadata, papi_attribute_t ***used) 155 { 156 papi_status_t status = PAPI_OK; 157 char *s; 158 int integer; 159 char bool; 160 char host[BUFSIZ]; 161 char *user = "nobody"; 162 uid_t uid = getuid(); 163 struct passwd *pw; 164 165 if (svc == NULL) 166 return (PAPI_BAD_REQUEST); 167 168 /* There is nothing to do */ 169 if (attributes == NULL) 170 return (PAPI_OK); 171 172 gethostname(host, sizeof (host)); 173 add_lpd_control_line(metadata, 'H', host); 174 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 175 "job-originating-host-name", host); 176 177 if ((pw = getpwuid(uid)) != NULL) 178 user = pw->pw_name; 179 if (uid == 0) 180 papiAttributeListGetString(svc->attributes, NULL, "username", 181 &user); 182 add_lpd_control_line(metadata, 'P', user); 183 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 184 "job-originating-user-name", user); 185 186 /* Class for Banner Page */ 187 s = NULL; 188 papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s); 189 if (s != NULL) { 190 add_lpd_control_line(metadata, 'C', s); 191 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 192 "rfc-1179-class", s); 193 } 194 195 /* Print Banner Page */ 196 s = NULL; 197 papiAttributeListGetString(attributes, NULL, "job-sheets", &s); 198 if ((s != NULL) && (strcmp(s, "standard") == 0)) { 199 add_lpd_control_line(metadata, 'L', user); 200 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 201 "job-sheets", s); 202 } 203 204 /* Jobname */ 205 s = NULL; 206 papiAttributeListGetString(attributes, NULL, "job-name", &s); 207 if (s != NULL) { 208 add_lpd_control_line(metadata, 'J', s); 209 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 210 "job-name", s); 211 } 212 213 /* User to mail when job is done - lpr -m */ 214 bool = PAPI_FALSE; 215 papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool); 216 if (bool == PAPI_TRUE) { 217 add_lpd_control_line(metadata, 'M', user); 218 papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL, 219 "rfc-1179-mail", bool); 220 } 221 222 /* Title for pr */ 223 s = NULL; 224 papiAttributeListGetString(attributes, NULL, "pr-title", &s); 225 if (s != NULL) { 226 add_lpd_control_line(metadata, 'T', s); 227 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 228 "pr-title", s); 229 } 230 231 /* Indent - used with pr filter */ 232 integer = 0; 233 papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer); 234 if (integer >= 1) { 235 add_int_control_line(metadata, 'I', integer, LPD_RFC); 236 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 237 "pr-indent", integer); 238 } 239 240 /* Width - used with pr filter */ 241 integer = 0; 242 papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer); 243 if (integer >= 1) { 244 add_int_control_line(metadata, 'W', integer, LPD_RFC); 245 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 246 "pr-width", integer); 247 } 248 249 /* file with Times Roman font lpr -1 */ 250 s = NULL; 251 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s); 252 if (s != NULL) { 253 add_lpd_control_line(metadata, '1', s); 254 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 255 "rfc-1179-font-r", s); 256 } 257 258 /* file with Times Roman font lpr -2 */ 259 s = NULL; 260 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s); 261 if (s != NULL) { 262 add_lpd_control_line(metadata, '2', s); 263 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 264 "rfc-1179-font-i", s); 265 } 266 267 /* file with Times Roman font lpr -3 */ 268 s = NULL; 269 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s); 270 if (s != NULL) { 271 add_lpd_control_line(metadata, '3', s); 272 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 273 "rfc-1179-font-b", s); 274 } 275 276 /* file with Times Roman font lpr -4 */ 277 s = NULL; 278 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s); 279 if (s != NULL) { 280 add_lpd_control_line(metadata, '4', s); 281 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 282 "rfc-1179-font-s", s); 283 } 284 285 /* 286 * The document format needs to be added, but the control line 287 * should be added when the filenames are figured out. 288 */ 289 s = NULL; 290 papiAttributeListGetString(attributes, NULL, "document-format", &s); 291 if (s != NULL) { 292 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 293 "document-format", s); 294 } 295 296 return (status); 297 } 298 299 static char * 300 unused_attributes(papi_attribute_t **list, papi_attribute_t **used) 301 { 302 char *result = NULL; 303 char **names = NULL; 304 int i; 305 306 if ((list == NULL) || (used == NULL)) 307 return (NULL); 308 309 for (i = 0; used[i] != NULL; i++) 310 list_append(&names, used[i]->name); 311 312 if (names != NULL) { 313 papi_attribute_t **unused = NULL; 314 315 /* add these to the list of things to ignore */ 316 list_append(&names, "document-format"); 317 list_append(&names, "copies"); 318 319 split_and_copy_attributes(names, list, NULL, &unused); 320 if (unused != NULL) { 321 size_t size = 0; 322 323 do { 324 size += 1024; 325 if (result != NULL) 326 free(result); 327 result = calloc(1, size); 328 } while (papiAttributeListToString(unused, " ", 329 result, size) != PAPI_OK); 330 papiAttributeListFree(unused); 331 } 332 free(names); 333 } 334 335 return (result); 336 } 337 338 /* 339 * lpd_add_svr4_attributes 340 * Solaris 2.x LP - BSD protocol extensions 341 */ 342 static papi_status_t 343 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes, 344 char **metadata, papi_attribute_t ***used) 345 { 346 papi_attribute_t *tmp[2]; 347 char *s; 348 int integer; 349 350 if (svc == NULL) 351 return (PAPI_BAD_REQUEST); 352 353 /* media */ 354 s = NULL; 355 papiAttributeListGetString(attributes, NULL, "media", &s); 356 if (s != NULL) { 357 add_svr4_control_line(metadata, 'f', s); 358 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 359 "media", s); 360 } 361 362 /* Handling */ 363 s = NULL; 364 papiAttributeListGetString(attributes, NULL, "job-hold-until", &s); 365 if ((s != NULL) && (strcmp(s, "indefinite") == 0)) { 366 add_svr4_control_line(metadata, 'H', "hold"); 367 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 368 "job-hold-until", "indefinite"); 369 } else if ((s != NULL) && (strcmp(s, "no-hold") == 0)) { 370 add_svr4_control_line(metadata, 'H', "immediate"); 371 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 372 "job-hold-until", "no-hold"); 373 } else if (s != NULL) { 374 add_svr4_control_line(metadata, 'H', s); 375 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 376 "job-hold-until", s); 377 } 378 379 /* Pages */ 380 s = NULL; 381 memset(tmp, NULL, sizeof (tmp)); 382 tmp[0] = papiAttributeListFind(attributes, "page-ranges"); 383 if (tmp[0] != NULL) { 384 char buf[BUFSIZ]; 385 386 papiAttributeListToString(tmp, " ", buf, sizeof (buf)); 387 if ((s = strchr(buf, '=')) != NULL) { 388 add_svr4_control_line(metadata, 'P', ++s); 389 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 390 "page-ranges", s); 391 } 392 } 393 394 /* Priority : lp -q */ 395 integer = -1; 396 papiAttributeListGetInteger(attributes, NULL, "job-priority", &integer); 397 if (integer != -1) { 398 integer = 40 - (integer / 2.5); 399 add_int_control_line(metadata, 'q', integer, LPD_SVR4); 400 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 401 "job-priority", integer); 402 } 403 404 /* Charset : lp -S */ 405 s = NULL; 406 papiAttributeListGetString(attributes, NULL, "lp-charset", &s); 407 if (s != NULL) { 408 add_svr4_control_line(metadata, 'S', s); 409 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 410 "lp-charset", s); 411 } 412 413 /* Type : done when adding file */ 414 415 /* Mode : lp -y */ 416 s = NULL; 417 papiAttributeListGetString(attributes, NULL, "lp-modes", &s); 418 if (s != NULL) { 419 add_svr4_control_line(metadata, 'y', s); 420 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 421 "lp-modes", s); 422 } 423 424 /* Options lp -o are handled elsewhere */ 425 if ((s = unused_attributes(attributes, *used)) != NULL) { 426 add_lpd_control_line(metadata, 'O', s); 427 free(s); 428 } 429 430 return (PAPI_OK); 431 } 432 433 papi_status_t 434 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes, 435 char **metadata, papi_attribute_t ***used) 436 { 437 char *s = NULL; 438 439 /* Options lp -o */ 440 if ((s = unused_attributes(attributes, *used)) != NULL) { 441 add_hpux_control_line(metadata, s); 442 free(s); 443 } 444 445 return (PAPI_OK); 446 } 447 448 papi_status_t 449 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes, 450 char **metadata, papi_attribute_t ***used) 451 { 452 if ((svc == NULL) || (metadata == NULL)) 453 return (PAPI_BAD_REQUEST); 454 455 lpd_add_rfc1179_attributes(svc, attributes, metadata, used); 456 457 /* add protocol extensions if applicable */ 458 if (svc->uri->fragment != NULL) { 459 if ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 460 (strcasecmp(svc->uri->fragment, "svr4") == 0)) 461 lpd_add_svr4_attributes(svc, attributes, metadata, 462 used); 463 else if (strcasecmp(svc->uri->fragment, "hpux") == 0) 464 lpd_add_hpux_attributes(svc, attributes, metadata, 465 used); 466 /* 467 * others could be added here: 468 * lprng, sco, aix, digital unix, xerox, ... 469 */ 470 } 471 472 return (PAPI_OK); 473 } 474 475 papi_status_t 476 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes, 477 char **files, char **metadata, papi_attribute_t ***used) 478 { 479 char *format = "text/plain"; 480 char rfc_fmt = 'l'; 481 int copies = 1; 482 char host[BUFSIZ]; 483 int i; 484 485 if ((svc == NULL) || (attributes == NULL) || (files == NULL) || 486 (metadata == NULL)) 487 return (PAPI_BAD_ARGUMENT); 488 489 papiAttributeListGetString(attributes, NULL, "document-format", 490 &format); 491 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 492 "document-format", format); 493 if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') { 494 if ((svc->uri->fragment != NULL) && 495 ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 496 (strcasecmp(svc->uri->fragment, "svr4") == 0))) 497 add_svr4_control_line(metadata, 'T', format); 498 rfc_fmt = 'l'; 499 } 500 501 papiAttributeListGetInteger(attributes, NULL, "copies", &copies); 502 if (copies < 1) 503 copies = 1; 504 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies); 505 506 gethostname(host, sizeof (host)); 507 508 for (i = 0; files[i] != NULL; i++) { 509 char name[BUFSIZ]; 510 struct stat statbuf; 511 char key; 512 int j; 513 514 if ((strcmp("standard input", files[i]) != 0) && 515 (access(files[i], R_OK) < 0)) { 516 detailed_error(svc, gettext("aborting request, %s: %s"), 517 files[i], strerror(errno)); 518 return (PAPI_NOT_AUTHORIZED); 519 } 520 if (strcmp("standard input", files[i]) != 0) { 521 if (stat(files[i], &statbuf) < 0) { 522 detailed_error(svc, 523 gettext("Cannot access file: %s: %s"), 524 files[i], strerror(errno)); 525 return (PAPI_DOCUMENT_ACCESS_ERROR); 526 } 527 if (statbuf.st_size == 0) { 528 detailed_error(svc, 529 gettext("Zero byte (empty) file: %s"), 530 files[i]); 531 return (PAPI_BAD_ARGUMENT); 532 } 533 } 534 535 if (i < 26) 536 key = 'A' + i; 537 else if (i < 52) 538 key = 'a' + (i - 26); 539 else if (i < 62) 540 key = '0' + (i - 52); 541 else { 542 detailed_error(svc, 543 gettext("too many files, truncated at 62")); 544 return (PAPI_OK_SUBST); 545 } 546 547 snprintf(name, sizeof (name), "df%cXXX%s", key, host); 548 549 for (j = 0; j < copies; j++) 550 add_lpd_control_line(metadata, rfc_fmt, name); 551 add_lpd_control_line(metadata, 'U', name); 552 add_lpd_control_line(metadata, 'N', (char *)files[i]); 553 } 554 555 return (PAPI_OK); 556 } 557 558 papi_status_t 559 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes, 560 int *ofd) 561 { 562 papi_status_t status = PAPI_INTERNAL_ERROR; 563 int fd; 564 char path[32]; 565 char *list[2]; 566 567 if ((svc == NULL) || (metadata == NULL)) 568 return (PAPI_BAD_ARGUMENT); 569 570 strcpy(path, "/tmp/lpd-job-XXXXXX"); 571 fd = mkstemp(path); 572 write(fd, metadata, strlen(metadata)); 573 close(fd); 574 575 list[0] = path; 576 list[1] = NULL; 577 578 if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) { 579 switch (errno) { 580 case ENOSPC: 581 status = PAPI_TEMPORARY_ERROR; 582 break; 583 case EIO: 584 status = PAPI_TEMPORARY_ERROR; 585 break; 586 case ECONNREFUSED: 587 status = PAPI_SERVICE_UNAVAILABLE; 588 break; 589 case ENOENT: 590 status = PAPI_NOT_ACCEPTING; 591 break; 592 case EBADMSG: 593 case EBADF: 594 status = PAPI_OK; 595 break; 596 default: 597 status = PAPI_TIMEOUT; 598 break; 599 } 600 } else 601 status = PAPI_OK; 602 603 if (ofd != NULL) 604 *ofd = fd; 605 else 606 close(fd); 607 608 /* read the ID and add it to to the job */ 609 if ((fd = open(path, O_RDONLY)) >= 0) { 610 int job_id = 0; 611 read(fd, &job_id, sizeof (job_id)); 612 papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE, 613 "job-id", job_id); 614 close(fd); 615 } 616 617 unlink(path); 618 619 return (status); 620 } 621