This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / libexec / elvispreserve / prsvunix.c
/* prsvunix.c */
/* This file contains the UNIX-specific parts of the "elvprsv" program. */
#if OSK
#define ELVPRSV
#include "osk.c"
#else
#include <sys/stat.h>
#include <pwd.h>
#endif
#ifndef __STDC__
/* some older systems don't declare this in pwd.h, I guess. */
extern struct passwd *getpwuid();
#endif
#if ANY_UNIX /* { */
/* Since elvprsv runs as SUID-root, we need a *secure* version of popen() */
#define popen safe_popen
#define pclose safe_pclose
/* This function is similar to the standard popen() function, except for...
* 1) It doesn't use the shell, for security reasons.
* 2) Shell services are not supported, including quoting.
* 3) The mode can only be "w". "r" is not supported.
* 4) No more than 9 arguments can be given, including the command.
*/
/*ARGSUSED*/
static FILE *safe_popen(cmd, mode)
char *cmd; /* the filename of the program to be run */
char *mode; /* "w", ignored */
{
char path[100];/* full pathname of argv[0] */
char *argv[10];/* the arguments */
int r0w1[2];/* the pipe fd's */
int i;
FILE *fp;
/* parse the arguments */
for (i = 0; i < 9 && *cmd; i++)
{
/* remember where this arg starts */
argv[i] = cmd;
/* move to the end of the argument */
do
{
cmd++;
} while (*cmd && *cmd != ' ');
/* then mark end of arg & skip to next */
while (*cmd && *cmd == ' ')
{
*cmd++ = '\0';
}
printf("argv[%d]=\"%s\"\n", i, argv[i]);
}
argv[i] = (char *)0;
/* make the pipe */
if (pipe(r0w1) < 0)
{
perror("pipe()");
return (FILE *)0; /* pipe failed */
}
switch (fork())
{
case -1: /* error */
perror("fork()");
return (FILE *)0;
case 0: /* child */
/* close the "write" end of the pipe */
close(r0w1[1]);
/* redirect stdin to come from the "read" end of the pipe */
close(0);
dup(r0w1[0]);
close(r0w1[0]);
/* exec the shell to run the command */
if (*argv[0] != '/')
{
/* no path, try "/bin/argv[0]" */
strcpy(path, "/bin/");
strcat(path, argv[0]);
execv(path, argv);
perror(path);
/* if that failed, then try "/usr/bin/argv[0]" */
strcpy(path, "/usr/bin/");
strcat(path, argv[0]);
execv(path, argv);
perror(path);
}
else
{
/* full pathname given, so use it */
execv(argv[0], argv);
perror(argv[0]);
}
/* if we get here, exec failed */
exit(1);
default: /* parent */
/* close the "read" end of the pipe */
close(r0w1[0]);
/* convert the "write" fd into a (FILE *) */
fp = fdopen(r0w1[1], "w");
return fp;
}
/*NOTREACHED*/
}
/* This function closes the pipe opened by popen(), and returns 0 for success */
static int safe_pclose(fp)
FILE *fp; /* value returned by popen() */
{
int status;
/* close the file, and return the defunct child's exit status */
fclose(fp);
wait(&status);
return status;
}
#endif /* } ANY UNIX */
/* This variable is used to add extra error messages for mail sent to root */
char *ps;
/* This function returns the login name of the owner of a file */
char *ownername(filename)
char *filename; /* name of a file */
{
struct stat st;
struct passwd *pw;
/* stat the file, to get its uid */
if (stat(filename, &st) < 0)
{
ps = "stat() failed";
return "root";
}
/* get the /etc/passwd entry for that user */
pw = getpwuid(st.st_uid);
if (!pw)
{
ps = "uid not found in password file";
return "root";
}
/* return the user's name */
return pw->pw_name;
}
/* This function sends a mail message to a given user, saying that a file
* has been preserved.
*/
void mail(user, file, when)
char *user; /* name of user who should receive the mail */
char *file; /* name of original text file that was preserved */
char *when; /* description of why the file was preserved */
{
char cmd[80];/* buffer used for constructing a "mail" command */
FILE *m; /* stream used for giving text to the "mail" program */
char *base; /* basename of the file */
/* separate the directory name from the basename. */
for (base = file + strlen(file); --base > file && *base != SLASH; )
{
}
if (*base == SLASH)
{
*base++ = '\0';
}
/* for anonymous buffers, pretend the name was "foo" */
if (!strcmp(base, "*"))
{
base = "foo";
}
/* open a pipe to the "mail" program */
#if OSK
sprintf(cmd, "mail \"-s=%s preserved!\" %s", base, user);
#else /* ANY_UNIX */
sprintf(cmd, "mail -s Graceland %s", user);
#endif
m = popen(cmd, "w");
if (!m)
{
perror(cmd);
/* Can't send mail! Hope the user figures it out. */
return;
}
/* Tell the user that the file was preserved */
fprintf(m, "A version of your file \"%s%c%s\"\n", file, SLASH, base);
fprintf(m, "was preserved when %s.\n", when);
fprintf(m, "To recover this file, do the following:\n");
fprintf(m, "\n");
#if OSK
fprintf(m, " chd %s\n", file);
#else /* ANY_UNIX */
fprintf(m, " cd %s\n", file);
#endif
fprintf(m, " elvisrecover %s\n", base);
fprintf(m, "\n");
fprintf(m, "With fond wishes for a speedy recovery,\n");
fprintf(m, " Elvis\n");
if (ps)
{
fprintf(m, "\nP.S. %s\n", ps);
ps = (char *)0;
}
/* close the stream */
pclose(m);
}