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