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