1 #ifndef lint
2 static char	sccsid[] = "@(#)$Id: misc.c,v 1.49 1996/01/09 12:37:21 sob Exp $";
3 #endif
4 
5 #include "common.h"
6 
7 /*
8  * open_valid_art -- determine if a given article name is valid;
9  *		if it is, return a file pointer to the open article,
10  *		along with a unique id of the article.
11  *
12  *	Parameters:	"artname" is a string containing the
13  *			name of the article.
14  *			"id" is space for us to put the article
15  *			id in.
16  *
17  *	Returns:	File pointer to the open article if the
18  *			article is valid; NULL otherwise
19  *
20  *	Side effects:	None.
21  */
22 
23 FILE *
open_valid_art(artname,id)24 open_valid_art(artname, id)
25 	char		*artname;
26 	char		*id;
27 {
28 	static int	crnt_art_num;
29 	static char	crnt_art_id[MAXBUFLEN];
30 	int		fd;
31 	struct stat	statbuf;
32 
33 	if (art_fp != NULL) {
34 		if (crnt_art_num == atoi(artname)) {
35 			if (fseek(art_fp, (long) 0, 0) < 0)
36 				close_crnt();
37 			else {
38 				(void) strcpy(id, crnt_art_id);
39 				return (art_fp);
40 			}
41 		} else
42 			close_crnt();
43 	}
44 
45 	art_fp = fopen(artname, "r");
46 
47 	if (art_fp == NULL)
48 		return (NULL);
49 
50 	fd = fileno(art_fp);
51 
52 	if (fstat(fd, &statbuf) < 0) {
53 		close_crnt();
54 		return (NULL);
55 	}
56 
57 	if ((statbuf.st_mode & S_IFMT) != S_IFREG) {
58 		close_crnt();
59 		return (NULL);
60 	}
61 
62 	get_id(art_fp, id);
63 	(void) strcpy(crnt_art_id, id);
64 	crnt_art_num = atoi(artname);
65 	return (art_fp);
66 }
67 
68 
69 /*
70  * gethistent -- return the path name of an article if it's
71  * in the history file.
72  *
73  *	Parameters:	"msg_id" is the message ID of the
74  *			article, enclosed in <>'s.
75  *			"lookup", only check if article exists
76  *
77  *	Returns:	A char pointer to a static data area
78  *			containing the full pathname of the
79  *			article, or NULL if the message-id is not
80  *			in the history file.
81  *
82  *	Side effects:	opens dbm database
83  *			(only once, keeps it open after that).
84  *			If running Bnews, converts "msg_id" to lower case.
85  *			If running Cnews, converts "msg_id" per rfc822.
86  *			If in a group, sets group_artnum to appropriate value.
87  *
88  */
89 
90 #ifndef NDBM
91 # ifndef DBM
92 #  ifndef USGHIST
93 #   define USGHIST
94 #  endif
95 # endif
96 #endif
97 
98 char *
gethistent(msg_id,lookup)99 gethistent(msg_id, lookup)
100 	char		*msg_id;
101 	int		lookup;
102 {
103 	char		line[MAXBUFLEN];
104 	char		*tmp;
105 	register char	*cp;
106 	char		*s;
107 	long		ltmp;
108 	static char	path[MAXPATHLEN];
109 #ifdef USGHIST
110 	char		*histfile();
111 	register int	len;
112 #else
113 #ifdef DBM
114 	static int	dbopen = 0;
115 	datum		fetch();
116 #else
117 	static DBM	*db = NULL;	/* History file, dbm version */
118 #endif /* !DBM */
119 	datum		 key, content;
120 #endif /* !USGHIST */
121 	static FILE	*hfp = NULL;	/* history file, text version */
122 
123 #ifdef CNEWS
124 	cp = rindex(msg_id,'@');	/* look for @ in message id */
125 	if( cp != NULL)
126 	{
127 	    for(;*cp != '\0';++cp)
128 #else
129 	{
130 	    for (cp = msg_id; *cp != '\0'; ++cp)
131 #endif
132 		if (isupper(*cp))
133 			*cp = tolower(*cp);
134 /* Make ctags happy */
135 #ifdef CNEWS
136 	}
137 #else
138 	}
139 #endif
140 #ifdef USGHIST
141 	hfp = fopen(histfile(msg_id), "r");
142 	if (hfp == NULL) {
143 #ifdef SYSLOG
144 		syslog(LOG_ERR, "gethistent: histfile: %m");
145 #endif
146 		return (NULL);
147 	}
148 
149 	len = strlen(msg_id);
150 	while (fgets(line, sizeof (line), hfp))
151 		if (!strncasecmp(msg_id, line, len))
152 			break;
153 
154 	if (feof(hfp)) {
155 		(void) fclose(hfp);
156 		return (NULL);
157 	}
158 #else /* !USGHIST */
159 #ifdef DBM
160 	if (!dbopen) {
161 		if (dbminit(historyfile) < 0) {
162 #ifdef SYSLOG
163 			syslog(LOG_ERR, "openartbyid: dbminit %s: %m",
164 				historyfile);
165 #endif
166 			return (NULL);
167 		} else
168 			dbopen = 1;
169 	}
170 #else /* !DBM (ndbm) */
171 	if (db == NULL) {
172 		db = dbm_open(historyfile, O_RDONLY, 0);
173 		if (db == NULL) {
174 #ifdef SYSLOG
175 			syslog(LOG_ERR, "openartbyid: dbm_open %s: %m",
176 				historyfile);
177 #endif
178 			return (NULL);
179 		}
180 	}
181 #endif /* !DBM */
182 
183 	key.dptr = msg_id;
184 	key.dsize = strlen(msg_id) + 1;
185 
186 #ifdef DBM
187 	content = fetch(key);
188 #else /* !DBM (ndbm) */
189 	content = dbm_fetch(db, key);
190 #endif
191 	if (content.dptr == NULL)
192 		return (NULL);
193 
194 	/*
195 	 * If we are just checking to see if it exists return a non-NULL
196 	 * result
197 	 */
198 	if (lookup)
199 		return ((char *)1);
200 
201 	if (hfp == NULL) {
202 		hfp = fopen(historyfile, "r");
203 		if (hfp == NULL) {
204 #ifdef SYSLOG
205 			syslog(LOG_ERR, "message: fopen %s: %m",
206 				historyfile);
207 #endif
208 			return (NULL);
209 		}
210 	} else {
211 /* Why do this if we are going to do an absolute fseek below? XXX */
212 		rewind(hfp);
213 	}
214 
215 	bcopy(content.dptr, (char *)&ltmp, sizeof (long));
216 	if (fseek(hfp, ltmp, 0) < 0) {
217 #ifdef SYSLOG
218 		syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m",
219 		       historyfile, ltmp, fileno(hfp));
220 #endif
221 		return (NULL);
222 	}
223 
224 	(void) fgets(line, sizeof(line), hfp);
225 #endif /* USGHIST */
226 
227 	if ((cp = index(line, '\n')) != NULL)
228 		*cp = '\0';
229 	cp = index(line, '\t');
230 	if (cp != NULL)
231 		cp = index(cp+1, '\t');
232 #ifdef SYSLOG
233 	else
234 	    syslog(LOG_ERR,
235 		"message: malformed line in history file at %ld bytes, id %s",
236 			ltmp, msg_id);
237 #endif
238 	if (cp == NULL) return(NULL); /* this article has expired */
239 	tmp = cp+1;
240 	group_artnum = 0;
241 	if (group_name) {
242 		int glen = strlen(group_name);
243 		for (;;) {
244 			if (!strncmp(group_name,tmp,glen) && tmp[glen] == '/') {
245 				group_artnum = atol(tmp+glen+1);
246 				break;
247 			}
248 			cp = index(tmp, ' ');
249 			if (cp == NULL) break;
250 			tmp = cp+1;
251 		}
252 	}
253 
254 	if ((cp = index(tmp, ' ')) != NULL)
255 		*cp = '\0';
256 
257 	while ((cp = index(tmp, '.')) != NULL)
258 		*cp = '/';
259 
260 	(void) strcpy(path, spooldir);
261 	(void) strcat(path, "/");
262 	(void) strcat(path, tmp);
263 #ifdef USGHIST
264 	(void) fclose(hfp);
265 #endif
266 	return (path);
267 }
268 
269 /*
270  * openartbyid -- open an article by message-id.
271  *
272  *	Arguments:	"msg_id" is the message-id of the article
273  *			to open.
274  *
275  *	Returns:	File pointer to opened article, or NULL if
276  *			the article was not in the history file or
277  *			could not be opened.
278  *
279  *	Side effects:	Opens article.
280  */
281 
282 FILE *
openartbyid(msg_id)283 openartbyid(msg_id)
284 	char	*msg_id;
285 {
286 	char	*path;
287 
288 	path = gethistent(msg_id, 0);
289 	if (path != NULL)
290 		return (fopen(path, "r"));
291 	else
292 		return (NULL);
293 }
294 
295 
296 /*
297  * check_ngperm -- check to see if they're allowed to see this
298  * article by matching Newsgroups: and Distribution: line.
299  *
300  *	Parameters:	"fp" is the file pointer of this article.
301  *
302  *	Returns:	0 if they're not allowed to see it.
303  *			1 if they are.
304  *
305  *	Side effects:	None.
306  */
307 
308 int
check_ngperm(fp)309 check_ngperm(fp)
310 	register FILE	*fp;
311 {
312 	char		buf[MAXBUFLEN];
313 	register char	*cp;
314 	static char	**ngarray;
315 	int		ngcount = 0;
316 
317 	if (ngpermcount == 0) {
318 		if (ALLBUT == 0)
319 			return 0;
320 		return (1);
321 	}
322 
323 	while (fgets(buf, sizeof (buf), fp) != NULL) {
324 		if (buf[0] == '\n')		/* End of header */
325 			break;
326 		if (buf[0] != 'N' && buf[0] != 'n')
327 			continue;
328 		cp = index(buf, '\n');
329 		if (cp)
330 			*cp = '\0';
331 		cp = index(buf, ':');
332 		if (cp == NULL)
333 			continue;
334 		*cp = '\0';
335 		if (!strcasecmp(buf, "newsgroups")) {
336 			ngcount = get_nglist(&ngarray, cp+2);
337 			break;
338 		}
339 	}
340 
341 #ifndef USG
342 	(void) rewind(fp);
343 #else
344 	rewind(fp);
345 #endif
346 	if (ngcount == 0)	/* Either no newgroups or null entry */
347 		return (1);
348 
349 	return (ngmatch(s1strneql, ALLBUT,
350 		ngpermlist, ngpermcount, ngarray, ngcount));
351 }
352 
353 
354 /*
355  * spew -- spew out the contents of a file to stdout, doing
356  * the necessary cr-lf additions at the end.  Finish with
357  * a "." on a line by itself, and an fflush(stdout).
358  *
359  *	Parameters:	"how" tells what part of the file we
360  *			want spewed:
361  *				ARTICLE   The entire thing.
362  *				HEAD	  Just the first part.
363  *				BODY	  Just the second part.
364  *			"fp" is the open file to spew from.
365  *
366  *	Returns:	Nothing.
367  *
368  *	Side effects:	Changes current position in file.
369  */
370 
371 void
spew(fp,how)372 spew(fp, how)
373 	FILE		*fp;
374 	int		how;
375 {
376 	char		line[NNTP_STRLEN];
377 	register char	*cp;
378 
379 #ifdef LOG
380 	++arts_acsd;
381 #endif
382 
383 	if (how == STAT) {
384 		(void) fflush(stdout);
385 		return;
386 	}
387 
388 	cp = line;
389 	while (fgets(line, sizeof(line)-6, fp) != NULL
390 	    && (cp == NULL || *line != '\n')) {
391 		if (how == BODY)	/* We need to skip this anyway */
392 			continue;
393 		if (cp != NULL && *line == '.')
394 			putchar('.');
395 		cp = index(line, '\n');
396 		if (cp != NULL)
397 			*cp = '\0';
398 		fputs(line, stdout);
399 		if (cp != NULL) {
400 			putchar('\r');
401 			putchar('\n');
402 		}
403 	}
404 
405 	if (how == HEAD) {
406 		putline(".");
407 		(void) fflush(stdout);
408 		return;
409 	}
410 	if (how == ARTICLE) {
411 		putchar('\r');
412 		putchar('\n');
413 	}
414 
415 	while (fgets(line, sizeof(line)-6, fp) != NULL) {
416 		if (cp != NULL && *line == '.')
417 			putchar('.');
418 		cp = index(line, '\n');
419 		if (cp != NULL)
420 			*cp = '\0';
421 		fputs(line, stdout);
422 		if (cp != NULL) {
423 			putchar('\r');
424 			putchar('\n');
425 		}
426 	}
427 	if (cp == NULL) {
428 		putchar('\r');
429 		putchar('\n');
430 	}
431 	putline(".");
432 	(void) fflush(stdout);
433 }
434 
435 
436 /*
437  * get_id -- get the message id of the current article.
438  *
439  *	Parameters:	"art_fp" is a pointer to the open file.
440  *			"id" is space for the message ID.
441  *
442  *	Returns:	Nothing.
443  *
444  *	Side effects:	Seeks and rewinds on "art_fp".
445  *			Changes space pointed to by "id".
446  */
447 
448 void
get_id(gart_fp,id)449 get_id(gart_fp, id)
450 	register FILE	*gart_fp;
451 	char		*id;
452 {
453 	char		line[MAXBUFLEN];
454 	register char	*cp;
455 
456 	while (fgets(line, sizeof(line), gart_fp) != NULL) {
457 		if (*line == '\n')
458 			break;
459 		if (*line == 'M' || *line == 'm') {	/* "Message-ID" */
460 			if ((cp = index(line, ' ')) != NULL) {
461 				*cp = '\0';
462 				if (!strcasecmp(line, "Message-ID:")) {
463 					(void) strcpy(id, cp + 1);
464 					if ((cp = index(id, '\n')) != NULL)
465 						*cp = '\0';
466 #ifndef USG
467 					(void) rewind(gart_fp);
468 #else
469 					rewind(gart_fp);
470 #endif
471 					return;
472 				}
473 			}
474 		}
475 	}
476 #ifndef USG
477 	(void) rewind(gart_fp);
478 #else
479 	rewind(gart_fp);
480 #endif
481 	(void) strcpy(id, "<0>");
482 }
483 
484 
485 /*
486  * close_crnt -- close the current article file pointer, if it's
487  *	open.
488  *
489  *	Parameters:	None.
490  *
491  *	Returns:	Nothing.
492  *
493  *	Side effects:	Closes "art_fp" if it's open; sets "art_fp" to NULL.
494  */
495 
496 void
close_crnt()497 close_crnt()
498 {
499 	if (art_fp != NULL)
500 		(void) fclose(art_fp);
501 	art_fp = NULL;
502 }
503 
504 
505 /*
506  * findart -- find an article number in the article array.
507  *
508  *	Parameters:	"artname" is a string containing
509  *			the name of the article.
510  *
511  *	Returns:	An index into "art_array",
512  *			or -1 if "artname" isn't in "art_array".
513  *
514  *	Side effects:	None.
515  *
516  *	Improvement:	Replace this linear search with a binary one.
517  */
518 
519 int
findart(artname)520 findart(artname)
521 	char		*artname;
522 {
523 	register int	i, artnum;
524 
525 	artnum = atoi(artname);
526 
527 	for (i = 0; i < num_arts; ++i)
528 		if (art_array[i] == artnum)
529 			return(i);
530 
531 	return (-1);
532 }
533 
534 
535 /*
536  * get_distlist -- return a nicely set up array of distribution groups
537  * along with a count, when given an NNTP-spec distribution list
538  * in the form <dist1,dist2,...,distn>.
539  *
540  *	Parameters:		"array" is storage for our array,
541  *				set to point at some static data.
542  *				"list" is the NNTP distribution list.
543  *
544  *	Returns:		Number of distributions found.
545  *				-1 on error.
546  *
547  *	Side effects:		Changes static data area.
548  */
549 
550 int
get_distlist(array,list)551 get_distlist(array, list)
552 	char		***array;
553 	char		*list;
554 {
555 	char		*cp;
556 	int		distcount;
557 	static char	**dist_list = (char **) NULL;
558 
559 	if (list[0] != '<')
560 		return (-1);
561 
562 	cp = index(list + 1, '>');
563 	if (cp != NULL)
564 		*cp = '\0';
565 	else
566 		return (-1);
567 
568 	for (cp = list + 1; *cp != '\0'; ++cp)
569 		if (*cp == ',')
570 			*cp = ' ';
571 	distcount = parsit(list + 1, &dist_list);
572 	*array = dist_list;
573 	return (distcount);
574 }
575 
576 
577 /*
578  * lower -- convert a character to lower case, if it's upper case.
579  *
580  *	Parameters:	"c" is the character to be
581  *			converted.
582  *
583  *	Returns:	"c" if the character is not
584  *			upper case, otherwise the lower
585  *			case equivalent of "c".
586  *
587  *	Side effects:	None.
588  */
589 
590 char
lower(c)591 lower(c)
592 	register char	c;
593 {
594 	if (isascii(c) && isupper(c))
595 		c = c - 'A' + 'a';
596 	return (c);
597 }
598 
599 
600 /* the following is from news 2.11 */
601 
602 #ifdef USGHIST
603 /*
604 ** Generate the appropriate history subfile name
605 */
606 char *
histfile(hline)607 histfile(hline)
608 char *hline;
609 {
610 	char chr;	/* least significant digit of article number */
611 	static char subfile[BUFSIZ];
612 
613 	chr = findhfdigit(hline);
614 	sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr);
615 	return subfile;
616 }
617 
618 int
findhfdigit(fn)619 findhfdigit(fn)
620 char *fn;
621 {
622 	register char *p;
623 	register int chr;
624 
625 	p = index(fn, '@');
626 	if (p != NULL && p > fn)
627 		chr = *(p - 1);
628 	else
629 		chr = '0';
630 	if (!isdigit(chr))
631 		chr = '0';
632 	return chr;
633 }
634 #endif /* USGHIST */
635 
636 #if defined(USG) && !defined(SVR4)
637 int
dup2(x,y)638 dup2(x,y)
639 int x,y;
640 {
641 	close(y);
642 	return(fcntl(x, F_DUPFD,y ));
643 }
644 #endif
645 
646 /*
647  * The following is a mish-mosh of code submitted to the net
648  * by Stan Barber <sob@bcm.tmc.edu>, Tad Guy <tadguy@cs.odu.edu>,
649  * Chris Jepeway <jepeway@utkcs2.cs.utk.edu>, and Tom Lane <tgl@cs.cmu.edu>.
650  */
651 
652 /*
653  * returns 1 if there are lots of free blocks for the nntp server to use;
654  * a zero value is the small number of blocks remaining (more or less).
655  */
656 #define DFREE_OK	0
657 #define DFREE_INODES	1
658 #define DFREE_BLOCKS	2
659 #define DFREE_ERR	3
660 
661 int
space(min_free)662 space(min_free)
663 int min_free;
664 {
665     int result;
666 
667     result = dfree(SPOOLDIR,min_free);
668     if (result == DFREE_OK) return(1);
669 #ifdef SYSLOG
670     switch (result) {
671 	case DFREE_ERR:
672 		syslog(LOG_ERR,"dfree failed due to syscall error");
673 		break;
674 #ifdef LOG
675 	case DFREE_INODES:
676 		syslog(LOG_INFO,"no inodes on %s",SPOOLDIR);
677 		break;
678 	case DFREE_BLOCKS:
679 		syslog(LOG_INFO,"no space on %s",SPOOLDIR);
680 		break;
681 #endif
682 	    }
683 #endif
684     return(0);
685 }
686 
687 /*
688  * Now we define the dfree() routine, which returns the free space
689  * on the file system containing the specified directory.
690  * Space is measured in kilobytes.
691  * A negative value is returned on error.
692  */
693 #ifndef READ_SUPER
694 #ifndef SVR4
695 #if defined(sun) || defined(hpux) || defined(pyr) || defined(hp300) || defined(NeXT) || defined(linux)
696 #include <sys/vfs.h>
697 #define statfilesys	statfs		/* routine to call when trying to  */
698 					/* stat a file system to get the # */
699 					/* of free blocks available	   */
700 typedef struct statfs statfs_type;	/* the data type into which statfs() */
701 					/* wants to return useful information*/
702 #define bombed(call)    ((call) == -1)	/* boolean expression returning 1 if */
703 					/* a call to statfs() fails	     */
704 #define blkfree(fs)	((fs).f_bfree)	/* given a statfs_type, return total */
705 					/* # of free blocks		     */
706 #define blkavail(fs)	((fs).f_bavail)	/* given a statfs_type called fs,  */
707 					/* return # of blocks available to */
708 					/* a non-privileged user	   */
709 #define filfree(fs)	((fs).f_ffree)	/* given a statfs_type called fs,  */
710  					/* return number of free inodes	   */
711 #else
712 #if defined(BSD_44)
713 #include <sys/types.h>
714 #include <sys/mount.h>
715 #define statfilesys	statfs
716 					/* stat a file system to get the # */
717 					/* of free blocks available	   */
718 typedef struct statfs statfs_type;	/* the data type into which statfs() */
719 					/* wants to return useful information*/
720 #define bombed(call)    ((call) == -1)	/* boolean expression returning 1 if */
721 					/* a call to statfs() fails	     */
722 #define blkfree(fs)	((fs).f_bfree)	/* given a statfs_type, return total */
723 					/* # of free blocks		     */
724 #define blkavail(fs)	((fs).f_bfree)	/* given a statfs_type called fs,  */
725 					/* return # of blocks available to */
726 					/* a non-privileged user	   */
727 #define filfree(fs)	((fs).f_ffree)	/* given a statfs_type called fs,  */
728  					/* return number of free inodes	   */
729 #endif /* BSD_44 */
730 #endif
731 #else  /* SVR4  */
732 #include <sys/statvfs.h>
733 #define statfilesys	statvfs		/* routine to call when trying to  */
734 					/* stat a file system to get the # */
735 					/* of free blocks available	   */
736 typedef struct statvfs statfs_type;	/* the data type into which statfs() */
737 					/* wants to return useful information*/
738 #define bombed(call)    ((call) == -1)	/* boolean expression returning 1 if */
739 					/* a call to statfs() fails	     */
740 #define blkfree(fs)	((fs).f_bfree)	/* given a statfs_type, return total */
741 					/* # of free blocks		     */
742 #define blkavail(fs)	((fs).f_bavail)	/* given a statfs_type called fs,  */
743 					/* return # of blocks available to */
744 					/* a non-privileged user	   */
745 #define filfree(fs)	((fs).f_ffree)	/* given a statfs_type called fs,  */
746  					/* return number of free inodes	   */
747 #endif  /* SVR4 */
748 
749 #if defined(apollo)
750 #include <sys/types.h>
751 #include <sys/statfs.h>
752 #define statfilesys(a,b)	statfs(a,b, sizeof(struct statfs), 0)		/* routine to call when trying to  */
753 					/* stat a file system to get the # */
754 					/* of free blocks available	   */
755 typedef struct statfs statfs_type;	/* the data type into which statfs() */
756 					/* wants to return useful information*/
757 #define bombed(call)    ((call) == -1)	/* boolean expression returning 1 if */
758 					/* a call to statfs() fails	     */
759 #define blkfree(fs)	((fs).f_bfree)	/* given a statfs_type, return total */
760 					/* # of free blocks		     */
761 #define blkavail(fs)	((fs).f_bfree)	/* given a statfs_type called fs,  */
762 					/* return # of blocks available to */
763 					/* a non-privileged user	   */
764 #define filfree(fs)	((fs).f_ffree)	/* given a statfs_type called fs,  */
765  					/* return number of free inodes	   */
766 #endif /* apollo */
767 
768 #ifdef ultrix
769 #include <sys/mount.h>
770 typedef struct fs_data statfs_type;
771 #define statfilesys	statfs
772 #define bombed(call)	((call) <= 0)
773 #define blkfree(fs)	((int)((fs).fd_req.bfree))
774 #define blkavail(fs)	((int)((fs).fd_req.bfreen))
775 #define filfree(fs)	((int)((fs).fd_req.gfree))
776 #endif
777 
778 #if defined(USG) && !defined(hpux) && !defined(SVR4)
779 #include <ustat.h>
780 typedef struct ustat statfs_type;
781 /*
782  * You've got to make calls to 2 functions to get
783  * free blocks on a USG system, so statfilesys can't just be a macro.
784  * written by Stan Barber <sob@watson.bcm.tmc.edu>
785  */
786 int
statfilesys(dir,fs)787 statfilesys(dir, fs)
788 char *dir;
789 statfs_type *fs;
790 {
791     struct stat file;
792     if (stat(dir,&file)) return(-1);
793     if (ustat(file.st_dev, fs)) return(-2);
794     return(0);
795 }
796 #define bombed(call)	(call != 0)
797 #define blkfree(fs)	((fs).f_tfree)
798 #define blkavail(fs)	((fs).f_tfree)
799 				/* USG doesn't reserve blocks for root */
800 #define filfree(fs)	((fs).f_tinode)
801 #endif /* USG && !hpux  && !SVR4 */
802 
803 #ifdef CMU_MACH
804 /* This code supplied by Tom Lane <tgl@cs.cmu.edu> */
805 #include <sys/ioctl.h>
806 typedef struct fsparam statfs_type;
807 int
statfilesys(dir,fs)808 statfilesys(dir, fs)
809 char *dir;
810 statfs_type *fs;
811 {
812     int fd;
813     fd = open(dir, O_RDONLY);
814     if (fd < 0) return(-1);
815     if (ioctl(fd, FIOCFSPARAM, fs) < 0) {
816 	close(fd);
817 	return(-2);
818     }
819     close(fd);
820     return(0);
821 }
822 #define bombed(call)	((call) < 0)
823 #define blkfree(fs)	((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100)
824 #define blkavail(fs)	(-1)
825 #endif /* CMU_MACH */
826 
827 int
dfree(spool,free_space)828 dfree(spool,free_space)
829 const char *spool;
830 int free_space;
831 {
832     statfs_type fsys;
833     int err;
834 
835     if (bombed(err = statfilesys(SPOOLDIR, &fsys)))
836 	return(DFREE_ERR);		/* can't get file system info */
837 # if defined(filfree) && defined(MINFILES)
838      if (filfree(fsys) < MINFILES )
839  	return( DFREE_INODES );
840 # endif
841     if (blkavail(fsys) <= 0L) {
842 	/* the bavail field doesn't apply to this file system */
843 	if(blkfree(fsys) < free_space)
844 	    return( DFREE_BLOCKS );
845      } else {
846 	if (blkavail(fsys) < free_space )
847 	    return( DFREE_BLOCKS );
848      }
849     return( DFREE_OK );
850 }
851 
852 #else /* READ_SUPER */
853 /*
854  * This code is used if you've got to directly read the superblock
855  * to determine how much space you've got left.  It's copied from
856  * patches posted by Tad Guy <tadguy@cs.odu.edu>
857  */
858 
859 #include <sys/fs.h>
860 #include <fstab.h>
861 
862 /*
863  * return the number of free kilobytes remaining on the filesystem where
864  * the named file resides.  returns -1 on error.
865  */
866 
dfree(name,free_space)867 dfree(name, free_space)
868 const char *name;
869 int free_space;
870 {
871     struct stat namest, fsst;
872     struct fstab *fsp;
873     char lname[MAXPATHLEN];
874     int fd;
875     union {
876 	struct fs u_fs;
877 	char dummy[SBSIZE];
878     } sb;
879 #define sblock sb.u_fs
880 
881     strcpy(lname,name);
882     do {
883 	if (stat(lname,&namest))		/* if stat fails, die */
884 	{
885 #ifdef SYSLOG
886 	  syslog(LOG_ERR,"dfree stat(%s) failed: %m", lname);
887 #endif
888 	  return  DFREE_ERR;
889 	}
890 	if ((namest.st_mode & S_IFMT) == S_IFLNK) { /* if symlink */
891 	    if ((fd = readlink(lname,lname,sizeof(lname))) < 0)
892 	    {
893 #ifdef SYSLOG
894 	      syslog(LOG_ERR,"dfree readlink() failed: %m");
895 #endif
896 	      return DFREE_ERR;
897 	    }
898 	    lname[fd] = '\0';
899 	}
900     } while ((namest.st_mode & S_IFMT) == S_IFLNK);
901 
902     (void) setfsent();
903 
904     while (fsp = getfsent()) {
905 	if (stat(fsp->fs_spec,&fsst))
906 	  continue;
907 	if (fsst.st_rdev == namest.st_dev)
908 	  break;
909     }
910 
911     if (!fsp ||	(fd = open(fsp->fs_spec,O_RDONLY)) < 0) {
912 	(void) endfsent();
913 #ifdef SYSLOG
914 	syslog(LOG_ERR,"dfree open(%s,O_RDONLY) failed: %m", fsp->fs_spec);
915 #endif
916 	return DFREE_ERR;
917     }
918     (void) endfsent();
919 
920     (void) lseek(fd,SBLOCK*DEV_BSIZE,L_SET);
921     if (read(fd,(char *)&sblock,SBSIZE) != SBSIZE ||
922 	(sblock.fs_magic != FS_MAGIC))
923     {
924 #ifdef SYSLOG
925       syslog(LOG_ERR,"dfree read() failed: %m");
926 #endif
927       return DFREE_ERR;
928     }
929     (void) close(fd);
930 
931 # if defined(filfree) && defined(MINFILES)
932     if (filfree(fsys) < MINFILES )
933 	return( DFREE_INODES );
934 # endif
935     if( ((((sblock.fs_dsize) * ( 100 - sblock.fs_minfree) / 100)
936 	  - ((sblock.fs_dsize)
937 	     - (sblock.fs_cstotal.cs_nbfree
938 		* sblock.fs_frag + sblock.fs_cstotal.cs_nffree)))
939 	 * sblock.fs_fsize / 1024) < free_space )
940 	return( DFREE_BLOCKS );
941    return( DFREE_OK );
942 }
943 
944 #endif /* READ_SUPER */
945 
946 #ifdef LOAD
947 /*
948 **  GETLA -- get the current load average
949 **
950 **	This code stolen from la.c. (And subsequently stolen from sendmail,
951 **		conf.c for nntpd.)
952 **
953 **	Parameters:
954 **		none.
955 **
956 **	Returns:
957 **		The current load average as an integer.
958 **
959 **	Side Effects:
960 **		none.
961 */
962 
963 
964 #if defined(BSD_44)
965 #include <stdlib.h>
966 
967 int
getla(void)968 getla( void )
969 {
970 	double avenrun[3];
971 	int rc;
972 
973         rc = getloadavg( avenrun, 1 );
974 	if ( rc == -1 )
975 		return 1;
976 # ifdef FSCALE
977 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
978 # else
979 	return ((int) (avenrun[0] + 0.5));
980 # endif
981 }
982 
983 #else
984 #if defined(USG) && !defined(SVR4)
985 int
getla()986 getla()
987 {
988 	return(0);
989 }
990 #else
991 #include <nlist.h>
992 #include <sys/ioctl.h>
993 
994 struct	nlist Nl[] =
995 {
996 #ifdef SVR4
997 	{ "avenrun" },
998 #else
999 #ifdef bsdi
1000 	{ "_averunnable" },
1001 #else
1002 	{ "_avenrun" },
1003 #endif
1004 #endif
1005 #define	X_AVENRUN	0
1006 	{ 0 },
1007 };
1008 
1009 #ifdef SVR4
1010 #define KERNEL_FILE "/kernel/unix"
1011 #else
1012 #ifdef bsdi
1013 #define KERNEL_FILE "/bsd"
1014 #else
1015 #define KERNEL_FILE "/vmunix"
1016 #endif
1017 #endif
1018 
1019 #ifdef	SVR4
1020 #ifndef FSHIFT
1021 #define FSHIFT  8
1022 #endif
1023 #ifndef FSCALE
1024 #define FSCALE  (1 << FSHIFT)
1025 #endif
1026 #endif
1027 
1028 int
getla()1029 getla()
1030 {
1031 	static int kmem = -1;
1032 # ifdef FSCALE
1033 	long avenrun[3];
1034 # else
1035 	double avenrun[3];
1036 # endif
1037 
1038 	if (kmem < 0) {
1039 		kmem = open("/dev/kmem", 0, 0);
1040 		if (kmem < 0) {
1041 #ifdef SYSLOG
1042 			syslog(LOG_ERR,"can't open /dev/kmem: %m");
1043 #endif
1044 			return (-1);
1045 		}
1046 #ifndef SVR4
1047 		if (ioctl(kmem, (int) FIOCLEX, (char *) 0) < 0) {
1048 #ifdef SYSLOG
1049 			syslog(LOG_ERR,"ioctl FIOCLEX of /dev/kmem failed: %m");
1050 #endif
1051 		}
1052 #endif /* !SVR4 */
1053 		if (nlist(KERNEL_FILE, Nl) < 0 || Nl[X_AVENRUN].n_value == 0) {
1054 #ifdef SYSLOG
1055 			syslog(LOG_ERR,"nlist of %s failed: %m", KERNEL_FILE);
1056 #endif
1057 			return (-1);
1058 		}
1059 	}
1060 	if (lseek(kmem, (off_t) Nl[X_AVENRUN].n_value, 0) == -1 ||
1061 	    read(kmem, (char *) avenrun, sizeof(avenrun)) < sizeof(avenrun))
1062 	{
1063 		/* thank you Ian */
1064 #ifdef SYSLOG
1065 		syslog(LOG_ERR,"lseek or read of /dev/kmem failed: %m");
1066 #endif
1067 		return (-1);
1068 	}
1069 # ifdef FSCALE
1070 	return ((int) (avenrun[0] + FSCALE/2) >> FSHIFT);
1071 # else
1072 	return ((int) (avenrun[0] + 0.5));
1073 # endif
1074 }
1075 #endif
1076 #endif /* BSD_44 */
1077 #endif /* LOAD */
1078