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 *)<mp, 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