limits
Moderator, John Quarterman
std-unix at ut-sally.UUCP
Wed Nov 20 09:38:14 AEST 1985
[ One thing to remember in this discussion is that standards committees
are loath to attempt to standardize and innovate at the same time.
In this particular posting (as in any others), note that parenthetical
remarks in square brackets are those of the moderator only if they end
with -mod ]
Date: Tue, 19 Nov 85 10:00:44 cst
From: allegra!jpl
> 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.
Let's kick it around a little first. I agree with your decision to
keep this out of the kernel, but I'll amplify to avoid misunderstandings.
1) I want a general mechanism that applies to all include
files, not just limits.h.
2) The kernel is a lousy place to store the limits.h information.
It is preposterous to have a separate system call for each
value. If you return a structure that includes all the values,
you trash existing binaries whenever you make the returned
structure larger by adding another value. If you use an index
to return a single value, you can only port to systems that
agree with you on the index values.
3) It is unworkable. If I want to run my code on a kernel where
the maintainers (wisely) refused to clutter up their system,
not only can I not port my binaries, I can't even port my
source code.
KEEP THIS AT USER LEVEL WHERE IT BELONGS! AND WHERE WE CAN CONTROL IT!!!
[Pardon me, I seem to be getting carried away in a moderated newsgroup.]
[ Now that you mention it.... -mod ]
My major gripe with Joseph's solution is point 1) above [although his
program can be made to serve for other include files] together with a
hard-earned awareness that duplicating information from limit.s in a
file like /etc/limits WITHOUT ENFORCING THE CONSISTENCY OF THAT
INFORMATION is a sure recipe for disaster. So let's try to address the
problems with reading directly from limits.h. To keep the discussion
concrete, I have a first-cut at such a program at the end of this
diatribe. Type lines like
<stdio.h> _NFILE NULL frobaz
at it, and it will tell you what the values of _NFILE, NULL and frobaz
are according to include file <stdio.h>. If you actually run the
program, you will recognize one problem. It's slow. I claim this is
a non-problem: look up your values once, and then run nice and fast.
If you READ the program (unencumbered as it is by comments), you will
discover more serious problems.
1) The program uses ``cc -E'' and ``sed'' to extract the information.
I can't glibly laugh this one off. If you don't have cc (the sed
part could be built into the program) on the target machine, you
can't look up the values. I see this as by far the most serious
problem, even though all the machines I use have cc.
2) It relies on unpromised characteristics of the C preprocessor.
The value to be looked up gets sandwiched between ``=== '' and
`` ===\n'', and sed expects to find the value on a line of this
form. The preprocessor is free to tamper with the format of
the line, although, on all the machines I have tried it on, it
leaves the format alone. This is not such a big deal. In a
practical implementation, the action of sed should probably be
replaced by more robust [and efficient] code in the lookup
routine. Another alternative would be to generate a real
C program, compile it and execute it to generate the results.
This would eliminate any peculiarities of the preprocessor,
but it would mean that the include file be syntactically
complete. For example, you couldn't have any undefined externs,
or undeclared types. [I have railed elsewhere on the value of
of making all #include files idempotent, and then always including
everything you need. I'll spare you a playback.]
3) It only applies to #defined constants. Another non-problem.
Variables should be initialized using #defined constants anyway,
so there should be a #defined constant around to use.
4) The runtime environment is lacking all sorts of -D and -I
arguments and the working directory that may make a difference
at compile time. Two answers: if they REALLY make a difference,
neither a kernel-based nor a fixed table-based solution will do
any better. In fact, it would be real nice if this information
were available in symbolic form at compile time, so one could
drop the information in the object code, as one does with SCCS
or RCS information. It would often be invaluable to be able to
snuffle through a binary and determine what compile-time options
were used to produce it. If that were possible (I won't hold my
breath), the lookup routine could more nearly duplicate what
happened at compile time, and address the gripe about the lack
of #if's.
Enough from me for now. The promised code follows.
John P. Linderman Better Living through Portability allegra!jpl
#include <stdio.h>
static char **
mkvect(file, lines)
char *file;
int lines;
{
FILE *iop;
char **pp, *p;
char *malloc();
char **retval = (char **) NULL;
int c;
int chars = 0;
int vects = 1;
if ((lines > 0) && ((iop = fopen(file, "r")) != NULL)) {
while ((c = getc(iop)) != EOF) {
chars++;
if (c == '\n') vects++;
}
if ((ferror(iop) == 0) && (lines == vects)) {
retval = (char **) malloc((vects * sizeof(char *)) + chars);
if (retval != (char **) NULL) {
(void) clearerr(iop);
(void) rewind(iop);
p = (char *)(retval + vects);
pp = retval;
*pp++ = p;
do {
if ((c = getc(iop)) == EOF) {
(void) free((char *) retval);
retval = (char **) NULL;
break;
}
if (c == '\n') {
*p++ = '\0';
*pp++ = p;
} else *p++ = c;
} while (--chars);
if (c != EOF) *--pp = (char *) NULL;
}
}
(void) fclose(iop);
}
return (retval);
}
char **
rtlook(inc, val)
char *inc;
char **val;
{
#define NAMEZ 12
static char tmplate[NAMEZ] = "/tmp/XXXXXX";
char ifile[NAMEZ];
char ofile[NAMEZ];
char commnd[512];
char *strcpy(), *mktemp();
char **retval = (char **) NULL;
int n = 1;
FILE *iop, *popen();
(void) strcpy(ifile, tmplate);
(void) mktemp(ifile);
if ((iop = fopen(ifile, "w")) != NULL) {
(void) strcpy(ofile, tmplate);
(void) mktemp(ofile);
(void) fprintf(iop, "#include %s\n", inc);
for (; (*val != NULL) && (**val != '\0'); n++, val++) {
(void) fprintf(iop, "\n#ifdef %s\n", *val);
(void) fprintf(iop, "=== %s ===\n", *val);
(void) fprintf(iop, "#else\n");
(void) fprintf(iop, "=== ===\n");
(void) fprintf(iop, "#endif\n");
}
if ((fflush(iop) != EOF) && !ferror(iop) &&
(fclose(iop) != EOF)) {
(void) sprintf(commnd,
"cc -E %s | sed -n '/^=== \\(.*\\) ===$/s//\\1/p' > %s",
ifile, ofile);
(void) system(commnd);
retval = mkvect(ofile, n);
(void) unlink(ofile);
}
(void) unlink(ifile);
}
return (retval);
}
#include <ctype.h>
main()
{
char line[512];
char *p, **qq, **pp, *q[300];
int n;
while (gets(line) != NULL) {
for (p = line, pp = q; *p;) {
while (isspace(*p)) *p++ = '\0';
if (*p) {
*pp++ = p;
do p++; while(*p && !isspace(*p));
}
}
*pp = NULL;
if (pp != q) {
if ((qq = rtlook(q[0], q+1)) == NULL) {
(void) printf("lookup failed\n");
} else {
n = 0;
for (pp = q+1; (*pp != (char *) NULL) && **pp; pp++, n++) {
(void) printf("%s => %s\n", *pp, qq[n]);
}
(void) free((char *) qq);
}
}
}
}
Volume-Number: Volume 3, Number 27
More information about the Mod.std.unix
mailing list