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