1 #include	"qpage.h"
2 
3 
4 /*
5 ** global variables
6 */
7 #ifndef lint
8 static char	sccsid[] = "@(#)queue.c  1.22  07/07/98  tomiii@qpage.org";
9 #endif
10 
11 
12 /*
13 ** insert_jobs()
14 **
15 ** This function inserts a page into the job list.  Since each page
16 ** may contain multiple recipients each with a possibly different
17 ** paging service, each recipient is considered a separate job.  The
18 ** job list is sorted first by service name and then by level within
19 ** each service.  This allows all pages for a particular service to
20 ** be sent with one phone call (if possible).  Note that each job
21 ** simply contains pointers to the respective elements of a page
22 ** structure.  Therefore, a job in this context does not actually
23 ** contain any data, only pointers to data.
24 **
25 **	Input:
26 **		joblist - a pointer to the head node in the list
27 **		p - the new page to be added to the list.
28 **
29 **	Returns:
30 **		the number of pending jobs in the specified page
31 **
32 **	Note:
33 **		Jobs scheduled for the future (i.e. seen here but
34 **		not added to the job list) are counted in the number
35 **		returned by this function.
36 */
37 int
insert_jobs(job_t ** joblist,PAGE * p)38 insert_jobs(job_t **joblist, PAGE *p)
39 {
40 	job_t		*curr;
41 	job_t		*prev;
42 	job_t		*tmp;
43 	rcpt_t		*rcpt;
44 	service_t	*service;
45 	pager_t		*pager;
46 	int		jobcount;
47 	int		i;
48 
49 
50 	jobcount = 0;
51 
52 	for (rcpt=p->rcpts; rcpt; rcpt=rcpt->next) {
53 		/*
54 		** skip pages we've already sent
55 		*/
56 		if (rcpt->flags & F_SENT)
57 			continue;
58 
59 		/*
60 		** skip pages which are scheduled for the future
61 		*/
62 		if (rcpt->holduntil > time(NULL)) {
63 			if (Debug || Interactive)
64 				qpage_log(LOG_DEBUG, "skipping %s until %s",
65 					rcpt->pager,
66 					my_ctime(&rcpt->holduntil));
67 
68 			jobcount++;
69 			continue;
70 		}
71 
72 		pager = lookup(Pagers, rcpt->pager);
73 
74 		/*
75 		** If this is a raw pagerid we need to kludge something
76 		*/
77 		if (pager == NULL && (rcpt->flags & F_RAWPID)) {
78 			pager = (void *)malloc(sizeof(*pager));
79 			(void)memset((char *)pager, 0, sizeof(*pager));
80 			pager->name = strdup(rcpt->pager);
81 			pager->pagerid = strdup(rcpt->pager);
82 			pager->flags = rcpt->flags;
83 		}
84 
85 		/*
86 		** "pager" better not be NULL at this point
87 		*/
88 		if (pager == NULL) {
89 			qpage_log(LOG_ERR, "no such pager %s", rcpt->pager);
90 			continue;
91 		}
92 
93 		/*
94 		** If they specified a coverage, use it, otherwise
95 		** use the default coverage for this pager.
96 		*/
97 		if (rcpt->coverage)
98 			service = lookup(Services, rcpt->coverage);
99 		else
100 			service = pager->service;
101 
102 		if (service == NULL) {
103 			qpage_log(LOG_ERR, "no such service %s",
104 				rcpt->coverage);
105 
106 			continue;
107 		}
108 
109 #ifdef REJECT_IS_FAILURE
110 		/*
111 		** do not retry rejected pages
112 		*/
113 		if (rcpt->flags & F_REJECT) {
114 			rcpt->flags |= F_FAILED;
115 			continue;
116 		}
117 #endif
118 
119 		/*
120 		** limit retries to the number specified by the paging service
121 		*/
122 		if (rcpt->goodtries >= service->maxtries) {
123 			rcpt->flags |= F_FAILED;
124 
125 			qpage_log(LOG_ERR, "too many retries for %s in %s",
126 					rcpt->pager, p->filename);
127 
128 			continue;
129 		}
130 
131 		/*
132 		** build a new job for this recipient
133 		*/
134 		tmp = (void *)malloc(sizeof(*tmp));
135 		tmp->next = NULL;
136 		tmp->p = p;
137 		tmp->rcpt = rcpt;
138 		tmp->service = service;
139 		tmp->pager = pager;
140 
141 		if (Debug) {
142 			qpage_log(LOG_DEBUG, "pager=%s, pagerid=%s, service=%s",
143 				pager->name, pager->pagerid, service->name);
144 		}
145 
146 		curr = *joblist;
147 		prev = NULL;
148 
149 		/*
150 		** Scan through the job list to find an appropriate
151 		** place to insert this recipient.
152 		*/
153 		while (curr) {
154 			i = strcmp(curr->service->name, tmp->service->name);
155 
156 			if (i == 0)
157 				i = curr->rcpt->level - tmp->rcpt->level;
158 
159 			if (i == 0)
160 				i = curr->p->created - tmp->p->created;
161 
162 			if (i>0)
163 				break;
164 
165 			prev = curr;
166 			curr = curr->next;
167 		}
168 
169 		if (prev == NULL) {
170 			/*
171 			** insert the job at the beginning of the list
172 			*/
173 			tmp->next = *joblist;
174 			*joblist = tmp;
175 		}
176 		else {
177 			/*
178 			** insert the job somewhere after the first node
179 			*/
180 			tmp->next = prev->next;
181 			prev->next = tmp;
182 		}
183 
184 		jobcount++;
185 	}
186 
187 	/*
188 	** At this point, a jobcount of zero means all the recipients
189 	** of this page fall into one of these two categories:
190 	**
191 	**	- we already successfully sent the page
192 	**	- we failed to send the page and we should stop trying
193 	**
194 	** If there are no valid jobs here now, there won't be any in
195 	** the future so let's nuke this page.
196 	*/
197 	if (jobcount == 0)
198 		p->flags |= F_BADPAGE;
199 
200 	return(jobcount);
201 }
202 
203 
204 /*
205 ** read_page()
206 **
207 ** This function reads a page from the page queue.
208 **
209 **	Input:
210 **		file - the filename to read from
211 **
212 **	Returns:
213 **		a page structure, or NULL on failure
214 */
215 PAGE *
read_page(char * file)216 read_page(char *file)
217 {
218 	rcpt_t		*tmp;
219 	FILE		*fp;
220 	PAGE		*p;
221 	time_t		holduntil;
222 	time_t		lasttry;
223 	char		keyword[255];
224 	char		coverage[255];
225 	char		status[255];
226 	char		name[255];
227 	char		msgid[255];
228 	char		hostname[257];
229 	char		*buf;
230 	char		*ptr;
231 	int		tries;
232 	int		goodtries;
233 	int		version;
234 	int		buflen;
235 	int		gotmarker;
236 	int		line;
237 	int		level;
238 	int		flags;
239 	int		bytes;
240 	int		n;
241 
242 
243 	gotmarker = 0;
244 	line = 0;
245 	coverage[0] = '\0';
246 	level = DEFAULT_LEVEL;
247 	holduntil = 0;
248 	lasttry = 0;
249 	flags = 0;
250 	tries = 0;
251 	goodtries = 0;
252 
253 	if ((fp = fopen(file, "r")) == NULL) {
254 		qpage_log(LOG_NOTICE, "cannot open file %s for reading", file);
255 		return(NULL);
256 	}
257 
258 	if (lock_file(fileno(fp), O_RDONLY, TRUE) < 0) {
259 		qpage_log(LOG_ERR, "cannot lock %s: %s", file,
260 			strerror(errno));
261 
262 		return(NULL);
263 	}
264 
265 	p = (void *)malloc(sizeof(*p));
266 	(void)memset((char *)p, 0, sizeof(*p));
267 
268 	buf = (void *)malloc(BUFCHUNKSIZE);
269 	buflen = BUFCHUNKSIZE;
270 
271 	while (fgets(buf, buflen, fp)) {
272 		line++;
273 
274 		if ((ptr = strchr(buf, '\n')) == NULL) {
275 			qpage_log(LOG_ERR,
276 				"short read (this should never happen)");
277 		}
278 		else
279 			*ptr = '\0';
280 
281 		if (sscanf(buf, "%s %n", keyword, &n) != 1) {
282 			qpage_log(LOG_ERR,
283 				"no keyword (this should never happen)");
284 
285 			continue;
286 		}
287 
288 		switch (keyword[0]) {
289 			case '#': /* comment */
290 				break;
291 
292 			case '-': /* end-of-recipients marker */
293 				gotmarker++;
294 				break;
295 
296 			case 'B': /* bytes (size of message) */
297 				(void)sscanf(&buf[n], "%d", &bytes);
298 				if (bytes > buflen) {
299 					buf = (void *)realloc(buf, bytes);
300 					buflen = bytes;
301 				}
302 				break;
303 
304 			case 'C': /* created/coverage */
305 				if (gotmarker) {
306 					(void)sscanf(&buf[n], "%ld",
307 						&p->created);
308 				}
309 				else {
310 					(void)sscanf(&buf[n], "%s", coverage);
311 				}
312 				break;
313 
314 			case 'F': /* from/flags */
315 				if (gotmarker) {
316 					/*
317 					** We can't use sscanf() here
318 					** because there may be embedded
319 					** whitespace in the CALLerid
320 					** information.
321 					*/
322 					while (buf[n] && isspace(buf[n]))
323 						n++;
324 
325 					p->from = strdup(&buf[n]);
326 				}
327 				else {
328 					(void)sscanf(&buf[n], "%d", &flags);
329 				}
330 				break;
331 
332 			case 'G': /* goodtries */
333 				(void)sscanf(&buf[n], "%d", &goodtries);
334 				break;
335 
336 			case 'H': /* hostname/holduntil */
337 				if (gotmarker) {
338 					(void)sscanf(&buf[n], "%s",
339 						hostname);
340 
341 					p->hostname = strdup(hostname);
342 				}
343 				else {
344 					(void)sscanf(&buf[n], "%ld",
345 						&holduntil);
346 				}
347 				break;
348 
349 			case 'I': /* ident */
350 				p->ident = strdup(&buf[n]);
351 				break;
352 
353 			case 'L': /* lasttry */
354 				(void)sscanf(&buf[n], "%ld", &lasttry);
355 				break;
356 
357 			case 'M': /* message */
358 				p->message = strdup(&buf[n]);
359 				break;
360 
361 			case 'P': /* pager */
362 				name[0] = '\0';
363 				(void)sscanf(&buf[n], "%s", name);
364 
365 				tmp = (void *)malloc(sizeof(*tmp));
366 				(void)memset((char *)tmp, 0, sizeof(*tmp));
367 				tmp->next = p->rcpts;
368 				p->rcpts = tmp;
369 
370 				tmp->pager = strdup(name);
371 
372 				if (coverage[0])
373 					tmp->coverage = strdup(coverage);
374 
375 				tmp->holduntil = holduntil;
376 				tmp->lasttry = lasttry;
377 				tmp->goodtries = goodtries;
378 				tmp->tries = tries;
379 				tmp->level = level;
380 				tmp->flags = flags;
381 
382 				coverage[0] = '\0';
383 				level = DEFAULT_LEVEL;
384 				holduntil = 0;
385 				lasttry = 0;
386 				goodtries = 0;
387 				tries = 0;
388 				flags = 0;
389 
390 				break;
391 
392 			case 'S': /* status/servicelevel */
393 				if (gotmarker) {
394 					(void)sscanf(&buf[n], "%s", status);
395 				}
396 				else {
397 					(void)sscanf(&buf[n], "%d", &level);
398 				}
399 				break;
400 
401 			case 'T': /* tries */
402 				(void)sscanf(&buf[n], "%d", &tries);
403 				break;
404 
405 			case 'U': /* unique id */
406 				(void)sscanf(&buf[n], "%s", msgid);
407 				p->messageid = strdup(msgid);
408 				break;
409 
410 			case 'V': /* version */
411 				(void)sscanf(&buf[n], "%d", &version);
412 				if (version != 3) {
413 					qpage_log(LOG_ERR, "FATAL ERROR: incompatible version of queue file");
414 					clear_page(p, FALSE);
415 					free(p);
416 					return(NULL);
417 				}
418 				break;
419 
420 			default:
421 				qpage_log(LOG_NOTICE, "%s line %d: unknown meaning (%s)",
422 					file, line, buf);
423 				break;
424 		}
425 	}
426 
427 	free(buf);
428 	(void)fclose(fp);
429 
430 	p->filename = strdup(file);
431 
432 	if (p->messageid == NULL)
433 		p->messageid = strdup("[none]");
434 
435 	return(p);
436 }
437 
438 
439 /*
440 ** write_page()
441 **
442 ** This function writes a page to the page queue.  If the filename
443 ** field of the page structure is not null, it is assumed to point
444 ** to the name of the file the page was read from.  In this case,
445 ** if the page has been successfully delivered to all the recipients,
446 ** the file is removed.  Otherwise the page is written back to that
447 ** file.  If the filename field of the page structure is NULL, this
448 ** function assumes this is a new page.  A new filename is created
449 ** based on the current time.
450 **
451 **	Input:
452 **		p - a page structure
453 **		new - whether this is a new page
454 **
455 **	Returns:
456 **		an integer status code:
457 **			 0 = queue file was removed/renamed
458 **			 1 = page was written to queue file
459 **			-1 = error occurred; status unknown
460 */
461 int
write_page(PAGE * p,int new)462 write_page(PAGE *p, int new)
463 {
464 	rcpt_t		*tmp;
465 	FILE		*fp;
466 	char		filename[255];
467 	char		*badname;
468 	int		fd;
469 	int		ext;
470 	int		doit;
471 
472 
473 	/*
474 	** send e-mail notification (if needed) of the page status
475 	*/
476 	if (new == FALSE) {
477 		if (Administrator)
478 			notify_administrator(p);
479 
480 		if (p->from)
481 			notify_submitter(p);
482 	}
483 
484 	/*
485 	** first verify whether this page should be written back or not
486 	*/
487 	doit = FALSE;
488 	for (tmp=p->rcpts; tmp; tmp=tmp->next) {
489 		if (tmp->flags & F_SENT)
490 			continue;
491 
492 		doit = TRUE;
493 	}
494 
495 	if (doit == FALSE) {
496 		if (p->filename) {
497 			if (Debug)
498 				qpage_log(LOG_DEBUG, "unlinking %s",
499 					p->filename);
500 
501 			if (unlink(p->filename) < 0)
502 				qpage_log(LOG_WARNING, "unlink failed for %s: %s",
503 					p->filename, strerror(errno));
504 		}
505 
506 		return(0);
507 	}
508 
509 	if (p->filename == NULL) {
510 		ext = 0;
511 
512 		do {
513 			(void)sprintf(filename, "P%lu.%03u", time(NULL), ext++);
514 
515 			fd = open(filename, O_CREAT|O_EXCL|O_WRONLY, 0644);
516 
517 			if (fd >= 0)
518 				break;
519 
520 			if (errno != EEXIST) {
521 				qpage_log(LOG_NOTICE, "cannot create %s: %s",
522 					filename, strerror(errno));
523 			}
524 		}
525 		while (ext < 100);
526 
527 		if (fd < 0) {
528 			qpage_log(LOG_ERR, "cannot create file %s: %s",
529 				filename, strerror(errno));
530 
531 			return(-1);
532 		}
533 
534 		p->filename = strdup(filename);
535 	}
536 	else {
537 		if ((fd = open(p->filename, O_WRONLY, 0644)) < 0) {
538 			qpage_log(LOG_ERR, "cannot open file %s: %s",
539 				p->filename, strerror(errno));
540 
541 			return(-1);
542 		}
543 	}
544 
545 	if (lock_file(fd, O_RDWR, TRUE) < 0) {
546 		qpage_log(LOG_ERR, "cannot lock %s: %s", p->filename,
547 			strerror(errno));
548 
549 		return(-1);
550 	}
551 
552 	/*
553 	** explicitly truncate the file now that it's locked
554 	*/
555 	(void)ftruncate(fd, (off_t)0);
556 
557 	if ((fp = fdopen(fd, "w")) == NULL) {
558 		qpage_log(LOG_ERR, "cannot reopen file %s", p->filename);
559 		(void)close(fd);
560 		return(-1);
561 	}
562 
563 	fprintf(fp, "Version: 3\n");
564 
565 	for (tmp=p->rcpts; tmp; tmp=tmp->next) {
566 		if (tmp->coverage)
567 			fprintf(fp, "Coverage: %s\n", tmp->coverage);
568 
569 		if (tmp->holduntil)
570 			fprintf(fp, "Holduntil: %lu %s\n", tmp->holduntil,
571 				my_ctime(&tmp->holduntil));
572 
573 		if (tmp->lasttry)
574 			fprintf(fp, "Lasttry: %lu %s\n", tmp->lasttry,
575 				my_ctime(&tmp->lasttry));
576 
577 		fprintf(fp, "Tries: %d\n", tmp->tries);
578 
579 		if (tmp->goodtries)
580 			fprintf(fp, "Goodtries: %d\n", tmp->goodtries);
581 
582 		if (tmp->level != DEFAULT_LEVEL)
583 			fprintf(fp, "Servicelevel: %d\n", tmp->level);
584 
585 		if (tmp->flags) {
586 			fprintf(fp, "Flags: %d (", tmp->flags);
587 
588 			if (tmp->flags & F_SENT)
589 				fprintf(fp, " F_SENT");
590 
591 			if (tmp->flags & F_FAILED)
592 				fprintf(fp, " F_FAILED");
593 
594 			if (tmp->flags & F_BUSY)
595 				fprintf(fp, " F_BUSY");
596 
597 			if (tmp->flags & F_NOCARRIER)
598 				fprintf(fp, " F_NOCARRIER");
599 
600 			if (tmp->flags & F_NOMODEM)
601 				fprintf(fp, " F_NOMODEM");
602 
603 			if (tmp->flags & F_FORCED)
604 				fprintf(fp, " F_FORCED");
605 
606 			if (tmp->flags & F_NOPROMPT)
607 				fprintf(fp, " F_NOPROMPT");
608 
609 			if (tmp->flags & F_UNKNOWN)
610 				fprintf(fp, " F_UNKNOWN");
611 
612 			if (tmp->flags & F_REJECT)
613 				fprintf(fp, " F_REJECT");
614 
615 			if (tmp->flags & F_RAWPID)
616 				fprintf(fp, " F_RAWPID");
617 
618 			if (tmp->flags & F_SENDMAIL)
619 				fprintf(fp, " F_SENDMAIL");
620 
621 			if (tmp->flags & F_SENTMAIL)
622 				fprintf(fp, " F_SENTMAIL");
623 
624 			if (tmp->flags & F_SENTADMIN)
625 				fprintf(fp, " F_SENTADMIN");
626 
627 			fprintf(fp, " )\n");
628 		}
629 
630 		fprintf(fp, "Pager: %s\n", tmp->pager);
631 	}
632 
633 	fprintf(fp, "-\n");
634 
635 	if (p->from)
636 		fprintf(fp, "From: %s\n", p->from);
637 
638 	if (p->ident)
639 		fprintf(fp, "Ident: %s\n", p->ident);
640 
641 	if (p->hostname)
642 		fprintf(fp, "Hostname: %s\n", p->hostname);
643 
644 	/*
645 	** Tell the reader how big the buffer has to be in order to read
646 	** the next line.  This includes the message length plus the word
647 	** "Message:" plus a space, a newline, and a null character.
648 	*/
649 	fprintf(fp, "Bytes: %d\n", strlen(p->message)+11);
650 	fprintf(fp, "Message: %s\n", p->message);
651 	fprintf(fp, "Created: %lu %s\n", p->created, my_ctime(&p->created));
652 	fprintf(fp, "UniqueID: %s\n", p->messageid);
653 
654 	if (p->status)
655 		fprintf(fp, "Status: %s\n", p->status);
656 
657 	/*
658 	** Before we close the file (which releases the lock), we
659 	** should check to see if this page is worth reading again
660 	** in the future.  If not, rename the file to start with 'B'.
661 	*/
662 	badname = NULL;
663 	if (p->flags & F_BADPAGE) {
664 		badname = strdup(p->filename);
665 		badname[0] = 'B';
666 
667 		qpage_log(LOG_NOTICE, "renaming bad page to %s", badname);
668 
669 		if (rename(p->filename, badname) < 0) {
670 			qpage_log(LOG_WARNING, "cannot rename %s to %s: %s",
671 				p->filename, badname, strerror(errno));
672 		}
673 	}
674 
675 	if (fclose(fp)) {
676 		qpage_log(LOG_WARNING, "error writing queue file: %s",
677 			strerror(errno));
678 
679 		return(-1);
680 	}
681 
682 	if (badname) {
683 		free(badname);
684 		return(0);
685 	}
686 
687 	return(1);
688 }
689 
690 
691 /*
692 ** read_queue()
693 **
694 ** This function reads the filenames in the page queue.  Any file which
695 ** starts with a 'P' is considered a page.  All other files are ignored.
696 ** Files containing pages are passed to read_page() to be read.
697 **
698 **	Input:
699 **		bad - a boolean flag indicating whether to read bad pages
700 **
701 **	Returns:
702 **		a linked list of pages, linked in the order they are read
703 */
704 PAGE *
read_queue(int bad)705 read_queue(int bad)
706 {
707 	struct dirent	*entry;
708 	PAGE		*head;
709 	PAGE		*curr;
710 	PAGE		*tmp;
711 	DIR		*dirp;
712 
713 
714 	head = NULL;
715 	curr = NULL;
716 
717 	if ((dirp = opendir(".")) == NULL) {
718 		qpage_log(LOG_ERR, "cannot read current directory");
719 		return(NULL);
720 	}
721 
722 	while ((entry = readdir(dirp)) != NULL) {
723 		if (entry->d_name[0] != 'P') {
724 			if (bad == FALSE || entry->d_name[0] != 'B')
725 				continue;
726 		}
727 
728 		if ((tmp = read_page(entry->d_name)) != NULL) {
729 			if (head == NULL)
730 				head = tmp;
731 			else
732 				curr->next = tmp;
733 
734 			curr = tmp;
735 		}
736 	}
737 
738 	(void)closedir(dirp);
739 
740 	return(head);
741 }
742 
743 
744 /*
745 ** showqueue()
746 **
747 ** This function shows the pages currently in the queue.
748 **
749 **	Input:
750 **		nothing
751 **
752 **	Returns:
753 **		the number of pages in the page queue
754 */
755 int
showqueue(void)756 showqueue(void)
757 {
758 	PAGE		*pagelist;
759 	PAGE		*tmp;
760 	rcpt_t		*rcpt;
761 	int		count;
762 	time_t		now;
763 
764 
765 	count = 0;
766 	now = time(NULL);
767 
768 	pagelist = read_queue(TRUE);
769 
770 	for (tmp=pagelist; tmp; tmp=tmp->next) {
771 		printf("ID=%s%s\n", tmp->messageid,
772 			tmp->filename[0] == 'B' ? " (*** bad page ***)" : "");
773 
774 		printf("\t  Date: %s\n", my_ctime(&tmp->created));
775 		printf("\t  File: %s\n", tmp->filename);
776 		printf("\t  From: %s\n", tmp->from ? tmp->from : "[anonymous]");
777 
778 		if (tmp->hostname)
779 			printf("\t  Host: %s\n", tmp->hostname);
780 
781 		printf("\tLength: %d bytes\n", strlen(tmp->message));
782 
783 		for (rcpt=tmp->rcpts; rcpt; rcpt=rcpt->next) {
784 			printf("\t    To: pager=%s", rcpt->pager);
785 
786 			if (rcpt->tries)
787 				printf(", goodtries/tries=%d/%d",
788 					rcpt->goodtries, rcpt->tries);
789 
790 			if (rcpt->holduntil > now)
791 				printf(", holduntil=%s",
792 					my_ctime(&rcpt->holduntil));
793 
794 			if (rcpt->flags & F_SENT)
795 				printf(", status=SENT");
796 
797 			if (rcpt->flags & F_FAILED)
798 				printf(", status=FAILED");
799 
800 			printf("\n");
801 		}
802 
803 		if (tmp->next)
804 			printf("\n");
805 
806 		count++;
807 	}
808 
809 	if (count == 0)
810 		printf("The page queue is empty.\n");
811 
812 	return(count);
813 }
814 
815 
816 /*
817 ** runqueue()
818 **
819 ** This function reads the pages in the page queue, sorts them into
820 ** a job list, sends the jobs, and writes pages back to the page queue.
821 ** The number of pages remaining in the page queue is returned.  This
822 ** number includes pages which were not sent because of retry counts
823 ** being exceeded.
824 **
825 **	Input:
826 **		nothing
827 **
828 **	Returns:
829 **		an integer status (0=success)
830 **
831 **	Note:
832 **		This function creates memory leaks.  Fortunately,
833 **		it is only called from within a sub-process and
834 **		the memory will be reclaimed by the operating
835 **		system when the process exits.
836 */
837 int
runqueue(void)838 runqueue(void)
839 {
840 	PAGE		*pagelist;
841 	PAGE		*tmp;
842 	job_t		*joblist;
843 	int		count;
844 	int		lock;
845 
846 
847 	count = 0;
848 	joblist = NULL;
849 
850 	/*
851 	** lock the page queue
852 	*/
853 	if ((lock = lock_queue()) < 0)
854 		return(-1);
855 
856 	pagelist = read_queue(FALSE);
857 
858 	if (Debug)
859 		qpage_log(LOG_DEBUG, "getting job list");
860 
861 	for (tmp=pagelist; tmp; tmp=tmp->next) {
862 		if ((tmp->flags & F_BADPAGE) == 0)
863 			count += insert_jobs(&joblist, tmp);
864 	}
865 
866 	if (Debug)
867 		qpage_log(LOG_DEBUG, "pending jobs: %d", count);
868 
869 	if (joblist) {
870 		if (Debug)
871 			qpage_log(LOG_DEBUG, "sending job list");
872 
873 		send_pages(joblist);
874 	}
875 
876 	/*
877 	** We must write the pages back out regardless of whether
878 	** any jobs were processed.  This is because we may have
879 	** changed some flags (e.g. F_FAILED) and we need to ensure
880 	** that the changes are seen on the next iteration.
881 	*/
882 	if (Debug && pagelist)
883 		qpage_log(LOG_DEBUG, "writing job list");
884 
885 	for (tmp=pagelist; tmp; tmp=tmp->next) {
886 		if (write_page(tmp, FALSE) < 0) {
887 			qpage_log(LOG_WARNING, "lost page id=%s",
888 			tmp->messageid);
889 		}
890 	}
891 
892 	/*
893 	** unlock the page queue
894 	*/
895 	(void)close(lock);
896 
897 	return(0);
898 }
899