Fix a couple of compiler warnings
[unix-history] / libexec / elvispreserve / prsvunix.c
CommitLineData
e4b163b1
AM
1/* prsvunix.c */
2
3/* This file contains the UNIX-specific parts of the "elvprsv" program. */
4
5#if OSK
6#define ELVPRSV
7#include "osk.c"
8#else
9#include <sys/stat.h>
10#include <pwd.h>
11#endif
12#ifndef __STDC__
13/* some older systems don't declare this in pwd.h, I guess. */
14extern struct passwd *getpwuid();
15#endif
16
17#if ANY_UNIX /* { */
18/* Since elvprsv runs as SUID-root, we need a *secure* version of popen() */
19#define popen safe_popen
20#define pclose safe_pclose
21
22/* This function is similar to the standard popen() function, except for...
23 * 1) It doesn't use the shell, for security reasons.
24 * 2) Shell services are not supported, including quoting.
25 * 3) The mode can only be "w". "r" is not supported.
26 * 4) No more than 9 arguments can be given, including the command.
27 */
28/*ARGSUSED*/
29static FILE *safe_popen(cmd, mode)
30 char *cmd; /* the filename of the program to be run */
31 char *mode; /* "w", ignored */
32{
33 char path[100];/* full pathname of argv[0] */
34 char *argv[10];/* the arguments */
35 int r0w1[2];/* the pipe fd's */
36 int i;
37 FILE *fp;
38
39 /* parse the arguments */
40 for (i = 0; i < 9 && *cmd; i++)
41 {
42 /* remember where this arg starts */
43 argv[i] = cmd;
44
45 /* move to the end of the argument */
46 do
47 {
48 cmd++;
49 } while (*cmd && *cmd != ' ');
50
51 /* then mark end of arg & skip to next */
52 while (*cmd && *cmd == ' ')
53 {
54 *cmd++ = '\0';
55 }
56printf("argv[%d]=\"%s\"\n", i, argv[i]);
57 }
58 argv[i] = (char *)0;
59
60 /* make the pipe */
61 if (pipe(r0w1) < 0)
62 {
63perror("pipe()");
64 return (FILE *)0; /* pipe failed */
65 }
66
67 switch (fork())
68 {
69 case -1: /* error */
70perror("fork()");
71 return (FILE *)0;
72
73 case 0: /* child */
74 /* close the "write" end of the pipe */
75 close(r0w1[1]);
76
77 /* redirect stdin to come from the "read" end of the pipe */
78 close(0);
79 dup(r0w1[0]);
80 close(r0w1[0]);
81
82 /* exec the shell to run the command */
83 if (*argv[0] != '/')
84 {
85 /* no path, try "/bin/argv[0]" */
86 strcpy(path, "/bin/");
87 strcat(path, argv[0]);
88 execv(path, argv);
89perror(path);
90
91 /* if that failed, then try "/usr/bin/argv[0]" */
92 strcpy(path, "/usr/bin/");
93 strcat(path, argv[0]);
94 execv(path, argv);
95perror(path);
96 }
97 else
98 {
99 /* full pathname given, so use it */
100 execv(argv[0], argv);
101perror(argv[0]);
102 }
103
104 /* if we get here, exec failed */
105 exit(1);
106
107 default: /* parent */
108 /* close the "read" end of the pipe */
109 close(r0w1[0]);
110
111 /* convert the "write" fd into a (FILE *) */
112 fp = fdopen(r0w1[1], "w");
113 return fp;
114 }
115 /*NOTREACHED*/
116}
117
118
119/* This function closes the pipe opened by popen(), and returns 0 for success */
120static int safe_pclose(fp)
121 FILE *fp; /* value returned by popen() */
122{
123 int status;
124
125 /* close the file, and return the defunct child's exit status */
126 fclose(fp);
127 wait(&status);
128 return status;
129}
130#endif /* } ANY UNIX */
131
132
133/* This variable is used to add extra error messages for mail sent to root */
134char *ps;
135
136/* This function returns the login name of the owner of a file */
137char *ownername(filename)
138 char *filename; /* name of a file */
139{
140 struct stat st;
141 struct passwd *pw;
142
143 /* stat the file, to get its uid */
144 if (stat(filename, &st) < 0)
145 {
146 ps = "stat() failed";
147 return "root";
148 }
149
150 /* get the /etc/passwd entry for that user */
151 pw = getpwuid(st.st_uid);
152 if (!pw)
153 {
154 ps = "uid not found in password file";
155 return "root";
156 }
157
158 /* return the user's name */
159 return pw->pw_name;
160}
161
162
163/* This function sends a mail message to a given user, saying that a file
164 * has been preserved.
165 */
166void mail(user, file, when)
167 char *user; /* name of user who should receive the mail */
168 char *file; /* name of original text file that was preserved */
169 char *when; /* description of why the file was preserved */
170{
171 char cmd[80];/* buffer used for constructing a "mail" command */
172 FILE *m; /* stream used for giving text to the "mail" program */
173 char *base; /* basename of the file */
174
175 /* separate the directory name from the basename. */
176 for (base = file + strlen(file); --base > file && *base != SLASH; )
177 {
178 }
179 if (*base == SLASH)
180 {
181 *base++ = '\0';
182 }
183
184 /* for anonymous buffers, pretend the name was "foo" */
185 if (!strcmp(base, "*"))
186 {
187 base = "foo";
188 }
189
190 /* open a pipe to the "mail" program */
191#if OSK
192 sprintf(cmd, "mail \"-s=%s preserved!\" %s", base, user);
193#else /* ANY_UNIX */
194 sprintf(cmd, "mail -s Graceland %s", user);
195#endif
196 m = popen(cmd, "w");
197 if (!m)
198 {
199 perror(cmd);
200 /* Can't send mail! Hope the user figures it out. */
201 return;
202 }
203
204 /* Tell the user that the file was preserved */
205 fprintf(m, "A version of your file \"%s%c%s\"\n", file, SLASH, base);
206 fprintf(m, "was preserved when %s.\n", when);
207 fprintf(m, "To recover this file, do the following:\n");
208 fprintf(m, "\n");
209#if OSK
210 fprintf(m, " chd %s\n", file);
211#else /* ANY_UNIX */
212 fprintf(m, " cd %s\n", file);
213#endif
214 fprintf(m, " elvisrecover %s\n", base);
215 fprintf(m, "\n");
216 fprintf(m, "With fond wishes for a speedy recovery,\n");
217 fprintf(m, " Elvis\n");
218 if (ps)
219 {
220 fprintf(m, "\nP.S. %s\n", ps);
221 ps = (char *)0;
222 }
223
224 /* close the stream */
225 pclose(m);
226}