This is misc.c in view mode; [Download] [Up]
#ifndef lint static char *sccsid = "@(#)$Header: misc.c,v 1.41 90/12/12 00:00:02 sob Exp $"; #endif #include "common.h" /* * open_valid_art -- determine if a given article name is valid; * if it is, return a file pointer to the open article, * along with a unique id of the article. * * Parameters: "artname" is a string containing the * name of the article. * "id" is space for us to put the article * id in. * * Returns: File pointer to the open article if the * article is valid; NULL otherwise * * Side effects: None. */ FILE * open_valid_art(artname, id) char *artname; char *id; { static int crnt_art_num; static char crnt_art_id[MAXBUFLEN]; int fd; struct stat statbuf; if (art_fp != NULL) { if (crnt_art_num == atoi(artname)) { if (fseek(art_fp, (long) 0, 0) < 0) close_crnt(); else { (void) strcpy(id, crnt_art_id); return (art_fp); } } else close_crnt(); } art_fp = fopen(artname, "r"); if (art_fp == NULL) return (NULL); fd = fileno(art_fp); if (fstat(fd, &statbuf) < 0) { close_crnt(); return (NULL); } if ((statbuf.st_mode & S_IFMT) != S_IFREG) { close_crnt(); return (NULL); } get_id(art_fp, id); (void) strcpy(crnt_art_id, id); crnt_art_num = atoi(artname); return (art_fp); } /* * gethistent -- return the path name of an article if it's * in the history file. * * Parameters: "msg_id" is the message ID of the * article, enclosed in <>'s. * "lookup", only check if article exists * * Returns: A char pointer to a static data area * containing the full pathname of the * article, or NULL if the message-id is not * in thef history file. * * Side effects: opens dbm database * (only once, keeps it open after that). * If running Bnews, converts "msg_id" to lower case. * If running Cnews, converts "msg_id" per rfc822. * */ #ifndef NDBM # ifndef DBM # ifndef USGHIST # define USGHIST # endif not USGHIST # endif not DBM #endif not DBM char * gethistent(msg_id, lookup) char *msg_id; int lookup; { char line[MAXBUFLEN]; char *tmp; register char *cp; long ltmp; static char path[MAXPATHLEN]; #ifdef USGHIST char *histfile(); register int len; #else not USGHIST #ifdef DBM static int dbopen = 0; datum fetch(); #else not DBM static DBM *db = NULL; /* History file, dbm version */ #endif DBM datum key, content; #endif USGHIST static FILE *hfp = NULL; /* history file, text version */ #ifdef CNEWS cp = rindex(msg_id,'@'); /* look for @ in message id */ if( cp != NULL) { for(;*cp != '\0';++cp) #else { for (cp = msg_id; *cp != '\0'; ++cp) #endif if (isupper(*cp)) *cp = tolower(*cp); /* Make ctags happy */ #ifdef CNEWS } #else } #endif #ifdef USGHIST hfp = fopen(histfile(msg_id), "r"); if (hfp == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "gethistent: histfile: %m"); #endif SYSLOG return (NULL); } len = strlen(msg_id); while (fgets(line, sizeof (line), hfp)) if (!strncasecmp(msg_id, line, len)) break; if (feof(hfp)) { (void) fclose(hfp); return (NULL); } #else not USGHIST #ifdef DBM if (!dbopen) { if (dbminit(historyfile) < 0) { #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbminit %s: %m", historyfile); #endif SYSLOG return (NULL); } else dbopen = 1; } #else /* ndbm */ if (db == NULL) { db = dbm_open(historyfile, O_RDONLY, 0); if (db == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "openartbyid: dbm_open %s: %m", historyfile); #endif SYSLOG return (NULL); } } #endif DBM key.dptr = msg_id; key.dsize = strlen(msg_id) + 1; #ifdef DBM content = fetch(key); #else /* ndbm */ content = dbm_fetch(db, key); #endif DBM if (content.dptr == NULL) return (NULL); /* * If we are just checking to see if it exists return a non-NULL * result */ if (lookup) return ((char *)1); if (hfp == NULL) { hfp = fopen(historyfile, "r"); if (hfp == NULL) { #ifdef SYSLOG syslog(LOG_ERR, "message: fopen %s: %m", historyfile); #endif SYSLOG return (NULL); } } else { /* Why do this if we are going to do an absolute fseek below? XXX */ rewind(hfp); } bcopy(content.dptr, (char *)<mp, sizeof (long)); if (fseek(hfp, ltmp, 0) < 0) { #ifdef SYSLOG syslog(LOG_ERR, "message: %s: fseek to %ld on %d: %m", historyfile, ltmp, hfp); #endif SYSLOG return (NULL); } (void) fgets(line, sizeof(line), hfp); #endif USGHIST if ((cp = index(line, '\n')) != NULL) *cp = '\0'; cp = index(line, '\t'); if (cp != NULL) cp = index(cp+1, '\t'); #ifdef SYSLOG else syslog(LOG_ERR, "message: malformed line in history file at %ld bytes, id %s", ltmp, msg_id); #endif SYSLOG if (cp == NULL) return(NULL); /* this article has expired */ tmp = cp+1; if ((cp = index(tmp, ' ')) != NULL) *cp = '\0'; while ((cp = index(tmp, '.')) != NULL) *cp = '/'; (void) strcpy(path, spooldir); (void) strcat(path, "/"); (void) strcat(path, tmp); #ifdef USGHIST (void) fclose(hfp); #endif return (path); } /* * openartbyid -- open an article by message-id. * * Arguments: "msg_id" is the message-id of the article * to open. * * Returns: File pointer to opened article, or NULL if * the article was not in the history file or * could not be opened. * * Side effects: Opens article. */ FILE * openartbyid(msg_id) char *msg_id; { char *path; path = gethistent(msg_id, 0); if (path != NULL) return (fopen(path, "r")); else return (NULL); } /* * check_ngperm -- check to see if they're allowed to see this * article by matching Newsgroups: and Distribution: line. * * Parameters: "fp" is the file pointer of this article. * * Returns: 0 if they're not allowed to see it. * 1 if they are. * * Side effects: None. */ check_ngperm(fp) register FILE *fp; { char buf[MAXBUFLEN]; register char *cp; static char **ngarray; int ngcount = 0; if (ngpermcount == 0) { if (ALLBUT == 0) return 0; return (1); } while (fgets(buf, sizeof (buf), fp) != NULL) { if (buf[0] == '\n') /* End of header */ break; if (buf[0] != 'N' && buf[0] != 'n') continue; cp = index(buf, '\n'); if (cp) *cp = '\0'; cp = index(buf, ':'); if (cp == NULL) continue; *cp = '\0'; if (!strcasecmp(buf, "newsgroups")) { ngcount = get_nglist(&ngarray, cp+2); break; } } #ifndef USG (void) rewind(fp); #else rewind(fp); #endif if (ngcount == 0) /* Either no newgroups or null entry */ return (1); return (ngmatch(s1strneql, ALLBUT, ngpermlist, ngpermcount, ngarray, ngcount)); } /* * spew -- spew out the contents of a file to stdout, doing * the necessary cr-lf additions at the end. Finish with * a "." on a line by itself, and an fflush(stdout). * * Parameters: "how" tells what part of the file we * want spewed: * ARTICLE The entire thing. * HEAD Just the first part. * BODY Just the second part. * "fp" is the open file to spew from. * * Returns: Nothing. * * Side effects: Changes current position in file. */ spew(fp, how) FILE *fp; int how; { char line[NNTP_STRLEN]; register char *cp; #ifdef LOG ++arts_acsd; #endif if (how == STAT) { (void) fflush(stdout); return; } while (fgets(line, sizeof(line)-6, fp) != NULL && *line != '\n') { if (how == BODY) /* We need to skip this anyway */ continue; cp = index(line, '\n'); if (cp != NULL) *cp = '\0'; if (*line == '.') putchar('.'); putline(line); if (cp == NULL) { for (;;) { if ((fgets(line, sizeof(line)-6, fp) == NULL) || (index(line, '\n') != NULL)) break; } } } if (how == HEAD) { putchar('.'); putchar('\r'); putchar('\n'); (void) fflush(stdout); return; } else if (how == ARTICLE) { putchar('\r'); putchar('\n'); } while (fgets(line, sizeof(line)-6, fp) != NULL) { cp = index(line, '\n'); if (cp != NULL) *cp = '\0'; if (*line == '.') putchar('.'); putline(line); if (cp == NULL) { for (;;) { if ((fgets(line, sizeof(line)-6, fp) == NULL) || (index(line, '\n') != NULL)) break; } } } putchar('.'); putchar('\r'); putchar('\n'); (void) fflush(stdout); } /* * get_id -- get the message id of the current article. * * Parameters: "art_fp" is a pointer to the open file. * "id" is space for the message ID. * * Returns: Nothing. * * Side effects: Seeks and rewinds on "art_fp". * Changes space pointed to by "id". */ get_id(art_fp, id) register FILE *art_fp; char *id; { char line[MAXBUFLEN]; register char *cp; while (fgets(line, sizeof(line), art_fp) != NULL) { if (*line == '\n') break; if (*line == 'M' || *line == 'm') { /* "Message-ID" */ if ((cp = index(line, ' ')) != NULL) { *cp = '\0'; if (!strcasecmp(line, "Message-ID:")) { (void) strcpy(id, cp + 1); if ((cp = index(id, '\n')) != NULL) *cp = '\0'; #ifndef USG (void) rewind(art_fp); #else rewind(art_fp); #endif return; } } } } #ifndef USG (void) rewind(art_fp); #else rewind(art_fp); #endif (void) strcpy(id, "<0>"); } /* * close_crnt -- close the current article file pointer, if it's * open. * * Parameters: None. * * Returns: Nothing. * * Side effects: Closes "art_fp" if it's open; sets "art_fp" to NULL. */ close_crnt() { if (art_fp != NULL) (void) fclose(art_fp); art_fp = NULL; } /* * findart -- find an article number in the article array. * * Parameters: "artname" is a string containing * the name of the article. * * Returns: An index into "art_array", * or -1 if "artname" isn't in "art_array". * * Side effects: None. * * Improvement: Replace this linear search with a binary one. */ findart(artname) char *artname; { register int i, artnum; artnum = atoi(artname); for (i = 0; i < num_arts; ++i) if (art_array[i] == artnum) return(i); return (-1); } /* * get_distlist -- return a nicely set up array of distribution groups * along with a count, when given an NNTP-spec distribution list * in the form <dist1,dist2,...,distn>. * * Parameters: "array" is storage for our array, * set to point at some static data. * "list" is the NNTP distribution list. * * Returns: Number of distributions found. * -1 on error. * * Side effects: Changes static data area. */ get_distlist(array, list) char ***array; char *list; { char *cp; int distcount; static char **dist_list = (char **) NULL; if (list[0] != '<') return (-1); cp = index(list + 1, '>'); if (cp != NULL) *cp = '\0'; else return (-1); for (cp = list + 1; *cp != '\0'; ++cp) if (*cp == ',') *cp = ' '; distcount = parsit(list + 1, &dist_list); *array = dist_list; return (distcount); } /* * lower -- convert a character to lower case, if it's upper case. * * Parameters: "c" is the character to be * converted. * * Returns: "c" if the character is not * upper case, otherwise the lower * case equivalent of "c". * * Side effects: None. */ char lower(c) register char c; { if (isascii(c) && isupper(c)) c = c - 'A' + 'a'; return (c); } /* the following is from news 2.11 */ #ifdef USGHIST /* ** Generate the appropriate history subfile name */ char * histfile(hline) char *hline; { char chr; /* least significant digit of article number */ static char subfile[BUFSIZ]; chr = findhfdigit(hline); sprintf(subfile, "%s.d/%c", HISTORY_FILE, chr); return subfile; } findhfdigit(fn) char *fn; { register char *p; register int chr; p = index(fn, '@'); if (p != NULL && p > fn) chr = *(p - 1); else chr = '0'; if (!isdigit(chr)) chr = '0'; return chr; } #endif USGHIST #ifdef USG #ifndef GAZETTE bcopy(s, d, l) register char *s, *d; register int l; { while (l-- > 0) *d++ = *s++; } bcmp(s1, s2, l) register char *s1, *s2; register int l; { if (l == 0) return (0); do if (*s1++ != *s2++) break; while (--l); return (l); } bzero(p, l) register char *p; register int l; { while (l-- > 0) *p++ = 0; } #endif dup2(x,y) int x,y; { close(y); return(fcntl(x, F_DUPFD,y )); } #endif /* * The following is a mish-mosh of code submitted to the net * by Stan Barber <sob@bcm.tmc.edu>, Tad Guy <tadguy@cs.odu.edu>, * Chris Jepeway <jepeway@utkcs2.cs.utk.edu>, and Tom Lane <tgl@cs.cmu.edu>. */ /* * returns 1 if there are lots of free blocks for the nntp server to use; * a zero value is the small number of blocks remaining (more or less). */ #define DFREE_OK 0 #define DFREE_INODES 1 #define DFREE_BLOCKS 2 #define DFREE_ERR 3 int space(min_free) int min_free; { int result, dfree(); result = dfree(SPOOLDIR,min_free); if (result == DFREE_OK) return(1); #ifdef SYSLOG switch (result) { case DFREE_ERR: syslog(LOG_ERR,"dfree failed due to syscall error"); break; #ifdef LOG case DFREE_INODES: syslog(LOG_INFO,"no inodes on %s",SPOOLDIR); break; case DFREE_BLOCKS: syslog(LOG_INFO,"no space on %s",SPOOLDIR); break; #endif } #endif return(0); } /* * Now we define the dfree() routine, which returns the free space * on the file system containing the specified directory. * Space is measured in kilobytes. * A negative value is returned on error. */ #ifndef READ_SUPER #if defined(sun) || defined(hpux) || defined(pyr) || defined(hp300) || defined(NeXT) #include <sys/vfs.h> #define statfilesys statfs /* routine to call when trying to */ /* stat a file system to get the # */ /* of free blocks available */ typedef struct statfs statfs_type; /* the data type into which statfs() */ /* wants to return useful information*/ #define bombed(call) ((call) == -1) /* boolean expression returning 1 if */ /* a call to statfs() fails */ #define blkfree(fs) ((fs).f_bfree) /* given a statfs_type, return total */ /* # of free blocks */ #define blkavail(fs) ((fs).f_bavail) /* given a statfs_type called fs, */ /* return # of blocks available to */ /* a non-privileged user */ #define filfree(fs) ((fs).f_ffree) /* given a statfs_type called fs, */ /* return number of free inodes */ #endif #if defined(apollo) #include <sys/types.h> #include <sys/statfs.h> #define statfilesys(a,b) statfs(a,b, sizeof(struct statfs), 0) /* routine to call when trying to */ /* stat a file system to get the # */ /* of free blocks available */ typedef struct statfs statfs_type; /* the data type into which statfs() */ /* wants to return useful information*/ #define bombed(call) ((call) == -1) /* boolean expression returning 1 if */ /* a call to statfs() fails */ #define blkfree(fs) ((fs).f_bfree) /* given a statfs_type, return total */ /* # of free blocks */ #define blkavail(fs) ((fs).f_bfree) /* given a statfs_type called fs, */ /* return # of blocks available to */ /* a non-privileged user */ #define filfree(fs) ((fs).f_ffree) /* given a statfs_type called fs, */ /* return number of free inodes */ #endif /* apollo */ #ifdef ultrix #include <sys/mount.h> typedef struct fs_data statfs_type; #define statfilesys statfs #define bombed(call) ((call) <= 0) #define blkfree(fs) ((int)((fs).fd_req.bfree)) #define blkavail(fs) ((int)((fs).fd_req.bfreen)) #define filfree(fs) ((int)((fs).fd_req.gfree)) #endif #if defined(USG) && !defined(hpux) #include <ustat.h> typedef struct ustat statfs_type; /* * You've got to make calls to 2 functions to get * free blocks on a USG system, so statfilesys can't just be a macro. * written by Stan Barber <sob@watson.bcm.tmc.edu> */ int statfilesys(dir, fs) char *dir; statfs_type *fs; { struct stat file; if (stat(dir,&file)) return(-1); if (ustat(file.st_dev, fs)) return(-2); return(0); } #define bombed(call) (call != 0) #define blkfree(fs) ((fs).f_tfree) #define blkavail(fs) ((fs).f_tfree) /* USG doesn't reserve blocks for root */ #define filfree(fs) ((fs).f_tinode) #endif USG #ifdef CMU_MACH /* This code supplied by Tom Lane <tgl@cs.cmu.edu> */ #include <sys/ioctl.h> typedef struct fsparam statfs_type; int statfilesys(dir, fs) char *dir; statfs_type *fs; { int fd; fd = open(dir, O_RDONLY); if (fd < 0) return(-1); if (ioctl(fd, FIOCFSPARAM, fs) < 0) { close(fd); return(-2); } close(fd); return(0); } #define bombed(call) ((call) < 0) #define blkfree(fs) ((fs).fsp_free-((fs).fsp_size*(fs).fsp_minfree+99)/100) #define blkavail(fs) (-1) #endif MACH dfree(spool,free_space) char *spool; int free_space; { statfs_type fsys; int err; if (bombed(err = statfilesys(SPOOLDIR, &fsys))) return(DFREE_ERR); /* can't get file system info */ # if defined(filfree) && defined(MINFILES) if (filfree(fsys) < MINFILES ) return( DFREE_INODES ); # endif if (blkavail(fsys) < 0L) { /* the bavail field doesn't apply to this file system */ if(blkfree(fsys) < free_space) return( DFREE_BLOCKS ); } else { if (blkavail(fsys) < free_space ) return( DFREE_BLOCKS ); } return( DFREE_OK ); } #else READ_SUPER /* * This code is used if you've got to directly read the superblock * to determine how much space you've got left. It's copied from * patches posted by Tad Guy <tadguy@cs.odu.edu> */ #include <ufs/fs.h> #include <fstab.h> /* * return the number of free kilobytes remaining on the filesystem where * the named file resides. returns -1 on error. */ off_t lseek(); dfree(name, free_space) char *name; int free_space; { struct stat namest, fsst; struct fstab *fsp; char lname[MAXPATHLEN]; int fd; union { struct fs u_fs; char dummy[SBSIZE]; } sb; #define sblock sb.u_fs strcpy(lname,name); do { if (stat(lname,&namest)) /* if stat fails, die */ { #ifdef SYSLOG syslog(LOG_ERR,"dfree stat(%s) failed: %m", lname); #endif return DFREE_ERR; } if ((namest.st_mode & S_IFMT) == S_IFLNK) { /* if symlink */ if ((fd = readlink(lname,lname,sizeof(lname))) < 0) { #ifdef SYSLOG syslog(LOG_ERR,"dfree readlink() failed: %m"); #endif return DFREE_ERR; } lname[fd] = '\0'; } } while ((namest.st_mode & S_IFMT) == S_IFLNK); (void) setfsent(); while (fsp = getfsent()) { if (stat(fsp->fs_spec,&fsst)) continue; if (fsst.st_rdev == namest.st_dev) break; } if (!fsp || (fd = open(fsp->fs_spec,O_RDONLY)) < 0) { (void) endfsent(); #ifdef SYSLOG syslog(LOG_ERR,"dfree open(%s,O_RDONLY) failed: %m", fsp->fs_spec); #endif return DFREE_ERR; } (void) endfsent(); (void) lseek(fd,SBLOCK*DEV_BSIZE,L_SET); if (read(fd,(char *)&sblock,SBSIZE) != SBSIZE || (sblock.fs_magic != FS_MAGIC)) { #ifdef SYSLOG syslog(LOG_ERR,"dfree read() failed: %m"); #endif return DFREE_ERR; } (void) close(fd); # if defined(filfree) && defined(MINFILES) if (filfree(fsys) < MINFILES ) return( DFREE_INODES ); # endif if( ((((sblock.fs_dsize) * ( 100 - sblock.fs_minfree) / 100) - ((sblock.fs_dsize) - (sblock.fs_cstotal.cs_nbfree * sblock.fs_frag + sblock.fs_cstotal.cs_nffree))) * sblock.fs_fsize / 1024) < free_space ) return( DFREE_BLOCKS ); return( DFREE_OK ); } #endif READ_SUPER #ifdef LOAD /* ** GETLA -- get the current load average ** ** This code stolen from la.c. (And subsequently stolen from sendmail, ** conf.c for nntpd.) ** ** Parameters: ** none. ** ** Returns: ** The current load average as an integer. ** ** Side Effects: ** none. */ getla() { return(0); } #endif LOAD
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.