home *** CD-ROM | disk | FTP | other *** search
- [ Everybody talks about it, but this one did something about it. -mod ]
-
- Date: Sat, 16 Nov 85 15:11:46 est
- From: seismo!hadron!jsdy (Joseph S. D. Yao)
-
- Reading in limits on a per-machine basis is a good idea.
- However, the idea of reading in a struct or using a numerical
- ID for limits both constrain expandability. I also have
- problems with reading directly from limits.h. Let's do it
- from a file like /etc/limits.
-
- By the way -- one person said that define'd limits were needed
- for #if expressions in code. What about if () expressions? The
- only case in which the former couldn't be handled by the latter is
- in the case that you are really squeezed for core. ("main memory"
- to all you young whippersnappers.)
-
- /* #include <local.h> */
-
- /*********************************************************************\
- **
- ** limits -- read limits from the limits file.
- **
- ** Copyright and disclaimers:
- ** This code is Copyright (c) 1985 by one or more of:
- ** The author named below;
- ** The author's institution named below;
- ** (No institution paid for this code, so that's it).
- ** Permission is hereby granted to use or copy this code, in
- ** whole or in part, only under the conditions that this copyright
- ** notice (including other portions of this header comment and
- ** code herein referenced) are retained with all parts of this
- ** code; that all changes or corrections to this code be fully
- ** annotated in the code and notification of such be sent to
- ** the author and authors institution; and that this code not
- ** specifically be used for profit (although it may be included
- ** to enhance a larger work which would otherwise have still
- ** been used for profit).
- **
- ** Syntax:
- ** setlimits(filename)
- ** char *filename;
- ** getlimit(name, buf, length)
- ** char *name; int buf[], length;
- ** endlimits()
- **
- ** Description:
- ** This is an implementation of the suggested code to read the
- ** per-machine limits from a limits file. It assumes a file of
- ** the format:
- ** limit-name limit-value[, limit_value ... ]
- ** e.g.:
- ** char_bit 8
- ** char_min -128
- ** char_max 128
- ** etc. Lines that start with '#' are assumed to be comment
- ** lines. Lines that start with white space are assumed to
- ** be continuation lines.
- **
- ** Setlimits() returns SUCCESS if the file whose name is passed
- ** is readable, FAILURE if not. On a SUCCESS return, the file is
- ** set but not opened. A NULL argument returns to the original
- ** file name. Getlimit() returns FAILURE if no value, otherwise
- ** the number of values available. (May be > length.)
- ** Endlimits() closes the limits file, if open. No value is
- ** returned.
- **
- #ifdef SCCS
- ** Last modifed %G% %U%. Last retrieved %H% %T%.
- #endif SCCS
- **
- ** Author:
- ** Joseph S. D. Yao
- ** Engineering and Information Sciences Division
- ** Hadron, Inc.
- ** 9990 Lee Highway
- ** Fairfax VA 22030
- ** (703) 359-6163
- **
- ** Routines:
- ** int setlimits(filename)
- ** int getlimit(name, buf, length)
- ** void endlimits()
- ** static int getnum(str)
- **
- ** Declared:
- ** static char limfile[] = "/etc/limits"
- ** static char *curlimfile = limfile
- ** static FILE *limf = (FILE *) NULL
- **
- \*********************************************************************/
-
- #ifndef lint
- # ifdef SCCS
- static char SCCS_id[] = "%W%";
- # else
- static char RCS_id[] =
- "@(#)$Header:$";
- # endif SCCS
- #endif lint
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef limits
- # include <limits.h>
- #endif limits
- #include <sys/types.h>
-
- /* #include "std.h" */
- #define TRUE 1
- #define FALSE 0
-
- #define SUCCESS 0
- #define FAILURE (-1)
-
- #define NUL '\0'
-
- #define STDIN 0
- #define STDOUT 1
- #define STDERR 2
-
- #define ROPEN 0
- #define WOPEN 1
- #define RWOPEN 2
- #define XOPEN 3
- #define RXOPEN 4
- #define WXOPEN 5
- #define RWXOPEN 6
-
- #define READ "r"
- #define WRITE "w"
- #define APPEND "a"
- #define WREAD "r+"
- #define RWRITE "w+"
- #define RAPPEND "a+"
-
- #define F_ACC 00
- #define X_ACC 01
- #define W_ACC 02
- #define R_ACC 04
-
- #define ever (;;)
- #define until(x) while (!(x))
- #define unless(x) if (!(x))
-
- #define streq(a,b) (strcmp(a, b) == 0)
- #define strneq(a,b,n) (strncmp(a, b, n) == 0)
-
- typedef char bool; /* Smallest data object */
- typedef int boolean; /* Function argument and return. */
- /**/
-
- #define NL '\n'
- #define COMMENT '#'
- #define COMMA ','
- #define PLUS '+'
- #define MINUS '-'
-
- static char limfile[] = "/etc/limits";
- static char *curlimfile = limfile;
-
- static FILE *limf = (FILE *) NULL;
-
- /*
- ** Setlimits() returns SUCCESS if the file whose name is passed
- ** is readable, FAILURE if not. On a SUCCESS return, the file is
- ** set but not opened. A NULL argument returns to the original
- ** file name, whether or not the original file is readable.
- ** Note that a non-NULL filename must not disappear (e.g., be
- ** reclaimed on the stack, free'd, or written over) before it
- ** is opened in getlimit()!
- */
- int setlimits(filename)
- char *filename; /* NULL or the name of the new limits file. */
- {
- void endlimits();
-
- /* If name is NULL, go to the original. */
- if (filename == (char *) NULL) {
- if (limf != NULL)
- endlimits();
- curlimfile = limfile;
- return(SUCCESS);
- }
-
- /* If new file can't be read, forget it. */
- if (access(filename, R_ACC) < 0)
- return(FAILURE);
-
- /* Close old open file. */
- if (limf != NULL)
- endlimits();
- /* And use new one. */
- curlimfile = filename;
- return(SUCCESS);
- }
-
- /*
- ** Getlimit() returns FAILURE if no value, otherwise the number
- ** of values available. The number of values may be > 'length';
- ** but the number stored into buf[] will never be.
- ** Note that the result is always returned as a number of integers.
- ** It is up to the calling program to put them together into longs,
- ** complexes, etc. or decompose them into chars, bitfields, or
- ** whatever.
- **
- ** The search starts from wherever it left off, which improves
- ** performance if names are called in order from the file.
- ** (Say, alphabetical order.)
- */
- int getlimit(name, buf, length)
- char *name; /* Name of the limit wanted. */
- int buf[]; /* Pointer to the array of int's for these values. */
- int length;
- {
- register char *cp;
- register int n;
- bool been_here;
- bool new_line;
- char inbuf[BUFSIZ];
- off_t current;
- extern char *index();
-
- /* If not open, open it. */
- if (limf == (FILE *) NULL)
- limf = fopen(curlimfile, READ);
-
- /* If still not open, kick it in. */
- if (limf == (FILE *) NULL)
- return(FAILURE);
-
- n = strlen(name);
- /* Find where we currently are in the file. */
- current = ftell(limf);
- /* Initialise boolean values. */
- new_line = TRUE;
- been_here = FALSE;
-
- /* Search, starting wherever we left off. */
- for ever {
- /* Get a line from the file */
- cp = fgets(inbuf, sizeof(inbuf), limf);
- if (cp != (char *) NULL) {
-
- /* If gotten, test: if start of line */
- if (new_line &&
- /* and not a comment line */
- *cp != COMMENT &&
- /* and not a continuation line */
- !isspace(*cp) &&
- /* and the limit name is first */
- strneq(cp, name, n) &&
- /* followed by white space */
- isspace(cp[n]))
- break; /* go handle it. */
-
- /* Check whether a NL terminated the read. */
- new_line = (index(cp, NL) != (char *) NULL);
- } else {
- /* If not gotten, re-cycle. */
-
- /*
- ** Make sure the file doesn't get changed
- ** and cause an infinite loop here.
- */
- if (been_here)
- return(FAILURE);
- been_here = TRUE;
-
- /* Go back. */
- (void) fseek(limf, (off_t) 0L, 0);
- /* Well this starts a new line, no? */
- new_line = TRUE;
- }
-
- /* If we're where we started, we failed. */
- if (current == ftell(limf))
- return(FAILURE);
- }
-
- /*
- ** We only get here if we have a line in inbuf (or the start
- ** of one) that contains the limit name. Skip over it and
- ** start passing values.
- */
- cp += n + 1;
- n = 0;
- /* Check whether a NL terminated the read. */
- new_line = (index(cp, NL) != (char *) NULL);
-
- /*
- ** Our value may be preceded by whitespace, and is ended
- ** by a comma or whitespace or comment or EOL.
- */
- for ever {
- /* Skip any initial white space. */
- while (isspace(*cp))
- ++cp;
-
- /* Check whether line is done. */
- if (*cp == COMMENT || *cp == NUL) {
- /* Save current position */
- current = ftell(limf);
- /* Get new line. */
- cp = fgets(inbuf, sizeof(inbuf), limf);
- /* If EOF, do it over again at loc 0. */
- if (cp == (char *) NULL) {
- (void) fseek(limf, (off_t) 0L, 0);
- current = (off_t) 0L;
- cp = fgets(inbuf, sizeof(inbuf), limf);
- /* There has to be data here. */
- if (cp == (char *) NULL) {
- /* "never happen" */
- break;
- }
- }
-
- /*
- ** If new line is start of line but no white
- ** space, go back to start of line and return.
- */
- if (!new_line || !isspace(*cp)) {
- (void) fseek(limf, current, 0);
- break;
- }
-
- /* Check whether a NL terminated the read. */
- new_line = (index(cp, NL) != (char *) NULL);
-
- continue;
- }
-
- /* If it can fit, store the present value. */
- if (n < length)
- buf[n] = getnum(cp);
-
- /* Count another value. */
- ++n;
-
- /*
- ** We want to break but not skip on space, COMMENT, and
- ** NUL. We want to skip and break on COMMA. We want
- ** just to skip over everything else.
- */
- while (!isspace(*cp) && *cp != COMMENT && *cp != NUL &&
- *cp++ != COMMA);
- }
-
- /* Return the number of values found. */
- return(n);
- }
-
- /*
- ** Endlimits() closes the limits file, if open. No value is
- ** returned.
- */
- void endlimits()
- {
- if (limf != (FILE *) NULL) {
- (void) fclose(limf);
- limf = (FILE *) NULL;
- }
- }
-
- /*
- ** This routine converts strings to numbers of base specified
- ** by 0x or 0 or no prefix. Signs are allowed. Atoi() isn't
- ** used because it doesn't allow different bases, and for the
- ** sake of consistency.
- */
- static int getnum(str)
- register char *str;
- {
- register int base = 10;
- register int i = 0, digit;
- register int sign = 1;
-
- while (isspace(*str) || *str == PLUS || *str == MINUS) {
- if (*str == MINUS)
- sign = -sign;
- ++str;
- }
-
- if (*str == '0') {
- ++str;
- if (*str == 'x') {
- ++str;
- base = 16;
- } else
- base = 8;
- }
-
- /*
- ** As opposed to code that assumes contiguous digits and
- ** letters, the following will work even for (*shudder*)
- ** EBCDIC. Heck, it'll work for TTS and Baudot!
- */
- for ever {
- digit = -1;
- switch (*str++) {
- case '0': digit = 0; break;
- case '1': digit = 1; break;
- case '2': digit = 2; break;
- case '3': digit = 3; break;
- case '4': digit = 4; break;
- case '5': digit = 5; break;
- case '6': digit = 6; break;
- case '7': digit = 7; break;
-
- case '8': if (base > 8) digit = 8; break;
- case '9': if (base > 9) digit = 9; break;
-
- case 'A':
- case 'a':
- if (base > 10)
- digit = 10;
- break;
-
- case 'B':
- case 'b':
- if (base > 11)
- digit = 11;
- break;
-
- case 'C':
- case 'c':
- if (base > 12)
- digit = 12;
- break;
-
- case 'D':
- case 'd':
- if (base > 13)
- digit = 13;
- break;
-
- case 'E':
- case 'e':
- if (base > 14)
- digit = 14;
- break;
-
- case 'F':
- case 'f':
- if (base > 15)
- digit = 15;
- break;
-
- default: break;
- }
-
- if (digit < 0)
- break;
-
- i *= base;
- i += digit;
- }
-
- if (sign < 0)
- return(-i);
- return(i);
- }
-
- Joe Yao hadron!jsdy@seismo.{CSS.GOV,ARPA,UUCP}
-
- Volume-Number: Volume 3, Number 24
-
-