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: common.c 162 2006-05-08 14:17:44Z njacobs $ */ 29 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <unistd.h> 33 #include <sys/types.h> 34 #include <sys/stat.h> 35 #include <fcntl.h> 36 #include <alloca.h> 37 #include <string.h> 38 #include <libintl.h> 39 #include <ctype.h> 40 #include <pwd.h> 41 #include <papi.h> 42 #include "common.h" 43 44 #ifndef HAVE_GETPASSPHRASE /* some systems don't have getpassphrase() */ 45 #define getpassphrase getpass 46 #endif 47 48 /* give the most verbose error message to the caller */ 49 char * 50 verbose_papi_message(papi_service_t svc, papi_status_t status) 51 { 52 char *mesg; 53 54 mesg = papiServiceGetStatusMessage(svc); 55 56 if (mesg == NULL) 57 mesg = papiStatusString(status); 58 59 return (mesg); 60 } 61 62 static int 63 match_job(int id, char *user, int ac, char *av[]) 64 { 65 int i; 66 67 for (i = 0; i < ac; i++) 68 if (strcmp("-", av[i]) == 0) 69 return (0); /* "current" user match */ 70 else if ((isdigit(av[i][0]) != 0) && (id == atoi(av[i]))) 71 return (0); /* job-id match */ 72 else if (strcmp(user, av[i]) == 0) 73 return (0); /* user match */ 74 75 return (-1); 76 } 77 78 /* 79 * return 0 : argument passed is job-id && job-id matches 80 * or argument passed is user 81 */ 82 static int 83 match_job_rid(int id, int ac, char *av[]) 84 { 85 int i; 86 87 for (i = 0; i < ac; i++) 88 if (isdigit(av[i][0]) != 0) { 89 if (id == atoi(av[i])) 90 /* job-id match */ 91 return (0); 92 } else 93 /* argument passed is user */ 94 return (0); 95 return (-1); 96 } 97 98 static struct { 99 char *mime_type; 100 char *lp_type; 101 } type_map[] = { 102 { "text/plain", "simple" }, 103 { "application/octet-stream", "raw" }, 104 { "application/octet-stream", "any" }, 105 { "application/postscript", "postscript" }, 106 { "application/postscript", "ps" }, 107 { "application/x-cif", "cif" }, 108 { "application/x-dvi", "dvi" }, 109 { "application/x-plot", "plot" }, 110 { "application/x-ditroff", "troff" }, 111 { "application/x-troff", "otroff" }, 112 { "application/x-pr", "pr" }, 113 { "application/x-fortran", "fortran" }, 114 { "application/x-raster", "raster" }, 115 { NULL, NULL} 116 }; 117 118 char * 119 lp_type_to_mime_type(char *lp_type) 120 { 121 int i; 122 123 if (lp_type == NULL) 124 return ("application/octet-stream"); 125 126 for (i = 0; type_map[i].lp_type != NULL; i++) 127 if (strcasecmp(type_map[i].lp_type, lp_type) == 0) 128 return (type_map[i].mime_type); 129 130 return (lp_type); 131 } 132 133 /* 134 * to support job/printer status 135 */ 136 static char * 137 state_string(int state) 138 { 139 switch (state) { 140 case 3: 141 return (gettext("idle")); 142 case 4: 143 return (gettext("processing")); 144 case 5: 145 return (gettext("stopped")); 146 default: 147 return (gettext("unknown")); 148 } 149 } 150 151 static char *_rank_suffixes[] = { 152 "th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th" 153 }; 154 155 static char * 156 rank_string(const int rank) 157 { 158 static char buf[12]; 159 160 if (rank < 0) 161 snprintf(buf, sizeof (buf), gettext("invalid")); 162 else if (rank == 0) 163 snprintf(buf, sizeof (buf), gettext("active")); 164 else if ((rank > 10) && (rank < 14)) 165 sprintf(buf, "%dth", rank); 166 else 167 sprintf(buf, "%d%s", rank, _rank_suffixes[rank % 10]); 168 169 return (buf); 170 } 171 172 static void 173 printer_state_line(FILE *fp, papi_printer_t p, int num_jobs, char *name) 174 { 175 papi_attribute_t **list = papiPrinterGetAttributeList(p); 176 int state = 0; 177 char *reason = ""; 178 179 (void) papiAttributeListGetInteger(list, NULL, 180 "printer-state", &state); 181 (void) papiAttributeListGetString(list, NULL, 182 "printer-state-reasons", &reason); 183 (void) papiAttributeListGetString(list, NULL, 184 "printer-name", &name); 185 186 if ((state != 0x03) || (num_jobs != 0)) { 187 fprintf(fp, "%s: %s", name, state_string(state)); 188 if (state == 0x05) /* stopped */ 189 fprintf(fp, ": %s\n", reason); 190 else 191 fprintf(fp, "\n"); 192 } else 193 fprintf(fp, "no entries\n"); 194 } 195 196 static void 197 print_header(FILE *fp) 198 { 199 fprintf(fp, gettext("Rank\tOwner\t Job\tFile(s)\t\t\t\tTotal Size\n")); 200 } 201 202 static void 203 print_job_line(FILE *fp, int count, papi_job_t job, int fmt, int ac, char *av[]) 204 { 205 papi_attribute_t **list = papiJobGetAttributeList(job); 206 int copies = 1, id = 0, rank = count, size = 0; 207 char *name = "print job"; 208 char *user = "nobody"; 209 char *host = "localhost"; 210 char *suffix = "k"; 211 212 (void) papiAttributeListGetInteger(list, NULL, 213 "job-id", &id); 214 (void) papiAttributeListGetInteger(list, NULL, 215 "job-id-requested", &id); 216 (void) papiAttributeListGetString(list, NULL, 217 "job-originating-user-name", &user); 218 (void) papiAttributeListGetString(list, NULL, 219 "job-originating-host-name", &host); 220 221 /* if we are looking and it doesn't match, return early */ 222 if ((ac > 0) && (match_job(id, user, ac, av) < 0)) 223 return; 224 225 (void) papiAttributeListGetInteger(list, NULL, 226 "copies", &copies); 227 (void) papiAttributeListGetInteger(list, NULL, 228 "number-of-intervening-jobs", &rank); 229 230 if (papiAttributeListGetInteger(list, NULL, "job-octets", &size) 231 == PAPI_OK) 232 suffix = "bytes"; 233 else 234 (void) papiAttributeListGetInteger(list, NULL, 235 "job-k-octets", &size); 236 (void) papiAttributeListGetString(list, NULL, 237 "job-name", &name); 238 239 size *= copies; 240 241 if (fmt == 3) { 242 fprintf(fp, gettext("%s\t%-8.8s %d\t%-32.32s%d %s\n"), 243 rank_string(++rank), user, id, name, size, suffix); 244 } else 245 fprintf(fp, gettext( 246 "\n%s: %s\t\t\t\t[job %d %s]\n\t%-32.32s\t%d %s\n"), 247 user, rank_string(++rank), id, host, name, size, 248 suffix); 249 } 250 251 /* 252 * to support job cancelation 253 */ 254 static void 255 cancel_job(papi_service_t svc, FILE *fp, char *printer, papi_job_t job, 256 int ac, char *av[]) 257 { 258 papi_status_t status; 259 papi_attribute_t **list = papiJobGetAttributeList(job); 260 int id = -1; 261 int rid = -1; 262 char *user = ""; 263 char *mesg = gettext("cancelled"); 264 int i = 0; 265 266 papiAttributeListGetInteger(list, NULL, 267 "job-id", &id); 268 papiAttributeListGetInteger(list, NULL, 269 "job-id-requested", &rid); 270 papiAttributeListGetString(list, NULL, 271 "job-originating-user-name", &user); 272 273 /* if we are looking and it doesn't match, return early */ 274 if ((ac > 0) && (match_job(id, user, ac, av) < 0) && 275 (match_job(rid, user, ac, av) < 0)) 276 return; 277 278 /* 279 * A remote lpd job should be cancelled only based on 280 * job-id-requested 281 */ 282 if (rid != -1) { 283 if (match_job_rid(rid, ac, av) == -1) 284 /* job-id mismatch */ 285 return; 286 } 287 288 status = papiJobCancel(svc, printer, id); 289 if (status != PAPI_OK) 290 mesg = papiStatusString(status); 291 292 if (rid != -1) 293 fprintf(fp, "%s-%d: %s\n", printer, rid, mesg); 294 else 295 fprintf(fp, "%s-%d: %s\n", printer, id, mesg); 296 } 297 298 int 299 berkeley_queue_report(papi_service_t svc, FILE *fp, char *dest, int fmt, 300 int ac, char *av[]) 301 { 302 papi_status_t status; 303 papi_printer_t p = NULL; 304 papi_job_t *jobs = NULL; 305 char *pattrs[] = { "printer-name", "printer-state", 306 "printer-state-reasons", NULL }; 307 char *jattrs[] = { "job-name", "job-octets", "job-k-octets", "job-id", 308 "job-originating-user-name", "job-id-requested", 309 "job-originating-host-name", 310 "number-of-intervening-jobs", NULL }; 311 int num_jobs = 0; 312 313 status = papiPrinterQuery(svc, dest, pattrs, NULL, &p); 314 if (status != PAPI_OK) { 315 fprintf(fp, gettext( 316 "Failed to query service for state of %s: %s\n"), 317 dest, verbose_papi_message(svc, status)); 318 return (-1); 319 } 320 321 status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL, 322 0, &jobs); 323 if (status != PAPI_OK) { 324 fprintf(fp, gettext( 325 "Failed to query service for jobs on %s: %s\n"), 326 dest, verbose_papi_message(svc, status)); 327 return (-1); 328 } 329 if (jobs != NULL) { 330 while (jobs[num_jobs] != NULL) 331 num_jobs++; 332 } 333 334 printer_state_line(fp, p, num_jobs, dest); 335 if (num_jobs > 0) { 336 int i; 337 338 if (fmt == 3) 339 print_header(fp); 340 for (i = 0; jobs[i] != NULL; i++) 341 print_job_line(fp, i, jobs[i], fmt, ac, av); 342 } 343 344 papiPrinterFree(p); 345 papiJobListFree(jobs); 346 347 return (num_jobs); 348 } 349 350 int 351 berkeley_cancel_request(papi_service_t svc, FILE *fp, char *dest, 352 int ac, char *av[]) 353 { 354 papi_status_t status; 355 papi_job_t *jobs = NULL; 356 char *jattrs[] = { "job-originating-user-name", "job-id", 357 "job-id-requested", NULL }; 358 359 status = papiPrinterListJobs(svc, dest, jattrs, PAPI_LIST_JOBS_ALL, 360 0, &jobs); 361 362 if (status != PAPI_OK) { 363 fprintf(fp, gettext("Failed to query service for %s: %s\n"), 364 dest, verbose_papi_message(svc, status)); 365 return (-1); 366 } 367 368 /* cancel the job(s) */ 369 if (jobs != NULL) { 370 int i; 371 372 for (i = 0; jobs[i] != NULL; i++) 373 cancel_job(svc, fp, dest, jobs[i], ac, av); 374 } 375 376 papiJobListFree(jobs); 377 378 return (0); 379 } 380 381 int 382 get_printer_id(char *name, char **printer, int *id) 383 { 384 int result = -1; 385 386 if (name != NULL) { 387 char *p = strrchr(name, '-'); 388 389 *printer = name; 390 if (p != NULL) { 391 char *s = NULL; 392 393 *id = strtol(p + 1, &s, 10); 394 if (s[0] != '\0') 395 *id = -1; 396 else 397 *p = '\0'; 398 result = 0; 399 } else 400 *id = -1; 401 } 402 403 return (result); 404 } 405 406 /* 407 * strsplit() splits a string into a NULL terminated array of substrings 408 * determined by a seperator. The original string is modified, and newly 409 * allocated space is only returned for the array itself. If more than 410 * 1024 substrings exist, they will be ignored. 411 */ 412 char ** 413 strsplit(char *string, const char *seperators) 414 { 415 char *list[BUFSIZ], 416 **result; 417 int length = 0; 418 419 if ((string == NULL) || (seperators == NULL)) 420 return (NULL); 421 422 (void) memset(list, 0, sizeof (list)); 423 for (list[length] = strtok(string, seperators); 424 (list[length] != NULL) && (length < (BUFSIZ - 2)); 425 list[length] = strtok(NULL, seperators)) 426 length++; 427 428 if ((result = (char **)calloc(length+1, sizeof (char *))) != NULL) 429 (void) memcpy(result, list, length * sizeof (char *)); 430 431 return (result); 432 } 433 434 papi_status_t 435 jobSubmitSTDIN(papi_service_t svc, char *printer, char *prefetch, int len, 436 papi_attribute_t **list, papi_job_t *job) 437 { 438 papi_status_t status; 439 papi_stream_t stream = NULL; 440 int rc; 441 char buf[BUFSIZ]; 442 443 status = papiJobStreamOpen(svc, printer, list, NULL, &stream); 444 445 if (len > 0) 446 status = papiJobStreamWrite(svc, stream, prefetch, len); 447 448 while ((status == PAPI_OK) && ((rc = read(0, buf, sizeof (buf))) > 0)) 449 status = papiJobStreamWrite(svc, stream, buf, rc); 450 451 if (status == PAPI_OK) 452 status = papiJobStreamClose(svc, stream, job); 453 454 return (status); 455 } 456 457 /* 458 * is_postscript() will detect if the file passed in contains postscript 459 * data. A one is returned if the file contains postscript, zero is returned 460 * if the file is not postscript, and -1 is returned if an error occurs 461 */ 462 #define PS_MAGIC "%!" 463 #define PC_PS_MAGIC "^D%!" 464 int 465 is_postscript_stream(int fd, char *buf, int *len) 466 { 467 if ((*len = read(fd, buf, *len)) < 0) { 468 close(fd); 469 return (-1); 470 } 471 472 if ((strncmp(buf, PS_MAGIC, sizeof (PS_MAGIC) - 1) == 0) || 473 (strncmp(buf, PC_PS_MAGIC, sizeof (PC_PS_MAGIC) - 1) == 0)) 474 return (1); 475 else 476 return (0); 477 } 478 479 int 480 is_postscript(const char *file) 481 { 482 int rc = -1; 483 int fd; 484 485 if ((fd = open(file, O_RDONLY)) >= 0) { 486 char buf[3]; 487 int len = sizeof (buf); 488 489 rc = is_postscript_stream(fd, buf, &len); 490 close(fd); 491 } 492 493 return (rc); 494 } 495 496 static char ** 497 all_list(papi_service_t svc) 498 { 499 papi_status_t status; 500 papi_printer_t printer = NULL; 501 char *list[] = { "member-names", NULL }; 502 char **result = NULL; 503 504 status = papiPrinterQuery(svc, "_all", list, NULL, &printer); 505 if ((status == PAPI_OK) && (printer != NULL)) { 506 papi_attribute_t **attributes = 507 papiPrinterGetAttributeList(printer); 508 if (attributes != NULL) { 509 void *iter = NULL; 510 char *value = NULL; 511 512 for (status = papiAttributeListGetString(attributes, 513 &iter, "member-names", &value); 514 status == PAPI_OK; 515 status = papiAttributeListGetString(attributes, 516 &iter, NULL, &value)) 517 list_append(&result, strdup(value)); 518 } 519 papiPrinterFree(printer); 520 } 521 522 return (result); 523 } 524 525 static char ** 526 printers_list(papi_service_t svc) 527 { 528 papi_status_t status; 529 papi_printer_t *printers = NULL; 530 char *keys[] = { "printer-name", NULL }; 531 char **result = NULL; 532 533 status = papiPrintersList(svc, keys, NULL, &printers); 534 if ((status == PAPI_OK) && (printers != NULL)) { 535 int i; 536 537 for (i = 0; printers[i] != NULL; i++) { 538 papi_attribute_t **attributes = 539 papiPrinterGetAttributeList(printers[i]); 540 char *name = NULL; 541 542 (void) papiAttributeListGetString(attributes, NULL, 543 "printer-name", &name); 544 if ((name != NULL) && (strcmp(name, "_default") != 0)) 545 list_append(&result, strdup(name)); 546 } 547 papiPrinterListFree(printers); 548 } 549 550 return (result); 551 } 552 553 char ** 554 interest_list(papi_service_t svc) 555 { 556 static char been_here; 557 static char **result; 558 559 if (been_here == 0) { /* only do this once */ 560 been_here = 1; 561 562 if ((result = all_list(svc)) == NULL) 563 result = printers_list(svc); 564 } 565 566 return (result); 567 } 568 569 char * 570 localhostname() 571 { 572 static char *result; 573 574 if (result == NULL) { 575 static char buf[256]; 576 577 if (gethostname(buf, sizeof (buf)) == 0) 578 result = buf; 579 } 580 581 return (result); 582 } 583 584 int 585 cli_auth_callback(papi_service_t svc, void *app_data) 586 { 587 char prompt[BUFSIZ]; 588 char *user, *svc_name, *passphrase; 589 590 /* get the name of the service we are contacting */ 591 if ((svc_name = papiServiceGetServiceName(svc)) == NULL) 592 return (-1); 593 594 /* find our who we are supposed to be */ 595 if ((user = papiServiceGetUserName(svc)) == NULL) { 596 struct passwd *pw; 597 598 if ((pw = getpwuid(getuid())) != NULL) 599 user = pw->pw_name; 600 else 601 user = "nobody"; 602 } 603 604 /* build the prompt string */ 605 snprintf(prompt, sizeof (prompt), 606 gettext("passphrase for %s to access %s: "), user, svc_name); 607 608 /* ask for the passphrase */ 609 if ((passphrase = getpassphrase(prompt)) != NULL) 610 papiServiceSetPassword(svc, passphrase); 611 612 return (0); 613 } 614 615 int32_t 616 job_to_be_queried(papi_service_t svc, char *printer, int32_t id) 617 { 618 papi_job_t *jobs = NULL; 619 papi_status_t status; 620 int ret = -1; 621 char *jattrs[] = { "job-id", 622 "job-id-requested", NULL }; 623 624 status = papiPrinterListJobs(svc, printer, jattrs, PAPI_LIST_JOBS_ALL, 625 0, &jobs); 626 627 if (status != PAPI_OK) { 628 fprintf(stderr, gettext("Failed to query service for %s: %s\n"), 629 printer, verbose_papi_message(svc, status)); 630 return (-1); 631 } 632 633 if (jobs != NULL) { 634 int i = 0; 635 636 for (i = 0; jobs[i] != NULL; i++) { 637 int32_t rid = -1; 638 int32_t jid = -1; 639 papi_attribute_t **list = 640 papiJobGetAttributeList(jobs[i]); 641 642 papiAttributeListGetInteger(list, NULL, 643 "job-id-requested", &rid); 644 papiAttributeListGetInteger(list, NULL, 645 "job-id", &jid); 646 647 /* 648 * check if id matches with either rid or jid 649 */ 650 if (rid == id) { 651 /* get the actual id and return it */ 652 papiAttributeListGetInteger(list, NULL, 653 "job-id", &id); 654 return (id); 655 } else if (id == jid) { 656 if (rid != -1) { 657 /* 658 * It is a remote lpd job 659 * can be cancelled only 660 * using rid 661 */ 662 ret = -1; 663 } else { 664 /* 665 * its local or 666 * remote ipp job 667 */ 668 return (id); 669 } 670 } 671 } 672 return (ret); 673 } 674 return (id); 675 } 676