Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* elvprsv.c */ |
2 | ||
3 | /* Author: | |
4 | * Steve Kirkendall | |
5 | * 14407 SW Teal Blvd. #C | |
6 | * Beaverton, OR 97005 | |
7 | * kirkenda@cs.pdx.edu | |
8 | */ | |
9 | ||
10 | ||
11 | /* This file contains the portable sources for the "elvprsv" program. | |
12 | * "Elvprsv" is run by Elvis when Elvis is about to die. It is also | |
13 | * run when the computer boots up. It is not intended to be run directly | |
14 | * by the user, ever. | |
15 | * | |
16 | * Basically, this program does the following four things: | |
17 | * - It extracts the text from the temporary file, and places the text in | |
18 | * a file in the /usr/preserve directory. | |
19 | * - It adds a line to the /usr/preserve/Index file, describing the file | |
20 | * that it just preserved. | |
21 | * - It removes the temporary file. | |
22 | * - It sends mail to the owner of the file, saying that the file was | |
23 | * preserved, and how it can be recovered. | |
24 | * | |
25 | * The /usr/preserve/Index file is a log file that contains one line for each | |
26 | * file that has ever been preserved. Each line of this file describes one | |
27 | * preserved file. The first word on the line is the name of the file that | |
28 | * contains the preserved text. The second word is the full pathname of the | |
29 | * file that was being edited; for anonymous buffers, this is the directory | |
30 | * name plus "/foo". | |
31 | * | |
32 | * If elvprsv's first argument (after the command name) starts with a hyphen, | |
33 | * then the characters after the hyphen are used as a description of when | |
34 | * the editor went away. This is optional. | |
35 | * | |
36 | * The remaining arguments are all the names of temporary files that are | |
37 | * to be preserved. For example, on a UNIX system, the /etc/rc file might | |
38 | * invoke it this way: | |
39 | * | |
40 | * elvprsv "-the system went down" /tmp/elv_*.* | |
41 | * | |
42 | * This file contains only the portable parts of the preserve program. | |
43 | * It must #include a system-specific file. The system-specific file is | |
44 | * expected to define the following functions: | |
45 | * | |
46 | * char *ownername(char *filename) - returns name of person who owns file | |
47 | * | |
48 | * void mail(char *user, char *name, char *when) | |
49 | * - tell user that file was preserved | |
50 | */ | |
51 | ||
52 | #include <stdio.h> | |
53 | #include "config.h" | |
54 | #include "vi.h" | |
55 | ||
e4b163b1 AM |
56 | /* We include ctype.c here (instead of including just ctype.h and linking |
57 | * with ctype.o) because on some systems ctype.o will have been compiled in | |
58 | * "large model" and the elvprsv program is to be compiled in "small model" | |
59 | * You can't mix models. By including ctype.c here, we can avoid linking | |
60 | * with ctype.o. | |
61 | */ | |
62 | #include "ctype.c" | |
63 | ||
64 | void preserve P_((char *, char *)); | |
65 | void main P_((int, char **)); | |
66 | ||
15637ed4 RG |
67 | #if AMIGA |
68 | BLK tmpblk; | |
69 | # include "amiwild.c" | |
70 | # include "amiprsv.c" | |
71 | #endif | |
72 | ||
73 | #if OSK | |
74 | # undef sprintf | |
75 | #endif | |
76 | ||
77 | #if ANY_UNIX || OSK | |
78 | # include "prsvunix.c" | |
79 | #endif | |
80 | ||
81 | #if MSDOS || TOS | |
82 | # include "prsvdos.c" | |
83 | # define WILDCARD_NO_MAIN | |
84 | # include "wildcard.c" | |
85 | #endif | |
86 | ||
87 | ||
88 | BLK buf; | |
89 | BLK hdr; | |
90 | BLK name; | |
91 | int rewrite_now; /* boolean: should we send text directly to orig file? */ | |
92 | ||
93 | ||
94 | ||
95 | /* This function preserves a single file, and announces its success/failure | |
96 | * via an e-mail message. | |
97 | */ | |
98 | void preserve(tname, when) | |
99 | char *tname; /* name of a temp file to be preserved */ | |
100 | char *when; /* description of when the editor died */ | |
101 | { | |
102 | int infd; /* fd used for reading from the temp file */ | |
103 | FILE *outfp; /* fp used for writing to the recovery file */ | |
104 | FILE *index; /* fp used for appending to index file */ | |
105 | char outname[100]; /* the name of the recovery file */ | |
106 | char *user; /* name of the owner of the temp file */ | |
107 | #if AMIGA | |
108 | char *prsvdir; | |
109 | #endif | |
110 | int i; | |
111 | ||
112 | /* open the temp file */ | |
113 | infd = open(tname, O_RDONLY|O_BINARY); | |
114 | if (infd < 0) | |
115 | { | |
116 | /* if we can't open the file, then we should assume that | |
117 | * the filename contains wildcard characters that weren't | |
118 | * expanded... and also assume that they weren't expanded | |
119 | * because there are no files that need to be preserved. | |
120 | * THEREFORE... we should silently ignore it. | |
121 | * (Or loudly ignore it if the user was using -R) | |
122 | */ | |
123 | if (rewrite_now) | |
124 | { | |
125 | perror(tname); | |
126 | } | |
127 | return; | |
128 | } | |
129 | ||
130 | /* read the header and name from the file */ | |
131 | if (read(infd, hdr.c, BLKSIZE) != BLKSIZE | |
132 | || read(infd, name.c, BLKSIZE) != BLKSIZE) | |
133 | { | |
134 | /* something wrong with the file - sorry */ | |
e4b163b1 | 135 | fprintf(stderr, "%s: truncated header blocks\n", tname); |
15637ed4 RG |
136 | close(infd); |
137 | return; | |
138 | } | |
139 | ||
140 | /* If the filename block contains an empty string, then Elvis was | |
141 | * only keeping the temp file around because it contained some text | |
142 | * that was needed for a named cut buffer. The user doesn't care | |
143 | * about that kind of temp file, so we should silently delete it. | |
144 | */ | |
145 | if (name.c[0] == '\0' && name.c[1] == '\177') | |
146 | { | |
147 | close(infd); | |
148 | unlink(tname); | |
149 | return; | |
150 | } | |
151 | ||
e4b163b1 AM |
152 | /* If there are no text blocks in the file, then we must've never |
153 | * really started editing. Discard the file. | |
154 | */ | |
155 | if (hdr.n[1] == 0) | |
156 | { | |
157 | close(infd); | |
158 | unlink(tname); | |
159 | return; | |
160 | } | |
161 | ||
15637ed4 RG |
162 | if (rewrite_now) |
163 | { | |
164 | /* we don't need to open the index file */ | |
165 | index = (FILE *)0; | |
166 | ||
167 | /* make sure we can read every block! */ | |
168 | for (i = 1; i < MAXBLKS && hdr.n[i]; i++) | |
169 | { | |
170 | lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); | |
e4b163b1 AM |
171 | if (read(infd, buf.c, BLKSIZE) != BLKSIZE |
172 | || buf.c[0] == '\0') | |
15637ed4 RG |
173 | { |
174 | /* messed up header */ | |
175 | fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); | |
176 | close(infd); | |
177 | return; | |
178 | } | |
179 | } | |
180 | ||
181 | /* open the user's file for writing */ | |
182 | outfp = fopen(name.c, "w"); | |
183 | if (!outfp) | |
184 | { | |
185 | perror(name.c); | |
186 | close(infd); | |
187 | return; | |
188 | } | |
189 | } | |
190 | else | |
191 | { | |
192 | /* open/create the index file */ | |
193 | index = fopen(PRSVINDEX, "a"); | |
194 | if (!index) | |
195 | { | |
196 | perror(PRSVINDEX); | |
e4b163b1 | 197 | exit(2); |
15637ed4 RG |
198 | } |
199 | ||
e4b163b1 AM |
200 | /* should be at the end of the file already, but MAKE SURE */ |
201 | fseek(index, 0L, 2); | |
202 | ||
15637ed4 RG |
203 | /* create the recovery file in the PRESVDIR directory */ |
204 | #if AMIGA | |
205 | prsvdir = &PRSVDIR[strlen(PRSVDIR) - 1]; | |
206 | if (*prsvdir == '/' || *prsvdir == ':') | |
207 | { | |
208 | sprintf(outname, "%sp%ld", PRSVDIR, ftell(index)); | |
209 | } | |
210 | else | |
211 | #endif | |
212 | sprintf(outname, "%s%cp%ld", PRSVDIR, SLASH, ftell(index)); | |
213 | outfp = fopen(outname, "w"); | |
214 | if (!outfp) | |
215 | { | |
216 | perror(outname); | |
217 | close(infd); | |
218 | fclose(index); | |
219 | return; | |
220 | } | |
221 | } | |
222 | ||
223 | /* write the text of the file out to the recovery file */ | |
224 | for (i = 1; i < MAXBLKS && hdr.n[i]; i++) | |
225 | { | |
226 | lseek(infd, (long)hdr.n[i] * (long)BLKSIZE, 0); | |
e4b163b1 AM |
227 | if (read(infd, buf.c, BLKSIZE) != BLKSIZE |
228 | || buf.c[0] == '\0') | |
15637ed4 RG |
229 | { |
230 | /* messed up header */ | |
231 | fprintf(stderr, "%s: unrecoverable -- header trashed\n", name.c); | |
232 | fclose(outfp); | |
233 | close(infd); | |
234 | if (index) | |
235 | { | |
236 | fclose(index); | |
237 | } | |
238 | unlink(outname); | |
239 | return; | |
240 | } | |
241 | fputs(buf.c, outfp); | |
242 | } | |
243 | ||
244 | /* add a line to the index file */ | |
245 | if (index) | |
246 | { | |
247 | fprintf(index, "%s %s\n", outname, name.c); | |
248 | } | |
249 | ||
250 | /* close everything */ | |
251 | close(infd); | |
252 | fclose(outfp); | |
253 | if (index) | |
254 | { | |
255 | fclose(index); | |
256 | } | |
257 | ||
258 | /* Are we doing this due to something more frightening than just | |
259 | * a ":preserve" command? | |
260 | */ | |
261 | if (*when) | |
262 | { | |
263 | /* send a mail message */ | |
264 | mail(ownername(tname), name.c, when); | |
265 | ||
266 | /* remove the temp file -- the editor has died already */ | |
267 | unlink(tname); | |
268 | } | |
269 | } | |
270 | ||
e4b163b1 | 271 | void main(argc, argv) |
15637ed4 RG |
272 | int argc; |
273 | char **argv; | |
274 | { | |
275 | int i; | |
276 | char *when = "the editor went away"; | |
277 | ||
278 | #if MSDOS || TOS | |
279 | /* expand any wildcards in the command line */ | |
e4b163b1 | 280 | _ct_init(""); |
15637ed4 RG |
281 | argv = wildexpand(&argc, argv); |
282 | #endif | |
283 | ||
e4b163b1 | 284 | /* do we have a "-c", "-R", or "-when elvis died" argument? */ |
15637ed4 RG |
285 | i = 1; |
286 | if (argc >= i + 1 && !strcmp(argv[i], "-R")) | |
287 | { | |
288 | rewrite_now = 1; | |
289 | when = ""; | |
290 | i++; | |
291 | #if ANY_UNIX | |
292 | setuid(geteuid()); | |
293 | #endif | |
294 | } | |
295 | #if OSK | |
296 | else | |
297 | { | |
298 | setuid(0); | |
299 | } | |
300 | #endif | |
301 | if (argc >= i + 1 && argv[i][0] == '-') | |
302 | { | |
303 | when = argv[i] + 1; | |
304 | i++; | |
305 | } | |
306 | ||
307 | /* preserve everything we're supposed to */ | |
308 | while (i < argc) | |
309 | { | |
310 | preserve(argv[i], when); | |
311 | i++; | |
312 | } | |
313 | } |