xref: /illumos-gate/usr/src/cmd/lp/cmd/lpsched/disp3.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28 /*	  All Rights Reserved  	*/
29 
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #include "dispatch.h"
34 #include <syslog.h>
35 
36 /**
37  ** remount_form() - MOUNT A FORM WHERE ANOTHER WAS MOUNTED
38  **/
39 
40 void
41 remount_form(register PSTATUS *pps, FSTATUS *pfs, short trayNum)
42 {
43 	trayNum--; /* make zero based */
44 	if (pps->forms && (pps->forms[trayNum].form == pfs)) {
45 		pps->forms[trayNum].isAvailable = (pfs ? 1 : 0);
46 					 /* force it */
47 		return;	/* nothing to do */
48 	} else if ((!pps->forms) && (!pfs)) {
49 		return;	/* nothing to do */
50 	}
51 
52 	/*
53 	 * Unmount the old form.
54 	 */
55 	if (pps->forms && pps->forms[trayNum].form) {
56 		register FSTATUS	*Opfs	= pps->forms[trayNum].form;
57 
58 		pps->forms[trayNum].form = 0;
59 		pps->forms[trayNum].isAvailable = 0;
60 		Opfs->mounted--;
61 
62 		/*
63 		 * Unmounting the form may make some print requests
64 		 * no longer printable, because they were accepted
65 		 * only because the form was already mounted.
66 		 * Unmounting the form will also force some requests
67 		 * to another printer (where the form is mounted)
68 		 * so they can print.
69 		 */
70 		form_in_question = Opfs;
71 		(void)queue_repel (pps, 0, qchk_form);
72 
73 		/*
74 		 * Maybe an alert is due.
75 		 */
76 		check_form_alert (Opfs, (_FORM *)0);
77 	}
78 
79 	/*
80 	 * Mount the new form?
81 	 */
82 	if (pfs) {
83 		syslog(LOG_DEBUG, "remount_form add %x(%s) to tray %d\n",
84 			 pfs, (pfs ? pfs->form->name : "NULL"), trayNum);
85 
86 		if (pps && !pps->forms) {
87                         pps->forms = (PFSTATUS *)calloc((trayNum +1),
88 							sizeof(PFSTATUS));
89 			pps->numForms = trayNum + 1;
90 		}
91 
92 		if (pps && pps->forms && (pps->numForms > trayNum)) {
93 			pps->forms[trayNum].form = pfs;
94 			pps->forms[trayNum].isAvailable = 1;
95 			pfs->mounted++;
96 		} else {
97 			return; /* nothing to do, can't mount form,
98 				   so no need to pretend we did */
99 		}
100 
101 
102 		/*
103 		 * Attract all the requests needing this newly mounted
104 		 * form. This may cause some unnecessary shuffling, but
105 		 * we have to ensure requests aren't assigned to a printer
106 		 * without the form mounted, so that the alert check is
107 		 * correct.
108 		 */
109 		if (pfs->requests) {
110 			form_in_question = pfs;
111 			queue_attract (pps, qchk_form, 0);
112 
113 			/*
114 			 * Maybe an alert can be shut off.
115 			 */
116 			check_form_alert (pfs, (_FORM *)0);
117 		}
118 
119 	} else {
120 		/*
121 		 * Attract first request that doesn't need a form mounted.
122 		 * We only need to get one request printing, because it
123 		 * completing will cause the next request to be attracted.
124 		 */
125 		form_in_question = 0;
126 		queue_attract (pps, qchk_form, 1);
127 	}
128 
129 	dump_pstatus ();
130 
131 	return;
132 }
133 
134 /**
135  ** remount_pwheel() - MOUNT A PRINT-WHEEL WHERE ANOTHER WAS MOUNTED
136  **/
137 
138 static void
139 remount_pwheel(register PSTATUS *pps, char *pwheel_name)
140 {
141 	PWSTATUS		*ppws;
142 
143 	if (SAME(pps->pwheel_name, pwheel_name))
144 		return;	/* nothing to do */
145 
146 	/*
147 	 * Unmount the old print wheel
148 	 */
149 	if (pps->pwheel_name) {
150 		register PWSTATUS	*Oppws	= pps->pwheel;
151 
152 		pps->pwheel = 0;
153 		if (Oppws)
154 			Oppws->mounted--;
155 
156 		/*
157 		 * Unmounting the print wheel may make some print
158 		 * requests no longer printable, because they were
159 		 * accepted only because the print wheel was already
160 		 * mounted. Unmounting the print wheel will also force
161 		 * some requests to another printer (where the print wheel
162 		 * is mounted) so they can print.
163 		 */
164 		pwheel_in_question = pps->pwheel_name;
165 		(void)queue_repel (pps, 0, qchk_pwheel);
166 
167 		unload_str (&pps->pwheel_name);
168 
169 		/*
170 		 * Maybe an alert is due.
171 		 */
172 		if (Oppws)
173 			check_pwheel_alert (Oppws, (PWHEEL *)0);
174 	}
175 
176 	/*
177 	 * Mount the new print wheel?
178 	 */
179 	if (pwheel_name) {
180 		load_str (&pps->pwheel_name, pwheel_name);
181 		if (ppws = search_pwstatus(pwheel_name)) {
182 			pps->pwheel = ppws;
183 			ppws->mounted++;
184 
185 			/*
186 			 * Attract all requests needing this newly
187 			 * mounted print wheel. This may cause some
188 			 * unnecessary shuffling, but we have to ensure
189 			 * requests aren't assigned to a printer without
190 			 * the print-wheel mounted, so that the alert
191 			 * check is correct.
192 			 */
193 			if (ppws->requests) {
194 				pwheel_in_question = pwheel_name;
195 				queue_attract (pps, qchk_pwheel, 0);
196 
197 				/*
198 				 * Maybe an alert can be shut off.
199 				 */
200 				check_pwheel_alert (ppws, (PWHEEL *)0);
201 			}
202 
203 		} else {
204 			/*
205 			 * Attract the first request that needs this newly
206 			 * mounted print wheel. If no alert has been
207 			 * defined for the print wheel, we don't know how
208 			 * many requests are queued waiting for it, so we
209 			 * have to do this unconditionally.
210 			 */
211 			pwheel_in_question = pwheel_name;
212 			queue_attract (pps, qchk_pwheel, 1);
213 		}
214 
215 	} else {
216 		/*
217 		 * Attract the first request that doesn't need a
218 		 * print wheel mounted.
219 		 * We only need to get one request printing, because it
220 		 * completing will cause the next request to be attracted.
221 		 */
222 		pwheel_in_question = 0;
223 		queue_attract (pps, qchk_pwheel, 1);
224 	}
225 
226 	dump_pstatus ();
227 
228 	return;
229 }
230 
231 #define MAX_TRAYS 100
232 
233 /**
234  ** s_max_trays()
235  **/
236 
237 void
238 s_max_trays(char *m, MESG *md)
239 {
240 	char			*printer;
241 	ushort			status;
242 	short numTrays;
243 	register PSTATUS	*pps;
244 	register PFSTATUS	*ppfs;
245 
246 	(void) getmessage(m, S_MAX_TRAYS, &printer, &numTrays);
247 	syslog(LOG_DEBUG, "s_max_trays(%s, %d)", (printer ? printer : "NULL"),
248 	       numTrays);
249 
250 	/* Have we seen this printer before? */
251 	if (!*printer || !(pps = search_pstatus(printer)))
252 		status = MNODEST;
253 
254 	/* How about the tray? */
255 	else if ((numTrays <=0) || (numTrays > MAX_TRAYS))
256 		status = MNOTRAY;
257 
258 	/* If the printer is currently printing, we can't disturb it. */
259 	else if (pps->request)
260 		    status = MBUSY;
261 
262 	else if (pps->forms) {
263 		if (!(ppfs = Realloc(pps->forms,numTrays * sizeof(PFSTATUS))))
264 			status = MNOMEM;
265 		else {
266 			int i;
267 
268 			for (i = pps->numForms; i < numTrays; i++) {
269 				ppfs[i].form = NULL;
270 				ppfs[i].isAvailable = 0;
271 			}
272 			pps->forms = ppfs;
273 			pps->numForms = numTrays;
274 			status = MOK;
275 		}
276 	} else if (!(ppfs = Calloc(numTrays,sizeof(PFSTATUS)))) {
277 		status = MNOMEM;
278 	} else  {
279 		pps->forms = ppfs;
280 		pps->numForms = numTrays;
281 		status = MOK;
282 	}
283 	dump_pstatus();
284 	mputm(md, R_MAX_TRAYS, status);
285 }
286 
287 /**
288  ** s_mount()
289  **/
290 
291 void
292 s_mount(char *m, MESG *md)
293 {
294 	char			*printer, *form, *pwheel_name;
295 	ushort			status;
296 	register PSTATUS	*pps;
297 	register FSTATUS	*pfs;
298 
299 	(void) getmessage(m, S_MOUNT, &printer, &form, &pwheel_name);
300 	syslog(LOG_DEBUG, "s_mount(%s, %s, %s)", (printer ? printer : "NULL"),
301 	       (form ? form : "NULL"), (pwheel_name ? pwheel_name : "NULL"));
302 
303 	if (!*form && !*pwheel_name)
304 		status = MNOMEDIA;
305 
306 	/* Have we seen this printer before? */
307 	else if (!*printer || !(pps = search_pstatus(printer)))
308 		status = MNODEST;
309 
310 	/* How about the form? */
311 	else if (*form && !(pfs = search_fstatus(form)))
312 		status = MNOMEDIA;
313 
314 	/* If the printer is currently printing, we can't disturb it. */
315 	else if (pps->request)
316 		    status = MBUSY;
317 
318 	else {
319 		/*
320 		 * Mount them.
321 		 */
322 		if (*form)
323 			remount_form (pps, pfs,1);
324 		if (*pwheel_name)
325 			remount_pwheel(pps, pwheel_name);
326 
327 		status = MOK;
328 	}
329 
330 	mputm(md, R_MOUNT, status);
331 }
332 
333 /*
334  * s_mount_tray()
335  */
336 
337 void
338 s_mount_tray(char *m, MESG *md)
339 {
340 	char			*printer, *form, *pwheel_name;
341 	ushort			status;
342 	short			trayNum;
343 	register PSTATUS	*pps;
344 	register FSTATUS	*pfs;
345 
346 	(void) getmessage(m, S_MOUNT_TRAY, &printer, &form, &pwheel_name,
347 		&trayNum);
348 	syslog(LOG_DEBUG, "s_mount_tray(%s, %s, %s, %d)",
349 	       (printer ? printer : "NULL"), (form ? form : "NULL"),
350 	       (pwheel_name ? pwheel_name : "NULL"), trayNum);
351 
352 	if (!*form && !*pwheel_name)
353 		status = MNOMEDIA;
354 
355 	/* Have we seen this printer before? */
356 	else if (!*printer || !(pps = search_pstatus(printer)))
357 		status = MNODEST;
358 
359 	/* How about the form? */
360 	else if (*form && !(pfs = search_fstatus(form)))
361 		status = MNOMEDIA;
362 
363 	/* How about the tray? */
364 	else if ((trayNum <=0) || (trayNum > pps->numForms))
365 		status = MNOTRAY;
366 
367 	/* If the printer is currently printing, we can't disturb it. */
368 	else if (pps->request)
369 		    status = MBUSY;
370 
371 	else {
372 		/*
373 		 * Mount them.
374 		 */
375 		if (*form)
376 			remount_form(pps, pfs,trayNum);
377 		if (*pwheel_name)
378 			remount_pwheel(pps, pwheel_name);
379 
380 		status = MOK;
381 	}
382 
383 	mputm (md, R_MOUNT_TRAY, status);
384 }
385 
386 /**
387  ** s_unmount()
388  **/
389 
390 void
391 s_unmount(char *m, MESG *md)
392 {
393 	char			*printer,
394 				*form,
395 				*pwheel_name;
396 	ushort			status;
397 	register PSTATUS	*pps;
398 
399 	(void)getmessage (m, S_UNMOUNT, &printer, &form, &pwheel_name);
400 	syslog(LOG_DEBUG, "s_unmount(%s, %s, %s)",
401 	       (printer ? printer : "NULL"), (form ? form : "NULL"),
402 	       (pwheel_name ? pwheel_name : "NULL"));
403 
404 	if (!*form && !*pwheel_name)
405 		status = MNOMEDIA;
406 
407 	/*
408 	 * Have we seen this printer before?
409 	 */
410 	else if (!*printer || !(pps = search_pstatus(printer)))
411 		status = MNODEST;
412 
413 
414 	/*
415 	 * If the printer is currently printing a request,
416 	 * we can't unmount the current form/pwheel.
417 	 */
418 	else if (pps->request)
419 		status = MBUSY;
420 
421 	else {
422 		/*
423 		 * Unmount them.
424 		 */
425 		if (*form)
426 			remount_form (pps, (FSTATUS *)0,1);
427 		if (*pwheel_name)
428 			remount_pwheel (pps, (char *)0);
429 
430 		status = MOK;
431 	}
432 
433 	mputm (md, R_UNMOUNT, status);
434 	return;
435 }
436 /**
437  ** s_unmount_tray()
438  **/
439 
440 void
441 s_unmount_tray(char *m, MESG *md)
442 {
443 	char			*printer,
444 				*form,
445 				*pwheel_name;
446 
447 	ushort			status;
448 	short			trayNum;
449 
450 	register PSTATUS	*pps;
451 
452 	(void)getmessage (m, S_UNMOUNT_TRAY, &printer, &form, &pwheel_name,
453 		&trayNum);
454 	syslog(LOG_DEBUG, "s_unmount_tray(%s, %s, %s, %d)",
455 	       (printer ? printer : "NULL"), (form ? form : "NULL"),
456 	       (pwheel_name ? pwheel_name : "NULL"), trayNum);
457 
458 
459 	if (!*form && !*pwheel_name)
460 		status = MNOMEDIA;
461 
462 	else if (!*printer || !(pps = search_pstatus(printer)))
463 		/* haven't seen this printer before */
464 		status = MNODEST;
465 	else if ((trayNum <=0) || (trayNum > pps->numForms))
466 		/* haven't seen the tray before */
467 		status = MNOTRAY;
468 	else if (pps->request)
469 		/* is the printer busy */
470 		status = MBUSY;
471 	else {
472 		/* Unmount them. */
473 		if (*form)
474 			remount_form (pps, (FSTATUS *)0,trayNum);
475 		if (*pwheel_name)
476 			remount_pwheel (pps, (char *)0);
477 
478 		status = MOK;
479 	}
480 
481 	mputm (md, R_UNMOUNT_TRAY, status);
482 	return;
483 }
484 
485 /**
486  ** s_load_form()
487  **/
488 
489 void
490 s_load_form(char *m, MESG *md)
491 {
492 	char			*form;
493 	ushort			status;
494 	register _FORM		*pf;
495 	register FSTATUS	*pfs;
496 
497 	(void)getmessage (m, S_LOAD_FORM, &form);
498 	syslog(LOG_DEBUG, "s_load_form(%s)", (form ? form : "NULL"));
499 
500 	if (!*form)
501 		/* no form specified */
502 		status = MNODEST;
503 	else if (!(pf = Getform(form))) {
504 		/* strange or missing form */
505 		switch (errno) {
506 		case EBADF:
507 			status = MERRDEST;
508 			break;
509 		case ENOENT:
510 		default:
511 			status = MNODEST;
512 			break;
513 		}
514 
515 	} else if ((pfs = search_fstatus(form))) {
516 		/* Have we seen this form before? */
517 		unload_list (&pfs->users_allowed);
518 		unload_list (&pfs->users_denied);
519 		load_userform_access (
520 			pf->name,
521 			&pfs->users_allowed,
522 			&pfs->users_denied
523 		);
524 
525 		load_sdn (&pfs->cpi, pf->cpi);
526 		load_sdn (&pfs->lpi, pf->lpi);
527 		load_sdn (&pfs->plen, pf->plen);
528 		load_sdn (&pfs->pwid, pf->pwid);
529 
530 
531 		/*
532 		 * These have to be done in the order shown,
533 		 * and after the assignments above, so that all
534 		 * the new information is in place for the
535 		 * checks. An unfortunate side effect is that
536 		 * it is possible for the alert to shut off
537 		 * and then come on again, if (1) enough requests
538 		 * are canceled to drop the level below the old
539 		 * alert threshold, but (2) the new alert threshold
540 		 * is even lower. The final alert will be correct,
541 		 * though.
542 		 */
543 
544 		form_in_question = pfs;
545 		queue_check (qchk_form);
546 
547 		check_form_alert (pfs, pf);
548 
549 
550 		status = MOK;
551 
552 	/*
553 	 * Room for a new form?
554 	 */
555 	} else if ((pfs = new_fstatus(pf))) {
556 		/*
557 		 * No alert is possible for a new form, of course,
558 		 * but this routine does a bit more than just check
559 		 * the alert.
560 		 */
561 		check_form_alert (pfs, pf);
562 		status = MOK;
563 	} else {
564 		free_form (pf);
565 		status = MNOSPACE;
566 	}
567 
568 	mputm (md, R_LOAD_FORM, status);
569 	return;
570 }
571 
572 /**
573  ** s_unload_form()
574  **/
575 
576 static void
577 _unload_form(register FSTATUS *pfs)
578 {
579 	int i;
580 	short numForms;
581 	PFSTATUS *ppfs;
582 
583 	/*
584 	 * Unmount this form everywhere and get rid of it.
585 	 */
586 	for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
587 		if (((ppfs = PStatus[i]->forms) != NULL) &&
588 		    ((numForms = PStatus[i]->numForms) > 0)) {
589 			int j;
590 			for ( j = 0 ; j < numForms ; j++ )
591 				if (ppfs[j].form == pfs) ppfs[j].form= NULL;
592 		}
593 
594 	return;
595 }
596 
597 void
598 s_unload_form(char *m, MESG *md)
599 {
600 	char			*form;
601 	ushort			status;
602 	RSTATUS			*prs;
603 	register FSTATUS	*pfs;
604 
605 	(void)getmessage (m, S_UNLOAD_FORM, &form);
606 	syslog(LOG_DEBUG, "s_unload_form(%s)", (form ? form : "NULL"));
607 
608 	if (!*form || STREQU(form, NAME_ALL)) {
609 		int i;
610 		/* If we have a request queued for ANY form, we can't do it. */
611 		status = MOK;
612 		for (i = 0; FStatus != NULL && FStatus[i] != NULL &&
613 			    status == MOK; i++) {
614 			for (prs = Request_List; prs != NULL; prs = prs->next)
615 				if (prs->form == FStatus[i]) {
616 					status = MBUSY;
617 					break;
618 				}
619 		}
620 
621 		if (status == MOK) {
622 			for (i = 0; FStatus != NULL && FStatus[i] != NULL; i++)
623 				_unload_form (FStatus[i]);
624 			free(FStatus);
625 			FStatus = NULL;
626 		}
627 
628 	} else if (!*form || !(pfs = search_fstatus(form)))
629 		/* Have we seen this form before? */
630 		status = MNODEST;
631 	else {
632 		/* Is there even one request waiting for this form? */
633 		status = MOK;
634 		for (prs = Request_List; prs != NULL; prs = prs->next)
635 			if (prs->form == pfs) {
636 				status = MBUSY;
637 				break;
638 			}
639 
640 		if (status == MOK) {
641 			_unload_form (pfs);
642 			list_remove((void ***)&FStatus, (void *)pfs);
643 		}
644 	}
645 
646 	mputm (md, R_UNLOAD_FORM, status);
647 	return;
648 }
649 
650 /**
651  ** s_load_printwheel()
652  **/
653 
654 void
655 s_load_printwheel(char *m, MESG *md)
656 {
657 	char			*pwheel_name;
658 	ushort			status;
659 	register PWHEEL		*ppw;
660 	register PWSTATUS	*ppws;
661 
662 	(void)getmessage (m, S_LOAD_PRINTWHEEL, &pwheel_name);
663 	syslog(LOG_DEBUG, "s_load_printwheel(%s)",
664 	       (pwheel_name ? pwheel_name : "NULL"));
665 
666 	if (!*pwheel_name)
667 		/* no printwheel specified */
668 		status = MNODEST;
669 	else if (!(ppw = Getpwheel(pwheel_name))) {
670 		/* Strange or missing print wheel? */
671 		switch (errno) {
672 		case EBADF:
673 			status = MERRDEST;
674 			break;
675 		case ENOENT:
676 		default:
677 			status = MNODEST;
678 			break;
679 		}
680 	} else if ((ppws = search_pwstatus(pwheel_name))) {
681 		/* Print wheel we already know about? */
682 		check_pwheel_alert (ppws, ppw);
683 		status = MOK;
684 	} else if ((ppws = new_pwstatus(ppw))) {
685 		/* Room for a new print wheel? */
686 		register RSTATUS 	*prs;
687 
688 		/*
689 		 * Because of the quirky nature of the print wheel
690 		 * structures, i.e. no structure unless an alert has
691 		 * been defined, we have to run through the requests
692 		 * and see which ones are waiting for this print wheel,
693 		 * so we can assign alerts and count pending requests.
694 		 */
695 		for (prs = Request_List; prs != NULL; prs = prs->next)
696 			if ((prs->pwheel_name == pwheel_name) &&
697 			    (!one_printer_with_charsets(prs))) {
698 				prs->pwheel = ppws;
699 				ppws->requests++;
700 			}
701 		check_pwheel_alert (ppws, ppw);
702 
703 		status = MOK;
704 	} else {
705 		freepwheel (ppw);
706 		status = MNOSPACE;
707 	}
708 
709 	mputm (md, R_LOAD_PRINTWHEEL, status);
710 	return;
711 }
712 
713 /**
714  ** s_unload_printwheel()
715  **/
716 
717 static void
718 _unload_pwheel(register PWSTATUS *ppws)
719 {
720 	register PSTATUS		*pps;
721 	register RSTATUS		*prs;
722 	int i;
723 
724 
725 	/*
726 	 * ``Unmount'' the alert part of this print wheel everywhere.
727 	 * THIS IS NOT A COMPLETE UNMOUNT, JUST THE ALERT STRUCTURE
728 	 * IS REMOVED.
729 	 */
730 	for (i = 0; PStatus != NULL && PStatus[i] != NULL; i++)
731 		if (PStatus[i]->pwheel == ppws)
732 			PStatus[i]->pwheel = 0;
733 
734 	/*
735 	 * Remove the alert part from all requests.
736 	 */
737 	for (prs = Request_List; prs; prs = prs->next)
738 		if (prs->pwheel == ppws)
739 			prs->pwheel = 0;
740 
741 	/*
742 	 * Cancel any alert pending. Here we're different from the
743 	 * similar code for unloading a form, because, to be able to
744 	 * unload a form we first require NO requests pending. If no
745 	 * requests are pending there should be no alert to cancel.
746 	 * Print wheels, on the other hand, only exist as names and
747 	 * alerts. We can always unload a ``print wheel'' because
748 	 * all we're really unloading is an alert. Thus, there can
749 	 * be requests queued for the print wheel (the name), and
750 	 * thus there can be an alert running.
751 	 */
752 	if (ppws->alert->active)
753 		cancel_alert (A_PWHEEL, ppws);
754 
755 	free_pwstatus(ppws);
756 
757 	return;
758 }
759 
760 void
761 s_unload_printwheel(char *m, MESG *md)
762 {
763 	char			*pwheel_name;
764 
765 	ushort			status;
766 
767 	register PWSTATUS	*ppws;
768 
769 
770 	/*
771 	 * We don't care if any requests are waiting for the print
772 	 * wheel(s)--what we're removing here is (are) just the alert(s)!
773 	 */
774 
775 	(void)getmessage (m, S_UNLOAD_PRINTWHEEL, &pwheel_name);
776 	syslog(LOG_DEBUG, "s_unload_printwheel(%s)",
777 	       (pwheel_name ? pwheel_name : "NULL"));
778 
779 
780 	/*
781 	 * Remove all print wheel alerts?
782 	 */
783 	if (!*pwheel_name || STREQU(pwheel_name, NAME_ALL)) {
784 		int i;
785 
786 		for (i = 0; PWStatus != NULL && PWStatus[i] != NULL; i++)
787 			_unload_pwheel (PWStatus[i]);
788 		free(PWStatus);
789 		PWStatus = NULL;
790 		status = MOK;
791 
792 	/*
793 	 * Have we seen this print wheel before?
794 	 */
795 	} else if (!(ppws = search_pwstatus(pwheel_name)))
796 		status = MNODEST;
797 
798 	else {
799 		_unload_pwheel (ppws);
800 		list_remove((void ***)&PWStatus, (void *)ppws);
801 		status = MOK;
802 
803 	}
804 
805 	mputm (md, R_UNLOAD_PRINTWHEEL, status);
806 	return;
807 }
808