code review: read in ps(1) result

L

lovecreatesbea...

/*thank you for your time*/

/*read in ps(1) result*/

#include <stdio.h>
#include <errno.h>
#include <sys/types.h>

#define M 256
#define N 32

#define str(n) #n /*from pete's*/
#define xstr(n) str(n)

int main(void)
{
char uid[N + 1];
pid_t pid;
pid_t ppid;
char stime[N + 1];
char cmd[M + 1];
char *ps = "ps -ef";
FILE *fp;
int errnum;
int n;

errno = 0;
if (!(fp = popen(ps, "r"))){
errnum = errno;
fprintf(stderr, "%s\n", strerror(errnum));
return 1;
}
errno = 0;
while((n = fscanf(fp, "%"xstr(N)"s %d %d %*s "
"%"xstr(N)"s %*s %*s %"xstr(M)"[^\n]",
uid, &pid, &ppid, stime, cmd)) != EOF){
if (n != 5){
fscanf(fp, "%*[^\n]");
continue;
}
fprintf(stdout, "%s, %d, %d, %s, %s\n",
uid, (int)pid, (int)ppid, stime, cmd);
errno = 0;
}
errnum = errno;
if (errnum)
fprintf(stderr, "%s\n", strerror(errnum));
pclose(fp);
return 0
}
 
E

Eric Sosman

[...]
errno = 0;
[...]
errnum = errno;
if (errnum)
fprintf(stderr, "%s\n", strerror(errnum));

No. Except as specifically documented (e.g., for strtod()),
any library function can set `errno' to a non-zero value, even
if no error occurs. Thus, finding `errno != 0' does not mean
there has been an error. Also, only a few library functions are
obliged to set `errno' when an error occurs -- for example, a
failing fopen() is not required to set it -- so `errno == 0' does
not imply the absence of errors. You have to detect success/failure
by other means, and then (perhaps) consult `errno' for further
information about a failure.
 
K

Keith Thompson

Eric Sosman said:
[...]
errno = 0;
[...]
errnum = errno;
if (errnum)
fprintf(stderr, "%s\n", strerror(errnum));

No. Except as specifically documented (e.g., for strtod()),
any library function can set `errno' to a non-zero value, even
if no error occurs. Thus, finding `errno != 0' does not mean
there has been an error. Also, only a few library functions are
obliged to set `errno' when an error occurs -- for example, a
failing fopen() is not required to set it -- so `errno == 0' does
not imply the absence of errors. You have to detect success/failure
by other means, and then (perhaps) consult `errno' for further
information about a failure.

To expand on that a bit, some secondary standards may specify that
certain standard C functions must set errno on failure. For example,
POSIX requires fopen() to set errno to one of several values (none
of which are defined by the C standard). And I don't know of any
C implementations, POSIX or otherwise, in which fopen() *doesn't*
set errno to some sensible value on failure (but my experience
is sufficiently limited that I probably wouldn't know about them
anyway).

If you're only concerned with POSIX-compliant systems, you can assume
that the value of errno is meaningful after a call to fopen() --
but *only* if you set errno to 0 before the call *and* fopen()
reported failure by returning a null pointer (otherwise errno
could be set to some spurious value, either by previous code or by
something called internally by fopen().

For non-POSIX systems, you can *probably* assume that errno is
meaningful under the above circumstances (and perror() and/or
strerror() will give you a useful message), but that's not at all
guaranteed by the C standard.

Note that the only errno values specified by the C standard itself
are 0, EDOM, EILSEQ, and ERANGE. Anything beyond that is left to
secondary standards and to individual implementations.
 
B

Ben Pfaff

Keith Thompson said:
To expand on that a bit, some secondary standards may specify that
certain standard C functions must set errno on failure. For example,
POSIX requires fopen() to set errno to one of several values (none
of which are defined by the C standard). And I don't know of any
C implementations, POSIX or otherwise, in which fopen() *doesn't*
set errno to some sensible value on failure (but my experience
is sufficiently limited that I probably wouldn't know about them
anyway).

malloc() may be a better example. POSIX requires malloc() to set
errno to ENOMEM on failure, if memory is not available. But a
lot of non-POSIX implementations in fact do not do this (and
ENOMEM is not defined by ISO C).
 
N

Nobody

Note that the only errno values specified by the C standard itself
are 0, EDOM, EILSEQ, and ERANGE. Anything beyond that is left to
secondary standards and to individual implementations.

That should provide a clue as to which functions are required (by the C
standard) to set errno under some circumstances (hint: not many of them).

errno is basically a POSIX feature which managed to leak into the C
standards. POSIX itself defines 81 possible non-zero values for errno,
while Linux currently defines 129 (1 through 131, with 41 and 58 unused).

http://www.opengroup.org/onlinepubs/9699919799/basedefs/errno.h.html
 
L

lawrence.jones

Keith Thompson said:
And I don't know of any
C implementations, POSIX or otherwise, in which fopen() *doesn't*
set errno to some sensible value on failure

Traditional Unix implementations didn't explicitly set errno but most
fopen() failures are caused by the failure of an underlying system call
which does, so it works in most cases. But not all: there were some
obscure failure modes that left errno set to a nonsensical value.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,763
Messages
2,569,563
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top