This commit was manufactured by cvs2svn to create tag 'FreeBSD-release/1.0'.
[unix-history] / libexec / elvispreserve / elvispreserve.c
CommitLineData
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
78ed81a3 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
64void preserve P_((char *, char *));
65void main P_((int, char **));
66
15637ed4
RG
67#if AMIGA
68BLK 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
88BLK buf;
89BLK hdr;
90BLK name;
91int 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 */
98void 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 */
78ed81a3 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
78ed81a3 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);
78ed81a3 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);
78ed81a3 197 exit(2);
15637ed4
RG
198 }
199
78ed81a3 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);
78ed81a3 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
78ed81a3 271void 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 */
78ed81a3 280 _ct_init("");
15637ed4
RG
281 argv = wildexpand(&argc, argv);
282#endif
283
78ed81a3 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}