Try this. I wrote it while practicing with APUE.
/*
* FILE: list-homepages.c
* AUTHOR: Alan Shutko
* DATE: Wed Sep 18 1996
*
*/
static char *rcsid = "$Header: /home/ats/Software/list-homepages.c,v 1.7.1.4
1997/03/19 22:50:07 ats Exp $";
#define HTML_DIR "/public_html"
#define SORT_COMMAND "/bin/sort"
#define HEADER_FILE "su-header.html"
#define FOOTER_FILE "su-footer.html"
#include <sys/wait.h>
#include <errno.h>
#include <limits.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
typedef enum err_status
{
ERR_RETURN,
ERR_QUIT,
ERR_DUMP
} err_status ;
void error_system(err_status errflag, const char *fmt, ...);
void error_user(err_status errflag, const char *fmt, ...);
size_t copy_file(FILE* in, FILE* out);
#define MAXLINE 4096
int main()
{
struct stat dir;
int i;
struct passwd *pwent;
char path[PATH_MAX];
char *fullname, *tmp;
int fd[2];
pid_t pid;
FILE* fp;
size_t count;
fprintf(stdout, "Content-type: text/html\n\n");
if ((fp = fopen(HEADER_FILE, "r")) != NULL)
copy_file(fp, stdout);
else
{
fprintf(stdout, "<HTML><HEAD>\n");
fprintf(stdout, "<title>Group Home Pages</title>\n");
fprintf(stdout, "<body>\n");
fprintf(stdout, "<h1>Group Home Pages</h1>\n");
fprintf(stdout, "<ul>\n");
}
fflush(NULL);
if (pipe(fd) < 0)
error_system(ERR_QUIT, "error creating pipe in line %d", __LINE__);
if ( (pid = fork()) < 0)
error_system(ERR_QUIT, "error in fork");
else if (pid > 0) /* parent */
{
FILE* pipep;
if ((pipep = fdopen(fd[1], "w")) == NULL)
error_system(ERR_QUIT, "error in fdopen");
for (i = 1; (pwent = getpwent()); i++)
{
if (pwent->pw_gid != 2000) /* not student group */
continue;
strcpy(path, pwent->pw_dir);
strcat(path, HTML_DIR);
if ((strlen(pwent->pw_gecos)) > 0) /* Use GECOS. Strip comma */
{
if ( (fullname = malloc(1+sizeof(char) *
strlen(pwent->pw_gecos)))
== NULL)
error_system(ERR_DUMP, "could not get memory for fullname");
/* Strip commas */
strcpy(fullname, pwent->pw_gecos);
if ((tmp = strpbrk(fullname, ",")) != NULL)
*tmp = '\0';
}
else /* Use pw_name */
{
if ((fullname = malloc(1+sizeof(char) *
strlen(pwent->pw_name)))
== NULL)
error_system(ERR_DUMP,
"could not get memory for fullname");
strcpy(fullname, pwent->pw_name);
}
if (stat(path, &dir) < 0) /* doesn't exist */
{
free(fullname);
continue;
}
fprintf(pipep, "<!--%s--><li><a href=\"/~%s/\">%s</a>\n",
fullname, pwent->pw_name, fullname);
free(fullname);
}
fclose(pipep);
close(fd[1]);
}
else
{
close(fd[1]);
if (fd[0] != STDIN_FILENO)
{
if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO)
error_system(ERR_QUIT, "error dup2 to stdin");
close(fd[0]);
}
execlp(SORT_COMMAND, "sort", (char *)0);
/* Error has occured if we get here */
error_system(ERR_QUIT, "error in exec");
exit(0);
}
wait(NULL);
if ((fp = fopen(FOOTER_FILE, "r")) != NULL)
copy_file(fp, stdout);
else
fprintf(stdout, "</body>\n");
exit(0);
}
/*@@
@routine error_system
@date Thu Sep 12 14:27:20 1996
@author Alan Shutko
@desc
This call signals an error in handling a system call to the user.
It will print a error string (with standard printf handling), print
the system error, then continue as specified in the abort
parameter.
If abort is RETURN, error_system will return to the caller. If
QUIT, it will call exit(EXIT_FAILURE). If DUMP, it will call
abort().
@enddesc
@calls
@calledby
@var abort
@vdesc Details what action to take after error is printed
@vtype err_status
@vio in
@var fmt
@vdesc format string
@vtype char*
@vio in
@vcomment
Printf style handline
@endvar
@@*/
void error_system(err_status errflag, const char *fmt, ...)
{
va_list args;
int errno_save; /* prevent errors from printf */
char buf[MAXLINE];
va_start(args, fmt);
errno_save = errno;
vsprintf(buf, fmt, args);
sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
fputs(buf, stderr);
fflush(NULL);
va_end(args);
switch (errflag)
{
case ERR_RETURN:
return;
case ERR_DUMP:
abort();
case ERR_QUIT:
exit(EXIT_FAILURE);
default:
error_user(ERR_DUMP, "Bad call to error_system!");
}
}
/*@@
@routine error_user
@date Thu Sep 12 14:40:10 1996
@author Alan Shutko
@desc
This call signals an error in userspace to the user. It will print
a error string (with standard printf handling).
If abort is RETURN, error_system will return to the caller. If
QUIT, it will call exit(EXIT_FAILURE). If DUMP, it will call
abort().
@enddesc
@calls
@calledby
@var abort
@vdesc Details what action to take after error is printed
@vtype err_status
@vio in
@var fmt
@vdesc format string
@vtype char*
@vio in
@vcomment
Printf style handline
@endvar
@@*/
void error_user(err_status errflag, const char *fmt, ...)
{
va_list args;
int errno_save;
/* prevent errors from printf */
char buf[MAXLINE];
va_start(args, fmt);
errno_save = errno;
vsprintf(buf, fmt, args);
strcat(buf, "\n");
fputs(buf, stderr);
fflush(NULL);
va_end(args);
switch (errflag)
{
case ERR_RETURN:
return;
case ERR_DUMP:
abort();
case ERR_QUIT:
exit(EXIT_FAILURE);
default:
error_user(ERR_DUMP, "Bad call to error_system!");
}
}
size_t copy_file(FILE* in, FILE* out)
{
size_t count, total;
char buf[BUFSIZ];
while (!feof(in))
{
if (!(count = fread(buf, sizeof(char), BUFSIZ, in) ))
error_system(ERR_QUIT, "fread failed");
if ((fwrite(buf, sizeof(char), count, out)) != count)
error_system(ERR_QUIT, "fwrite failed");
total += count;
}
return(total);
}
/*
* Local Variables:
* compile-command: "gcc -Wall -o list-homepages list-homepages.c"
* End:
*/
--
Alan Shutko <[EMAIL PROTECTED]> - By consent of the corrupted
I'm successful because I'm lucky. The harder I work, the luckier I get.
--
PLEASE read the Red Hat FAQ, Tips, Errata and the MAILING LIST ARCHIVES!
http://www.redhat.com/RedHat-FAQ /RedHat-Errata /RedHat-Tips /mailing-lists
To unsubscribe: mail [EMAIL PROTECTED] with
"unsubscribe" as the Subject.