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