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 106 snprintf(line, sizeof (line), "%c%s\n", code, value); 107 strlcat(*metadata, line, size); 108 109 return (PAPI_OK); 110 } 111 112 static papi_status_t 113 add_svr4_control_line(char **metadata, char code, char *value) 114 { 115 116 char line[BUFSIZ]; 117 118 if ((metadata == NULL) || (value == NULL)) 119 return (PAPI_BAD_REQUEST); 120 121 snprintf(line, sizeof (line), "%c%s", code, value); 122 123 return (add_lpd_control_line(metadata, '5', line)); 124 } 125 126 static papi_status_t 127 add_hpux_control_line(char **metadata, char *value) 128 { 129 130 char line[BUFSIZ]; 131 132 if ((metadata == NULL) || (value == NULL)) 133 return (PAPI_BAD_REQUEST); 134 135 snprintf(line, sizeof (line), " O%s", value); 136 137 return (add_lpd_control_line(metadata, 'N', line)); 138 } 139 140 static papi_status_t 141 add_int_control_line(char **metadata, char code, int value, int flag) 142 { 143 char buf[16]; 144 145 snprintf(buf, sizeof (buf), "%d", value); 146 147 if (flag == LPD_SVR4) 148 return (add_svr4_control_line(metadata, code, buf)); 149 else 150 return (add_lpd_control_line(metadata, code, buf)); 151 } 152 153 static papi_status_t 154 lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes, 155 char **metadata, papi_attribute_t ***used) 156 { 157 papi_status_t status = PAPI_OK; 158 char *s; 159 int integer; 160 char bool; 161 char host[BUFSIZ]; 162 char *user = "nobody"; 163 uid_t uid = getuid(); 164 struct passwd *pw; 165 char *h1; 166 167 if (svc == NULL) 168 return (PAPI_BAD_REQUEST); 169 170 /* There is nothing to do */ 171 if (attributes == NULL) 172 return (PAPI_OK); 173 174 gethostname(host, sizeof (host)); 175 if (papiAttributeListGetString(attributes, NULL, 176 "job-originating-host-name", &h1) == PAPI_OK) { 177 papiAttributeListAddString(&attributes, PAPI_ATTR_APPEND, 178 "job-host", h1); 179 } 180 add_lpd_control_line(metadata, 'H', host); 181 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 182 "job-originating-host-name", host); 183 184 if ((pw = getpwuid(uid)) != NULL) 185 user = pw->pw_name; 186 if (uid == 0) 187 papiAttributeListGetString(svc->attributes, NULL, "username", 188 &user); 189 add_lpd_control_line(metadata, 'P', user); 190 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 191 "job-originating-user-name", user); 192 193 /* Class for Banner Page */ 194 s = NULL; 195 papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s); 196 if (s != NULL) { 197 add_lpd_control_line(metadata, 'C', s); 198 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 199 "rfc-1179-class", s); 200 } 201 202 /* Print Banner Page */ 203 s = NULL; 204 papiAttributeListGetString(attributes, NULL, "job-sheets", &s); 205 if ((s != NULL) && (strcmp(s, "standard") == 0)) { 206 add_lpd_control_line(metadata, 'L', user); 207 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 208 "job-sheets", s); 209 } 210 211 /* Jobname */ 212 s = NULL; 213 papiAttributeListGetString(attributes, NULL, "job-name", &s); 214 if (s != NULL) { 215 add_lpd_control_line(metadata, 'J', s); 216 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 217 "job-name", s); 218 } 219 220 /* User to mail when job is done - lpr -m */ 221 bool = PAPI_FALSE; 222 papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool); 223 if (bool == PAPI_TRUE) { 224 add_lpd_control_line(metadata, 'M', user); 225 papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL, 226 "rfc-1179-mail", bool); 227 } 228 229 /* Title for pr */ 230 s = NULL; 231 papiAttributeListGetString(attributes, NULL, "pr-title", &s); 232 if (s != NULL) { 233 add_lpd_control_line(metadata, 'T', s); 234 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 235 "pr-title", s); 236 } 237 238 /* Indent - used with pr filter */ 239 integer = 0; 240 papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer); 241 if (integer >= 1) { 242 add_int_control_line(metadata, 'I', integer, LPD_RFC); 243 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 244 "pr-indent", integer); 245 } 246 247 /* Width - used with pr filter */ 248 integer = 0; 249 papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer); 250 if (integer >= 1) { 251 add_int_control_line(metadata, 'W', integer, LPD_RFC); 252 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 253 "pr-width", integer); 254 } 255 256 /* file with Times Roman font lpr -1 */ 257 s = NULL; 258 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s); 259 if (s != NULL) { 260 add_lpd_control_line(metadata, '1', s); 261 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 262 "rfc-1179-font-r", s); 263 } 264 265 /* file with Times Roman font lpr -2 */ 266 s = NULL; 267 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s); 268 if (s != NULL) { 269 add_lpd_control_line(metadata, '2', s); 270 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 271 "rfc-1179-font-i", s); 272 } 273 274 /* file with Times Roman font lpr -3 */ 275 s = NULL; 276 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s); 277 if (s != NULL) { 278 add_lpd_control_line(metadata, '3', s); 279 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 280 "rfc-1179-font-b", s); 281 } 282 283 /* file with Times Roman font lpr -4 */ 284 s = NULL; 285 papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s); 286 if (s != NULL) { 287 add_lpd_control_line(metadata, '4', s); 288 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 289 "rfc-1179-font-s", s); 290 } 291 292 /* 293 * The document format needs to be added, but the control line 294 * should be added when the filenames are figured out. 295 */ 296 s = NULL; 297 papiAttributeListGetString(attributes, NULL, "document-format", &s); 298 if (s != NULL) { 299 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 300 "document-format", s); 301 } 302 303 return (status); 304 } 305 306 static char * 307 unused_attributes(papi_attribute_t **list, papi_attribute_t **used) 308 { 309 char *result = NULL; 310 char **names = NULL; 311 int i; 312 313 if ((list == NULL) || (used == NULL)) 314 return (NULL); 315 316 for (i = 0; used[i] != NULL; i++) 317 list_append(&names, used[i]->name); 318 319 if (names != NULL) { 320 papi_attribute_t **unused = NULL; 321 322 /* add these to the list of things to ignore */ 323 list_append(&names, "document-format"); 324 list_append(&names, "copies"); 325 326 split_and_copy_attributes(names, list, NULL, &unused); 327 if (unused != NULL) { 328 size_t size = 0; 329 330 do { 331 size += 1024; 332 if (result != NULL) 333 free(result); 334 result = calloc(1, size); 335 } while (papiAttributeListToString(unused, " ", 336 result, size) != PAPI_OK); 337 papiAttributeListFree(unused); 338 } 339 free(names); 340 } 341 342 return (result); 343 } 344 345 /* 346 * lpd_add_svr4_attributes 347 * Solaris 2.x LP - BSD protocol extensions 348 */ 349 static papi_status_t 350 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes, 351 char **metadata, papi_attribute_t ***used) 352 { 353 papi_attribute_t *tmp[2]; 354 char *s; 355 int integer; 356 357 if (svc == NULL) 358 return (PAPI_BAD_REQUEST); 359 360 /* media */ 361 s = NULL; 362 papiAttributeListGetString(attributes, NULL, "media", &s); 363 if (s != NULL) { 364 add_svr4_control_line(metadata, 'f', s); 365 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 366 "media", s); 367 } 368 369 /* Handling */ 370 s = NULL; 371 papiAttributeListGetString(attributes, NULL, "job-hold-until", &s); 372 if ((s != NULL) && (strcmp(s, "indefinite") == 0)) { 373 add_svr4_control_line(metadata, 'H', "hold"); 374 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 375 "job-hold-until", "indefinite"); 376 } else if ((s != NULL) && (strcmp(s, "no-hold") == 0)) { 377 add_svr4_control_line(metadata, 'H', "immediate"); 378 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 379 "job-hold-until", "no-hold"); 380 } else if (s != NULL) { 381 add_svr4_control_line(metadata, 'H', s); 382 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 383 "job-hold-until", s); 384 } 385 386 /* Pages */ 387 s = NULL; 388 memset(tmp, 0, sizeof (tmp)); 389 tmp[0] = papiAttributeListFind(attributes, "page-ranges"); 390 if (tmp[0] != NULL) { 391 char buf[BUFSIZ]; 392 393 papiAttributeListToString(tmp, " ", buf, sizeof (buf)); 394 if ((s = strchr(buf, '=')) != NULL) { 395 add_svr4_control_line(metadata, 'P', ++s); 396 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 397 "page-ranges", s); 398 } 399 } 400 401 /* Priority : lp -q */ 402 integer = -1; 403 papiAttributeListGetInteger(attributes, NULL, "job-priority", &integer); 404 if (integer != -1) { 405 integer = 40 - (integer / 2.5); 406 add_int_control_line(metadata, 'q', integer, LPD_SVR4); 407 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 408 "job-priority", integer); 409 } 410 411 /* Charset : lp -S */ 412 s = NULL; 413 papiAttributeListGetString(attributes, NULL, "lp-charset", &s); 414 if (s != NULL) { 415 add_svr4_control_line(metadata, 'S', s); 416 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 417 "lp-charset", s); 418 } 419 420 /* Type : done when adding file */ 421 422 /* Mode : lp -y */ 423 s = NULL; 424 papiAttributeListGetString(attributes, NULL, "lp-modes", &s); 425 if (s != NULL) { 426 add_svr4_control_line(metadata, 'y', s); 427 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 428 "lp-modes", s); 429 } 430 431 /* Options lp -o are handled elsewhere */ 432 if ((s = unused_attributes(attributes, *used)) != NULL) { 433 add_lpd_control_line(metadata, 'O', s); 434 free(s); 435 } 436 437 return (PAPI_OK); 438 } 439 440 papi_status_t 441 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes, 442 char **metadata, papi_attribute_t ***used) 443 { 444 char *s = NULL; 445 446 /* Options lp -o */ 447 if ((s = unused_attributes(attributes, *used)) != NULL) { 448 add_hpux_control_line(metadata, s); 449 free(s); 450 } 451 452 return (PAPI_OK); 453 } 454 455 papi_status_t 456 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes, 457 char **metadata, papi_attribute_t ***used) 458 { 459 if ((svc == NULL) || (metadata == NULL)) 460 return (PAPI_BAD_REQUEST); 461 462 lpd_add_rfc1179_attributes(svc, attributes, metadata, used); 463 464 /* add protocol extensions if applicable */ 465 if (svc->uri->fragment != NULL) { 466 if ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 467 (strcasecmp(svc->uri->fragment, "svr4") == 0)) 468 lpd_add_svr4_attributes(svc, attributes, metadata, 469 used); 470 else if (strcasecmp(svc->uri->fragment, "hpux") == 0) 471 lpd_add_hpux_attributes(svc, attributes, metadata, 472 used); 473 /* 474 * others could be added here: 475 * lprng, sco, aix, digital unix, xerox, ... 476 */ 477 } 478 479 return (PAPI_OK); 480 } 481 482 papi_status_t 483 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes, 484 char **files, char **metadata, papi_attribute_t ***used) 485 { 486 char *format = "text/plain"; 487 char rfc_fmt = 'l'; 488 int copies = 1; 489 char host[BUFSIZ]; 490 int i; 491 492 if ((svc == NULL) || (attributes == NULL) || (files == NULL) || 493 (metadata == NULL)) 494 return (PAPI_BAD_ARGUMENT); 495 496 papiAttributeListGetString(attributes, NULL, "document-format", 497 &format); 498 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 499 "document-format", format); 500 if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') { 501 if ((svc->uri->fragment != NULL) && 502 ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 503 (strcasecmp(svc->uri->fragment, "svr4") == 0))) 504 add_svr4_control_line(metadata, 'T', format); 505 rfc_fmt = 'l'; 506 } 507 508 papiAttributeListGetInteger(attributes, NULL, "copies", &copies); 509 if (copies < 1) 510 copies = 1; 511 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies); 512 513 gethostname(host, sizeof (host)); 514 515 for (i = 0; files[i] != NULL; i++) { 516 char name[BUFSIZ]; 517 struct stat statbuf; 518 char key; 519 int j; 520 521 if ((strcmp("standard input", files[i]) != 0) && 522 (access(files[i], R_OK) < 0)) { 523 detailed_error(svc, gettext("aborting request, %s: %s"), 524 files[i], strerror(errno)); 525 return (PAPI_NOT_AUTHORIZED); 526 } 527 if (strcmp("standard input", files[i]) != 0) { 528 if (stat(files[i], &statbuf) < 0) { 529 detailed_error(svc, 530 gettext("Cannot access file: %s: %s"), 531 files[i], strerror(errno)); 532 return (PAPI_DOCUMENT_ACCESS_ERROR); 533 } 534 if (statbuf.st_size == 0) { 535 detailed_error(svc, 536 gettext("Zero byte (empty) file: %s"), 537 files[i]); 538 return (PAPI_BAD_ARGUMENT); 539 } 540 } 541 542 if (i < 26) 543 key = 'A' + i; 544 else if (i < 52) 545 key = 'a' + (i - 26); 546 else if (i < 62) 547 key = '0' + (i - 52); 548 else { 549 detailed_error(svc, 550 gettext("too many files, truncated at 62")); 551 return (PAPI_OK_SUBST); 552 } 553 554 snprintf(name, sizeof (name), "df%cXXX%s", key, host); 555 556 for (j = 0; j < copies; j++) 557 add_lpd_control_line(metadata, rfc_fmt, name); 558 add_lpd_control_line(metadata, 'U', name); 559 add_lpd_control_line(metadata, 'N', (char *)files[i]); 560 } 561 562 return (PAPI_OK); 563 } 564 565 papi_status_t 566 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes, 567 int *ofd) 568 { 569 papi_status_t status = PAPI_INTERNAL_ERROR; 570 int fd; 571 char path[32]; 572 char *list[2]; 573 574 if ((svc == NULL) || (metadata == NULL)) 575 return (PAPI_BAD_ARGUMENT); 576 577 strcpy(path, "/tmp/lpd-job-XXXXXX"); 578 fd = mkstemp(path); 579 write(fd, metadata, strlen(metadata)); 580 close(fd); 581 582 list[0] = path; 583 list[1] = NULL; 584 585 if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) { 586 switch (errno) { 587 case ENOSPC: 588 status = PAPI_TEMPORARY_ERROR; 589 break; 590 case EIO: 591 status = PAPI_TEMPORARY_ERROR; 592 break; 593 case ECONNREFUSED: 594 status = PAPI_SERVICE_UNAVAILABLE; 595 break; 596 case ENOENT: 597 status = PAPI_NOT_ACCEPTING; 598 break; 599 case EBADMSG: 600 case EBADF: 601 status = PAPI_OK; 602 break; 603 default: 604 status = PAPI_TIMEOUT; 605 break; 606 } 607 } else { 608 status = PAPI_OK; 609 } 610 611 if (ofd != NULL) 612 *ofd = fd; 613 else 614 close(fd); 615 616 /* read the ID and add it to to the job */ 617 if ((fd = open(path, O_RDONLY)) >= 0) { 618 int job_id = 0; 619 read(fd, &job_id, sizeof (job_id)); 620 papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE, 621 "job-id", job_id); 622 close(fd); 623 } 624 625 unlink(path); 626 627 return (status); 628 } 629