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 return (status); 286 } 287 288 static char * 289 unused_attributes(papi_attribute_t **list, papi_attribute_t **used) 290 { 291 char *result = NULL; 292 char **names = NULL; 293 int i; 294 295 if ((list == NULL) || (used == NULL)) 296 return (NULL); 297 298 for (i = 0; used[i] != NULL; i++) 299 list_append(&names, used[i]->name); 300 301 if (names != NULL) { 302 papi_attribute_t **unused = NULL; 303 304 /* add these to the list of things to ignore */ 305 list_append(&names, "document-format"); 306 list_append(&names, "copies"); 307 308 split_and_copy_attributes(names, list, NULL, &unused); 309 if (unused != NULL) { 310 size_t size = 0; 311 312 do { 313 size += 1024; 314 if (result != NULL) 315 free(result); 316 result = calloc(1, size); 317 } while (papiAttributeListToString(unused, " ", 318 result, size) != PAPI_OK); 319 papiAttributeListFree(unused); 320 } 321 free(names); 322 } 323 324 return (result); 325 } 326 327 /* 328 * lpd_add_svr4_attributes 329 * Solaris 2.x LP - BSD protocol extensions 330 */ 331 static papi_status_t 332 lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes, 333 char **metadata, papi_attribute_t ***used) 334 { 335 papi_attribute_t *tmp[2]; 336 char *s; 337 int integer; 338 339 if (svc == NULL) 340 return (PAPI_BAD_REQUEST); 341 342 /* media */ 343 s = NULL; 344 papiAttributeListGetString(attributes, NULL, "media", &s); 345 if (s != NULL) { 346 add_svr4_control_line(metadata, 'f', s); 347 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 348 "media", s); 349 } 350 351 /* Handling */ 352 s = NULL; 353 papiAttributeListGetString(attributes, NULL, "job-hold-until", &s); 354 if ((s != NULL) && (strcmp(s, "indefinite"))) { 355 add_svr4_control_line(metadata, 'H', "hold"); 356 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 357 "job-hold-until", "indefinite"); 358 } else if ((s != NULL) && (strcmp(s, "no-hold"))) { 359 add_svr4_control_line(metadata, 'H', "immediate"); 360 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 361 "job-hold-until", "no-hold"); 362 } else if (s != NULL) { 363 add_svr4_control_line(metadata, 'H', s); 364 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 365 "job-hold-until", s); 366 } 367 368 /* Pages */ 369 s = NULL; 370 memset(tmp, NULL, sizeof (tmp)); 371 tmp[0] = papiAttributeListFind(attributes, "page-ranges"); 372 if (tmp[0] != NULL) { 373 char buf[BUFSIZ]; 374 375 papiAttributeListToString(tmp, " ", buf, sizeof (buf)); 376 if ((s = strchr(buf, '=')) != NULL) { 377 add_svr4_control_line(metadata, 'P', ++s); 378 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 379 "page-ranges", s); 380 } 381 } 382 383 /* Priority : lp -q */ 384 integer = -1; 385 papiAttributeListGetInteger(attributes, NULL, "job-priority", &integer); 386 if (integer != -1) { 387 integer = 40 - (integer / 2.5); 388 add_int_control_line(metadata, 'q', integer, LPD_SVR4); 389 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, 390 "job-priority", integer); 391 } 392 393 /* Charset : lp -S */ 394 s = NULL; 395 papiAttributeListGetString(attributes, NULL, "lp-charset", &s); 396 if (s != NULL) { 397 add_svr4_control_line(metadata, 'S', s); 398 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 399 "lp-charset", s); 400 } 401 402 /* Type : done when adding file */ 403 404 /* Mode : lp -y */ 405 s = NULL; 406 papiAttributeListGetString(attributes, NULL, "lp-modes", &s); 407 if (s != NULL) { 408 add_svr4_control_line(metadata, 'y', s); 409 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 410 "lp-modes", s); 411 } 412 413 /* Options lp -o are handled elsewhere */ 414 if ((s = unused_attributes(attributes, *used)) != NULL) { 415 add_lpd_control_line(metadata, 'O', s); 416 free(s); 417 } 418 419 return (PAPI_OK); 420 } 421 422 papi_status_t 423 lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes, 424 char **metadata, papi_attribute_t ***used) 425 { 426 char *s = NULL; 427 428 /* Options lp -o */ 429 if ((s = unused_attributes(attributes, *used)) != NULL) { 430 add_hpux_control_line(metadata, s); 431 free(s); 432 } 433 434 return (PAPI_OK); 435 } 436 437 papi_status_t 438 lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes, 439 char **metadata, papi_attribute_t ***used) 440 { 441 if ((svc == NULL) || (metadata == NULL)) 442 return (PAPI_BAD_REQUEST); 443 444 lpd_add_rfc1179_attributes(svc, attributes, metadata, used); 445 446 /* add protocol extensions if applicable */ 447 if (svc->uri->fragment != NULL) { 448 if ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 449 (strcasecmp(svc->uri->fragment, "svr4") == 0)) 450 lpd_add_svr4_attributes(svc, attributes, metadata, 451 used); 452 else if (strcasecmp(svc->uri->fragment, "hpux") == 0) 453 lpd_add_hpux_attributes(svc, attributes, metadata, 454 used); 455 /* 456 * others could be added here: 457 * lprng, sco, aix, digital unix, xerox, ... 458 */ 459 } 460 461 return (PAPI_OK); 462 } 463 464 papi_status_t 465 lpd_job_add_files(service_t *svc, papi_attribute_t **attributes, 466 char **files, char **metadata, papi_attribute_t ***used) 467 { 468 char *format = "text/plain"; 469 char rfc_fmt = 'l'; 470 int copies = 1; 471 char host[BUFSIZ]; 472 int i; 473 474 if ((svc == NULL) || (attributes == NULL) || (files == NULL) || 475 (metadata == NULL)) 476 return (PAPI_BAD_ARGUMENT); 477 478 papiAttributeListGetString(attributes, NULL, "document-format", 479 &format); 480 papiAttributeListAddString(used, PAPI_ATTR_EXCL, 481 "document-format", format); 482 if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') { 483 if ((svc->uri->fragment != NULL) && 484 ((strcasecmp(svc->uri->fragment, "solaris") == 0) || 485 (strcasecmp(svc->uri->fragment, "svr4") == 0))) 486 add_svr4_control_line(metadata, 'T', format); 487 rfc_fmt = 'l'; 488 } 489 490 papiAttributeListGetInteger(attributes, NULL, "copies", &copies); 491 if (copies < 1) 492 copies = 1; 493 papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies); 494 495 gethostname(host, sizeof (host)); 496 497 for (i = 0; files[i] != NULL; i++) { 498 char name[BUFSIZ]; 499 struct stat statbuf; 500 char key; 501 int j; 502 503 if ((strcmp("standard input", files[i]) != 0) && 504 (access(files[i], R_OK) < 0)) { 505 detailed_error(svc, gettext("aborting request, %s: %s"), 506 files[i], strerror(errno)); 507 return (PAPI_NOT_AUTHORIZED); 508 } 509 if (strcmp("standard input", files[i]) != 0) { 510 stat(files[i], &statbuf); 511 if (statbuf.st_size == 0) { 512 detailed_error(svc, 513 gettext("Zero byte (empty) file: %s"), 514 files[i]); 515 return (PAPI_BAD_ARGUMENT); 516 } 517 } 518 519 if (i < 26) 520 key = 'A' + i; 521 else if (i < 52) 522 key = 'a' + (i - 26); 523 else if (i < 62) 524 key = '0' + (i - 52); 525 else { 526 detailed_error(svc, 527 gettext("too many files, truncated at 62")); 528 return (PAPI_OK_SUBST); 529 } 530 531 snprintf(name, sizeof (name), "df%cXXX%s", key, host); 532 533 for (j = 0; j < copies; j++) 534 add_lpd_control_line(metadata, rfc_fmt, name); 535 add_lpd_control_line(metadata, 'U', name); 536 add_lpd_control_line(metadata, 'N', (char *)files[i]); 537 } 538 539 return (PAPI_OK); 540 } 541 542 papi_status_t 543 lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes, 544 int *ofd) 545 { 546 papi_status_t status = PAPI_INTERNAL_ERROR; 547 int fd; 548 char path[32]; 549 char *list[2]; 550 551 if ((svc == NULL) || (metadata == NULL)) 552 return (PAPI_BAD_ARGUMENT); 553 554 strcpy(path, "/tmp/lpd-job-XXXXXX"); 555 fd = mkstemp(path); 556 write(fd, metadata, strlen(metadata)); 557 close(fd); 558 559 list[0] = path; 560 list[1] = NULL; 561 562 if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) { 563 switch (errno) { 564 case ENOSPC: 565 status = PAPI_TEMPORARY_ERROR; 566 break; 567 case EIO: 568 status = PAPI_TEMPORARY_ERROR; 569 break; 570 case ECONNREFUSED: 571 status = PAPI_SERVICE_UNAVAILABLE; 572 break; 573 case ENOENT: 574 status = PAPI_NOT_ACCEPTING; 575 break; 576 case EBADMSG: 577 case EBADF: 578 status = PAPI_OK; 579 break; 580 default: 581 status = PAPI_TIMEOUT; 582 break; 583 } 584 } else 585 status = PAPI_OK; 586 587 if (ofd != NULL) 588 *ofd = fd; 589 else 590 close(fd); 591 592 /* read the ID and add it to to the job */ 593 if ((fd = open(path, O_RDONLY)) >= 0) { 594 int job_id = 0; 595 read(fd, &job_id, sizeof (job_id)); 596 papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE, 597 "job-id", job_id); 598 close(fd); 599 } 600 601 unlink(path); 602 603 return (status); 604 } 605