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
snd_msg(service_t * svc,int type,...)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
rcv_msg(service_t * svc,int type,...)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
lpsched_status_to_papi_status(int status)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 *
lpsched_status_string(short status)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
lpsched_alloc_files(papi_service_t svc,int number,char ** prefix)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
lpsched_commit_job(papi_service_t svc,char * job,char ** tmp)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
lpsched_start_change(papi_service_t svc,char * printer,int32_t job_id,char ** tmp)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
lpsched_end_change(papi_service_t svc,char * printer,int32_t job_id)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
lpsched_accept_printer(papi_service_t svc,char * printer)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
lpsched_reject_printer(papi_service_t svc,char * printer,char * message)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
lpsched_enable_printer(papi_service_t svc,char * printer)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
lpsched_disable_printer(papi_service_t svc,char * printer,char * message)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
lpsched_load_unload_dest(papi_service_t handle,char * dest,int type)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
lpsched_remove_class(papi_service_t handle,char * dest)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
remove_from_class(papi_service_t handle,char * dest,CLASS * cls)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
lpsched_remove_printer(papi_service_t handle,char * dest)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
lpsched_add_modify_class(papi_service_t handle,char * dest,papi_attribute_t ** attributes)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
lpsched_add_printer(papi_service_t handle,char * dest,papi_attribute_t ** attributes)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
lpsched_add_modify_printer(papi_service_t handle,char * dest,papi_attribute_t ** attributes,int type)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