allyn@sleepy.UUCP (Mark Allyn) (06/12/91)
I need to be able to take what is printed when you call perror
and put it into a string variable to be used in a c program.
I know that the errno variable is an external variable which points
to some internal table in the kernel called sys_errlist.
Is there some way of getting at that table so that I can get at the
error messages?
I tried the following logical solution after RTFM but it did not
work (it got a seg fault)
goo.c
______________________________________________________
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/vfs.h>
#include <sys/syslog.h>
#include <errno.h>
main()
{
extern char **sys_errlist;
FILE *fpp;
int ctr1;
fpp=fopen("/goo","w");
perror("");
printf("errno is %d\n",errno);
printf("%d\n",(int)*(sys_errlist+errno));
}
_____________________________________________________
I compiled and linkded this program with
cc -g goo.c
jik@cats.ucsc.edu (Jonathan I. Kamens) (06/13/91)
In article <212@sleepy.UUCP>, allyn@sleepy.UUCP (Mark Allyn) writes: |> I need to be able to take what is printed when you call perror |> and put it into a string variable to be used in a c program. Check if your system has a function named strerror, that takes an int (usually errno) and returns a string. If it has it, there should be a man page for it. If there is, then use it. If not, you'll have to use sys_errlist, as you're trying to do. But you're not quite doing it right.... |> I know that the errno variable is an external variable which points |> to some internal table in the kernel called sys_errlist. sys_errlist is not "some internal table in the kernel," it's an array of strings compiled into the C library. The other variable you need to know about is the int sys_nerr, which contains the number of strings in sys_errlist. Before trying to reference a string in sys_errlist, you need to check if errno is less than sys_nerr; if it is not, then the error does not have a corresponding string in the sys_errlist. |> I tried the following logical solution after RTFM but it did not |> work (it got a seg fault) I see a couple of problems. |> extern char **sys_errlist; This should be "extern char *sys_errlist[];". Also, you should declare "extern int sys_nerr;". |> printf("%d\n",(int)*(sys_errlist+errno)); This should be if (errno < sys_nerr) printf("%s\n", sys_errlist[errno]); else printf("Unknown error\n"); -- Jonathan Kamens jik@CATS.UCSC.EDU
mouse@thunder.mcrcim.mcgill.edu (der Mouse) (06/15/91)
In article <212@sleepy.UUCP>, allyn@sleepy.UUCP (Mark Allyn) writes: > I need to be able to take what is printed when you call perror and > put it into a string variable to be used in a c program. > I know that the errno variable is an external variable which points > to some internal table in the kernel called sys_errlist. Not in the kernel; it's part of the C library. > Is there some way of getting at that table so that I can get at the > error messages? Certainly. > I tried the following logical solution after RTFM but it did not work > (it got a seg fault) Let's have a look.... > #include <stdio.h> > #include <signal.h> > #include <sys/types.h> > #include <sys/vfs.h> > #include <sys/syslog.h> > #include <errno.h> Why in the world are you including all those things? The only ones that have any relevance are <stdio.h> and <errno.h> (and see my fifth note below for a remark about the latter). > main() > { > extern char **sys_errlist; It's an array, not a pointer (try `extern char *sys_errlist[];'). > FILE *fpp; > int ctr1; > > fpp=fopen("/goo","w"); > perror(""); > printf("errno is %d\n",errno); > printf("%d\n",(int)*(sys_errlist+errno)); First, fopen is not guaranteed to leave anything useful in errno, at least not generally. (Your system may make such a promise, but it is not portable to assume so.) It frequently will do so, but you can't count on it. Second, the perror and printf calls may destroy errno, since it is no part of their contract to preserve it. You should save it in a variable of your own. Third, you should check that errno is within the range [0..sys_nerr), because the sys_errlist table may lag the system for new error codes. Fourth, why are you casting the string from sys_errlist to an int?! Fifth, a minor point: not all systems' <errno.h> actually declare errno. For portability you have to declare it yourself. (Yes, I agree this is a botch. Portability sometimes means putting up with botches.) And since this is the only thing <errno.h> does for you in this case, you can get rid of it once you add the declaration - though in a real program, where you use some of the Exxx values, you have to keep it.) > } Putting all this together, we get the following. (Well, most of it; this modified version still assumes that fopen() will leave something useful in errno. To do it right you should call open(2) directly, followed by fdopen() if the open() succeeds and you need a FILE *.) #include <stdio.h> main() { extern int errno; extern int sys_nerr; extern char *sys_errlist[]; FILE *fpp; int save_errno; fpp=fopen("/goo","w"); save_errno = errno; perror(""); printf("errno is %d\n",save_errno); if ((save_errno >= 0) && (save_errno < sys_nerr)) printf("%s\n",sys_errlist[save_errno]); else printf("Unknown error code %d\n",save_errno); } der Mouse old: mcgill-vision!mouse new: mouse@larry.mcrcim.mcgill.edu
dold@mitisft.Convergent.COM (Clarence Dold) (06/17/91)
in article <1991Jun15.151924.24619@thunder.mcrcim.mcgill.edu>, mouse@thunder.mcrcim.mcgill.edu (der Mouse) says: ... > Third, you should check that errno is within the range [0..sys_nerr), > because the sys_errlist table may lag the system for new error codes. ... > printf("errno is %d\n",save_errno); > if ((save_errno >= 0) && (save_errno < sys_nerr)) > printf("%s\n",sys_errlist[save_errno]); > else > printf("Unknown error code %d\n",save_errno); > } printf("Errno %d: %s\n", want_err, want_err <= sys_nerr ? sys_errlist[want_err] : "Out of range" ); I like this one because it's one of the few places where the " ? : " construct looks correct to me. -- --- Clarence A Dold - dold@tsmiti.Convergent.COM ...pyramid!ctnews!tsmiti!dold
boyd@prl.dec.com (Boyd Roberts) (06/17/91)
In article <2157@mitisft.Convergent.COM>, dold@mitisft.Convergent.COM (Clarence Dold) writes: > printf("Errno %d: %s\n", want_err, > want_err <= sys_nerr ? sys_errlist[want_err] : "Out of range" ); > > I like this one because it's one of the few places where the " ? : " > construct looks correct to me. Eh? The bounds of a reasonable errnos lie between 1 and sys_nerr. `errno == 0' means no error. Boyd Roberts boyd@prl.dec.com ``When the going gets wierd, the weird turn pro...''
gwyn@smoke.brl.mil (Doug Gwyn) (06/17/91)
In article <1991Jun17.124318.1384@prl.dec.com> boyd@prl.dec.com (Boyd Roberts) writes: -In article <2157@mitisft.Convergent.COM>, dold@mitisft.Convergent.COM (Clarence Dold) writes: -> printf("Errno %d: %s\n", want_err, -> want_err <= sys_nerr ? sys_errlist[want_err] : "Out of range" ); -> I like this one because it's one of the few places where the " ? : " -> construct looks correct to me. -Eh? The bounds of a reasonable errnos lie between 1 and sys_nerr. -`errno == 0' means no error. Which is probably why sys_errlist[0] contains "Error 0".
jik@cats.ucsc.edu (Jonathan I. Kamens) (06/18/91)
In article <2157@mitisft.Convergent.COM>, dold@mitisft.Convergent.COM (Clarence Dold) writes: |> printf("Errno %d: %s\n", want_err, |> want_err <= sys_nerr ? sys_errlist[want_err] : "Out of range" ); The "<=" should be "<". Sys_nerr records the number of elements in the sys_errlist array, which means the highest valid index in the array is sys_nerr-1, and the lowest is 0. -- Jonathan Kamens jik@CATS.UCSC.EDU
dold@mitisft.Convergent.COM (Clarence Dold) (06/18/91)
in article <1991Jun17.124318.1384@prl.dec.com>, boyd@prl.dec.com (Boyd Roberts) says: > In article <2157@mitisft.Convergent.COM>, dold@mitisft.Convergent.COM (Clarence Dold) writes: >> printf("Errno %d: %s\n", want_err, >> want_err <= sys_nerr ? sys_errlist[want_err] : "Out of range" ); > Eh? The bounds of a reasonable errnos lie between 1 and sys_nerr. > `errno == 0' means no error. But sys_errlist[0] does contain a string, so it shouldn't be excluded, unless you especially like to have extra instructions in your code. -- --- Clarence A Dold - dold@tsmiti.Convergent.COM ...pyramid!ctnews!tsmiti!dold
torek@elf.ee.lbl.gov (Chris Torek) (06/19/91)
>In article <212@sleepy.UUCP>, allyn@sleepy.UUCP (Mark Allyn) writes: >>I need to be able to take what is printed when you call perror >>and put it into a string variable to be used in a c program. In article <16982@darkstar.ucsc.edu> jik@cats.ucsc.edu (Jonathan I. Kamens) writes: > Check if your system has a function named strerror, that takes an int >(usually errno) and returns a string. ... If not, you'll have to use >sys_errlist ... In fact, if you do not have strerror(), you should write it in terms of sys_errlist: > if (errno < sys_nerr) > printf("%s\n", sys_errlist[errno]); > else > printf("Unknown error\n"); Better: #include <stdio.h> char * strerror(err) register int err; { extern char *sys_errlist[]; extern int sys_nerr; static char unknown[19+40+1]; /* 19: strlen("Unknown error code ") + 40: max length of 128 bit int in decimal (-170141183460469231731687303715884105728) + 1: final '\0' */ if ((unsigned)err < sys_nerr) return (sys_errlist[err]); (void) sprintf(unknown, "Unknown error code %d", err); return (unknown); } -- In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427) Berkeley, CA Domain: torek@ee.lbl.gov
dcoskun@alias.com (Denis Coskun) (06/20/91)
In <17138@darkstar.ucsc.edu> jik@cats.ucsc.edu (Jonathan I. Kamens) writes: > Sys_nerr records the number of elements in the sys_errlist array, > which means the highest valid index in the array is sys_nerr-1, > and the lowest is 0. While I agree that this makes sense, is this really established practice or standardized? I ask because SGIs (Irix 3.3.2) have messages for indices 0 through sys_nerr. This program, #include <stdio.h> #include <errno.h> extern int sys_nerr; extern char *sys_errlist[]; main() { printf("ENFSREMOTE = %d\n", ENFSREMOTE); printf("sys_nerr = %d\n", sys_nerr); printf("sys_errlist[sys_nerr] = `%s'\n", sys_errlist[sys_nerr]); } gives the following output: ENFSREMOTE = 135 sys_nerr = 135 sys_errlist[sys_nerr] = `Too many levels of remote in path' -- Denis Coskun Alias Research Inc. Toronto Canada dcoskun@alias.com
jik@cats.ucsc.edu (Jonathan I Kamens) (06/22/91)
In article <1991Jun19.215654.18120@alias.com>, dcoskun@alias.com (Denis Coskun) writes: |> In <17138@darkstar.ucsc.edu> jik@cats.ucsc.edu (Jonathan I. Kamens) writes: |> > Sys_nerr records the number of elements in the sys_errlist array, |> > which means the highest valid index in the array is sys_nerr-1, |> > and the lowest is 0. |> |> While I agree that this makes sense, is this really established practice |> or standardized? I ask because SGIs (Irix 3.3.2) have messages for indices |> 0 through sys_nerr. Well, here's my test program: main() { extern int sys_nerr; extern char *sys_errlist[]; printf("sys_nerr = %d\n", sys_nerr); printf("sys_errlist[sys_nerr] = 0x%x\n", sys_errlist[sys_nerr]); printf("sys_errlist[sys_nerr] = \"%s\"\n", sys_errlist[sys_nerr]); } It produces the following on an IBM RT/PC running AOS 4.3: sys_nerr = 76 sys_errlist[sys_nerr] = 0x4c sys_errlist[sys_nerr] = "1 h__" It produces the following on a VAX running BSD 4.3: sys_nerr = 76 sys_errlist[sys_nerr] = 0x4c sys_errlist[sys_nerr] = "}" It produces the following on a DECstation 3100 running Ultrix 3.1: sys_nerr = 75 sys_errlist[sys_nerr] = 0x20746f4e Segmentation violation (core dumped) It produces the following on the NeXT machine: sys_nerr = 84 sys_errlist[sys_nerr] = 0x0 sys_errlist[sys_nerr] = "(null pointer)" It produces the following on an IBM PS/2 running AIX 1.2: sys_nerr = 109 sys_errlist[sys_nerr] = 0x6d sys_errlist[sys_nerr] = "!" It produces the following on an i386 machine running SysVr4: sys_nerr = 152 sys_errlist[sys_nerr] = 0x98 sys_errlist[sys_nerr] = "" It produces the following on a Mac running A/UX: sys_nerr = 103 sys_errlist[sys_nerr] = 0x67 sys_errlist[sys_nerr] = "d" It produces the following on a Sparc running SunOS 4.1.1: sys_nerr = 91 sys_errlist[sys_nerr] = 0x5b Segmentation fault In case it's not obvious by now :-), what I'm trying to imply is that Irix 3.3.2 is probably wrong here. -- Jonathan Kamens jik@CATS.UCSC.EDU