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 /*LINTLIBRARY*/ 29 30 #include <stdio.h> 31 #include <stdarg.h> 32 #include <libintl.h> 33 #include <string.h> 34 #include <stdlib.h> 35 #include <errno.h> 36 37 38 /* lpsched include files */ 39 #include "lp.h" 40 #include "msgs.h" 41 #include "printers.h" 42 #include "class.h" 43 44 #include <papi_impl.h> 45 46 47 /* 48 * Format and send message to lpsched (die if any errors occur) 49 */ 50 /*VARARGS1*/ 51 int 52 snd_msg(service_t *svc, int type, ...) 53 { 54 int rc = -1; 55 va_list ap; 56 57 if (svc == NULL) 58 return (-1); 59 60 /* fill the message buffer */ 61 va_start(ap, type); 62 rc = _putmessage(svc->msgbuf, type, ap); 63 va_end(ap); 64 if (rc < 0) { 65 detailed_error(svc, 66 gettext("unable to build message for scheduler: %s"), 67 strerror(errno)); 68 return (rc); 69 } 70 71 /* write the message */ 72 while (((rc = mwrite(svc->md, svc->msgbuf)) < 0) && (errno == EINTR)) { 73 } 74 75 if (rc < 0) 76 detailed_error(svc, 77 gettext("unable to send message to scheduler: %s"), 78 strerror(errno)); 79 return (rc); 80 } 81 82 /* 83 * Receive message from lpsched (die if any errors occur) 84 */ 85 int 86 rcv_msg(service_t *svc, int type, ...) 87 { 88 int rc = -1; 89 90 if (svc == NULL) 91 return (-1); 92 93 /* read the message */ 94 while (((rc = mread(svc->md, svc->msgbuf, svc->msgbuf_size)) < 0) && 95 (errno == EINTR)) { 96 } 97 98 if (rc < 0) 99 detailed_error(svc, 100 gettext("unable to read message from scheduler: %s"), 101 strerror(errno)); 102 else { 103 va_list ap; 104 105 va_start(ap, type); 106 rc = _getmessage(svc->msgbuf, type, ap); 107 va_end(ap); 108 109 if (rc < 0) 110 detailed_error(svc, 111 gettext("unable to parse message from scheduler: %s"), 112 strerror(errno)); 113 } 114 115 return (rc); 116 } 117 118 papi_status_t 119 lpsched_status_to_papi_status(int status) 120 { 121 switch (status) { 122 case MNOMEM: 123 return (PAPI_TEMPORARY_ERROR); 124 case MNOFILTER: 125 return (PAPI_DOCUMENT_FORMAT_ERROR); 126 case MNOOPEN: 127 return (PAPI_DOCUMENT_ACCESS_ERROR); 128 case MERRDEST: 129 case MDENYDEST: 130 return (PAPI_NOT_ACCEPTING); 131 case MNOMEDIA: 132 return (PAPI_PRINT_SUPPORT_FILE_NOT_FOUND); 133 case MDENYMEDIA: 134 case MNOPERM: 135 return (PAPI_NOT_AUTHORIZED); 136 case MUNKNOWN: 137 case MNODEST: 138 case MNOINFO: 139 return (PAPI_NOT_FOUND); 140 case MTRANSMITERR: 141 return (PAPI_SERVICE_UNAVAILABLE); 142 case M2LATE: 143 return (PAPI_GONE); 144 case MBUSY: 145 return (PAPI_PRINTER_BUSY); 146 case MOK: 147 case MOKMORE: 148 return (PAPI_OK); 149 } 150 151 return (PAPI_INTERNAL_ERROR); 152 } 153 154 char * 155 lpsched_status_string(short status) 156 { 157 switch (status) { 158 case MNOMEM: 159 return (gettext("lpsched: out of memory")); 160 case MNOFILTER: 161 return (gettext("No filter available to convert job")); 162 case MNOOPEN: 163 return (gettext("lpsched: could not open request")); 164 case MERRDEST: 165 return (gettext("queue disabled")); 166 case MDENYDEST: 167 return (gettext("destination denied request")); 168 case MNOMEDIA: 169 return (gettext("unknown form specified in job")); 170 case MDENYMEDIA: 171 return (gettext("access denied to form specified in job")); 172 case MUNKNOWN: 173 return (gettext("no such resource")); 174 case MNODEST: 175 return (gettext("unknown destination")); 176 case MNOPERM: 177 return (gettext("permission denied")); 178 case MNOINFO: 179 return (gettext("no information available")); 180 case MTRANSMITERR: 181 return (gettext("failure to communicate with lpsched")); 182 default: { 183 static char result[16]; 184 185 snprintf(result, sizeof (result), gettext("status: %d"), 186 status); 187 return (result); 188 } 189 } 190 } 191 192 papi_status_t 193 lpsched_alloc_files(papi_service_t svc, int number, char **prefix) 194 { 195 papi_status_t result = PAPI_OK; 196 short status = MOK; 197 198 if ((svc == NULL) || (prefix == NULL)) 199 return (PAPI_BAD_ARGUMENT); 200 201 if ((snd_msg(svc, S_ALLOC_FILES, number) < 0) || 202 (rcv_msg(svc, R_ALLOC_FILES, &status, prefix) < 0)) 203 status = MTRANSMITERR; 204 205 if (status != MOK) { 206 detailed_error(svc, 207 gettext("failed to allocate %d file(s) for request: %s"), 208 number, lpsched_status_string(status)); 209 result = lpsched_status_to_papi_status(status); 210 } 211 212 return (result); 213 } 214 215 papi_status_t 216 lpsched_commit_job(papi_service_t svc, char *job, char **tmp) 217 /* job is host/req-id */ 218 { 219 papi_status_t result = PAPI_OK; 220 short status = MOK; 221 long bits; 222 223 if ((svc == NULL) || (job == NULL) || (tmp == NULL)) 224 return (PAPI_BAD_ARGUMENT); 225 226 if ((snd_msg(svc, S_PRINT_REQUEST, job) < 0) || 227 (rcv_msg(svc, R_PRINT_REQUEST, &status, tmp, &bits) < 0)) 228 status = MTRANSMITERR; 229 230 if (status != MOK) { 231 detailed_error(svc, gettext("failed to commit job (%s): %s"), 232 job, lpsched_status_string(status)); 233 result = lpsched_status_to_papi_status(status); 234 } 235 236 return (result); 237 } 238 239 papi_status_t 240 lpsched_start_change(papi_service_t svc, char *printer, int32_t job_id, 241 char **tmp) 242 { 243 papi_status_t result = PAPI_OK; 244 short status = MOK; 245 char req[BUFSIZ]; 246 char *dest; 247 248 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 249 return (PAPI_BAD_ARGUMENT); 250 251 dest = printer_name_from_uri_id(printer, job_id); 252 snprintf(req, sizeof (req), "%s-%d", dest, job_id); 253 free(dest); 254 255 if ((snd_msg(svc, S_START_CHANGE_REQUEST, req) < 0) || 256 (rcv_msg(svc, R_START_CHANGE_REQUEST, &status, tmp) < 0)) 257 status = MTRANSMITERR; 258 259 if (status != MOK) { 260 detailed_error(svc, 261 gettext("failed to initiate change for job (%s-%d): %s"), 262 printer, 263 job_id, lpsched_status_string(status)); 264 result = lpsched_status_to_papi_status(status); 265 } 266 267 return (result); 268 } 269 270 papi_status_t 271 lpsched_end_change(papi_service_t svc, char *printer, int32_t job_id) 272 { 273 papi_status_t result = PAPI_OK; 274 short status = MOK; 275 long bits; 276 char req[BUFSIZ]; 277 char *dest; 278 279 if ((svc == NULL) || (printer == NULL) || (job_id < 0)) 280 return (PAPI_BAD_ARGUMENT); 281 282 dest = printer_name_from_uri_id(printer, job_id); 283 snprintf(req, sizeof (req), "%s-%d", dest, job_id); 284 free(dest); 285 286 if ((snd_msg(svc, S_END_CHANGE_REQUEST, req) < 0) || 287 (rcv_msg(svc, R_END_CHANGE_REQUEST, &status, &bits) < 0)) 288 status = MTRANSMITERR; 289 290 if (status != MOK) { 291 detailed_error(svc, 292 gettext("failed to commit change for job (%s-%d): %s"), printer, 293 job_id, lpsched_status_string(status)); 294 result = lpsched_status_to_papi_status(status); 295 } 296 297 return (result); 298 } 299 300 papi_status_t 301 lpsched_accept_printer(papi_service_t svc, char *printer) 302 { 303 papi_status_t result = PAPI_OK; 304 short status = MOK; 305 char *req_id; 306 char *dest; 307 308 if ((svc == NULL) || (printer == NULL)) 309 return (PAPI_BAD_ARGUMENT); 310 311 dest = printer_name_from_uri_id(printer, -1); 312 if ((snd_msg(svc, S_ACCEPT_DEST, dest) < 0) || 313 (rcv_msg(svc, R_ACCEPT_DEST, &status, &req_id) < 0)) 314 status = MTRANSMITERR; 315 free(dest); 316 317 if ((status != MOK) && (status != MERRDEST)) { 318 detailed_error(svc, "%s: %s", printer, 319 lpsched_status_string(status)); 320 } 321 result = lpsched_status_to_papi_status(status); 322 323 return (result); 324 } 325 326 papi_status_t 327 lpsched_reject_printer(papi_service_t svc, char *printer, char *message) 328 { 329 papi_status_t result = PAPI_OK; 330 short status = MOK; 331 char *req_id; 332 char *dest; 333 334 if ((svc == NULL) || (printer == NULL)) 335 return (PAPI_BAD_ARGUMENT); 336 337 if (message == NULL) 338 message = "stopped by user"; 339 340 dest = printer_name_from_uri_id(printer, -1); 341 if ((snd_msg(svc, S_REJECT_DEST, dest, message, 0) < 0) || 342 (rcv_msg(svc, R_REJECT_DEST, &status, &req_id) < 0)) 343 status = MTRANSMITERR; 344 free(dest); 345 346 if ((status != MOK) && (status != MERRDEST)) { 347 detailed_error(svc, "%s: %s", printer, 348 lpsched_status_string(status)); 349 } 350 result = lpsched_status_to_papi_status(status); 351 352 return (result); 353 } 354 355 papi_status_t 356 lpsched_enable_printer(papi_service_t svc, char *printer) 357 { 358 papi_status_t result = PAPI_OK; 359 short status = MOK; 360 char *req_id; 361 char *dest; 362 363 if ((svc == NULL) || (printer == NULL)) 364 return (PAPI_BAD_ARGUMENT); 365 366 dest = printer_name_from_uri_id(printer, -1); 367 if ((snd_msg(svc, S_ENABLE_DEST, dest) < 0) || 368 (rcv_msg(svc, R_ENABLE_DEST, &status, &req_id) < 0)) 369 status = MTRANSMITERR; 370 free(dest); 371 372 if ((status != MOK) && (status != MERRDEST)) { 373 detailed_error(svc, "%s: %s", printer, 374 lpsched_status_string(status)); 375 } 376 result = lpsched_status_to_papi_status(status); 377 378 return (result); 379 } 380 381 papi_status_t 382 lpsched_disable_printer(papi_service_t svc, char *printer, char *message) 383 { 384 papi_status_t result = PAPI_OK; 385 short status = MOK; 386 char *req_id; 387 char *dest; 388 389 if ((svc == NULL) || (printer == NULL)) 390 return (PAPI_BAD_ARGUMENT); 391 392 if (message == NULL) 393 message = "stopped by user"; 394 395 dest = printer_name_from_uri_id(printer, -1); 396 if ((snd_msg(svc, S_DISABLE_DEST, dest, message, 0) < 0) || 397 (rcv_msg(svc, R_DISABLE_DEST, &status, &req_id) < 0)) 398 status = MTRANSMITERR; 399 free(dest); 400 401 if ((status != MOK) && (status != MERRDEST)) { 402 detailed_error(svc, "%s: %s", printer, 403 lpsched_status_string(status)); 404 } 405 result = lpsched_status_to_papi_status(status); 406 407 return (result); 408 } 409 410 papi_status_t 411 lpsched_load_unload_dest(papi_service_t handle, char *dest, int type) 412 { 413 service_t *svc = handle; 414 papi_status_t result; 415 short status = MOK; 416 417 /* tell the scheduler it's going */ 418 if (snd_msg(svc, type, dest, "", "") < 0) 419 return (PAPI_SERVICE_UNAVAILABLE); 420 421 switch (type) { 422 case S_LOAD_PRINTER: 423 type = R_LOAD_PRINTER; 424 break; 425 case S_UNLOAD_PRINTER: 426 type = R_UNLOAD_PRINTER; 427 break; 428 case S_LOAD_CLASS: 429 type = R_LOAD_CLASS; 430 break; 431 case S_UNLOAD_CLASS: 432 type = R_UNLOAD_CLASS; 433 } 434 435 if (rcv_msg(svc, type, &status) < 0) 436 return (PAPI_SERVICE_UNAVAILABLE); 437 438 result = lpsched_status_to_papi_status(status); 439 440 return (result); 441 } 442 443 papi_status_t 444 lpsched_remove_class(papi_service_t handle, char *dest) 445 { 446 papi_status_t result; 447 448 /* tell the scheduler it's going */ 449 result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_CLASS); 450 451 if (result == PAPI_OK) { 452 /* remove the scheduler config files */ 453 if (delclass(dest) == -1) 454 result = PAPI_SERVICE_UNAVAILABLE; 455 } 456 457 return (result); 458 } 459 460 static void 461 remove_from_class(papi_service_t handle, char *dest, CLASS *cls) 462 { 463 if (dellist(&cls->members, dest) == 0) { 464 if (cls->members != NULL) { 465 if (putclass(cls->name, cls) == 0) 466 (void) lpsched_load_unload_dest(handle, 467 cls->name, S_LOAD_CLASS); 468 } else 469 (void) lpsched_remove_class(handle, cls->name); 470 } 471 } 472 473 papi_status_t 474 lpsched_remove_printer(papi_service_t handle, char *dest) 475 { 476 477 papi_status_t result; 478 479 /* tell the scheduler it's going */ 480 result = lpsched_load_unload_dest(handle, dest, S_UNLOAD_PRINTER); 481 482 if (result == PAPI_OK) { 483 CLASS *cls; 484 char *dflt; 485 486 /* remove the scheduler config files */ 487 if (delprinter(dest) == -1) 488 return (PAPI_SERVICE_UNAVAILABLE); 489 490 /* remove from any classes */ 491 while ((cls = getclass(NAME_ALL)) != NULL) { 492 if (searchlist(dest, cls->members) != 0) 493 remove_from_class(handle, dest, cls); 494 freeclass(cls); 495 } 496 497 /* reset the default if it needs to be done */ 498 if (((dflt = getdefault()) != NULL) && 499 (strcmp(dflt, dest) == 0)) 500 putdefault(NAME_NONE); 501 } 502 503 return (result); 504 } 505 506 papi_status_t 507 lpsched_add_modify_class(papi_service_t handle, char *dest, 508 papi_attribute_t **attributes) 509 { 510 papi_status_t result; 511 void *iter = NULL; 512 char **members = NULL; 513 char *member; 514 515 /* 516 * The only attribute that we can modify for a class is the set of 517 * members. Anything else will be ignored. 518 */ 519 for (result = papiAttributeListGetString(attributes, &iter, 520 "member-names", &member); 521 result == PAPI_OK; 522 result = papiAttributeListGetString(attributes, &iter, 523 NULL, &member)) 524 addlist(&members, member); 525 526 if (members != NULL) { 527 /* modify the configuration file */ 528 CLASS class; 529 530 memset(&class, 0, sizeof (class)); 531 class.name = dest; 532 class.members = members; 533 534 if (putclass(dest, &class) == -1) { 535 if ((errno == EPERM) || (errno == EACCES)) 536 result = PAPI_NOT_AUTHORIZED; 537 else 538 result = PAPI_NOT_POSSIBLE; 539 } else 540 result = PAPI_OK; 541 542 freelist(members); 543 } else 544 result = PAPI_ATTRIBUTES; 545 546 /* tell the scheduler about the changes */ 547 if (result == PAPI_OK) 548 result = lpsched_load_unload_dest(handle, dest, S_LOAD_CLASS); 549 550 return (result); 551 } 552 553 papi_status_t 554 lpsched_add_printer(papi_service_t handle, char *dest, 555 papi_attribute_t **attributes) 556 { 557 PRINTER *p; 558 papi_status_t result = PAPI_TEMPORARY_ERROR; 559 560 if ((p = calloc(1, sizeof (*p))) != NULL) { 561 p->name = strdup(dest); 562 p->banner = BAN_ALWAYS; 563 p->interface = strdup("/usr/lib/lp/model/uri"); 564 p->fault_alert.shcmd = strdup("mail"); 565 566 attributes_to_printer(attributes, p); 567 568 if (putprinter(dest, p) == -1) { 569 if ((errno == EPERM) || (errno == EACCES)) 570 result = PAPI_NOT_AUTHORIZED; 571 else 572 result = PAPI_NOT_POSSIBLE; 573 } else 574 result = PAPI_OK; 575 576 freeprinter(p); 577 } 578 579 /* tell the scheduler about the changes */ 580 if (result == PAPI_OK) 581 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 582 583 return (result); 584 } 585 586 papi_status_t 587 lpsched_add_modify_printer(papi_service_t handle, char *dest, 588 papi_attribute_t **attributes, int type) 589 { 590 PRINTER *p; 591 papi_status_t result; 592 593 if (type == 0) { 594 if ((p = calloc(1, sizeof (*p))) != NULL) { 595 p->name = strdup(dest); 596 p->banner = BAN_ALWAYS; 597 p->interface = strdup("/usr/lib/lp/model/uri"); 598 p->fault_alert.shcmd = strdup("mail"); 599 } 600 } else 601 p = getprinter(dest); 602 603 if (p != NULL) { 604 attributes_to_printer(attributes, p); 605 606 if (putprinter(dest, p) == -1) { 607 if ((errno == EPERM) || (errno == EACCES)) 608 result = PAPI_NOT_AUTHORIZED; 609 else 610 result = PAPI_NOT_POSSIBLE; 611 } else 612 result = PAPI_OK; 613 614 freeprinter(p); 615 } else 616 result = PAPI_NOT_POSSIBLE; 617 618 /* tell the scheduler about the changes */ 619 if (result == PAPI_OK) 620 result = lpsched_load_unload_dest(handle, dest, S_LOAD_PRINTER); 621 622 return (result); 623 } 624