Home | History | Annotate | Download | only in lpsched
      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