xref: /illumos-gate/usr/src/cmd/lp/lib/papi/lpsched-msgs.c (revision 98f04078)
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