|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char *copyright =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char *sccsid = "@(#)expreserve.c 7.15 (Berkeley) 11/14/89";
15: #endif not lint
16:
17: #include <sys/param.h>
18: #include <sys/stat.h>
19: #include <sys/dir.h>
20: #include <pwd.h>
21: #include <stdio.h>
22: #include <ctype.h>
23: #include "pathnames.h"
24:
25: #ifdef VMUNIX
26: #define HBLKS 2
27: #else
28: #define HBLKS 1
29: #endif
30:
31: char xstr[1]; /* make loader happy */
32:
33: /*
34: * Expreserve - preserve a file in _PATH_PRESERVE.
35: * Bill Joy UCB November 13, 1977
36: *
37: * This routine is very naive - it doesn't remove anything from
38: * _PATH_PRESERVE... this may mean that we leave
39: * stuff there... the danger in doing anything with _PATH_PRESERVE
40: * is that the clock may be screwed up and we may get confused.
41: *
42: * We are called in two ways - first from the editor with no argumentss
43: * and the standard input open on the temp file. Second with an argument
44: * to preserve the entire contents of /tmp (root only).
45: *
46: * BUG: should do something about preserving Rx... (register contents)
47: * temporaries.
48: */
49:
50: #ifndef VMUNIX
51: #define LBLKS 125
52: #else
53: #define LBLKS 900
54: #endif
55: #define FNSIZE 128
56:
57: struct header {
58: time_t Time; /* Time temp file last updated */
59: int Uid; /* This users identity */
60: #ifndef VMUNIX
61: short Flines; /* Number of lines in file */
62: #else
63: int Flines;
64: #endif
65: char Savedfile[FNSIZE]; /* The current file name */
66: short Blocks[LBLKS]; /* Blocks where line pointers stashed */
67: } H;
68:
69: #ifdef lint
70: #define ignore(a) Ignore(a)
71: #define ignorl(a) Ignorl(a)
72: #else
73: #define ignore(a) a
74: #define ignorl(a) a
75: #endif
76:
77: struct passwd *getpwuid();
78: off_t lseek();
79: FILE *popen();
80:
81: #define eq(a, b) strcmp(a, b) == 0
82:
83: main(argc)
84: int argc;
85: {
86: register DIR *tf;
87: struct direct *dirent;
88: struct stat stbuf;
89:
90: /*
91: * If only one argument, then preserve the standard input.
92: */
93: if (argc == 1) {
94: if (copyout((char *) 0))
95: exit(1);
96: exit(0);
97: }
98:
99: /*
100: * If not super user, then can only preserve standard input.
101: */
102: if (getuid()) {
103: fprintf(stderr, "NOT super user\n");
104: exit(1);
105: }
106:
107: /*
108: * ... else preserve all the stuff in /tmp, removing
109: * it as we go.
110: */
111: if (chdir(_PATH_VARTMP) < 0) {
112: perror(_PATH_VARTMP);
113: exit(1);
114: }
115:
116: tf = opendir(".");
117: if (tf == NULL) {
118: perror(_PATH_VARTMP);
119: exit(1);
120: }
121: while ((dirent = readdir(tf)) != NULL) {
122: /* Ex temporaries must begin with Ex. */
123: if (dirent->d_name[0] != 'E' || dirent->d_name[1] != 'x')
124: continue;
125: if (stat(dirent->d_name, &stbuf))
126: continue;
127: if ((stbuf.st_mode & S_IFMT) != S_IFREG)
128: continue;
129: /*
130: * Save the bastard.
131: */
132: ignore(copyout(dirent->d_name));
133: }
134: closedir(tf);
135: exit(0);
136: }
137:
138: char pattern[MAXPATHLEN];
139:
140: /*
141: * Copy file name into pattern[].
142: * If name is (char *) 0, then do the standard input.
143: * We make some checks on the input to make sure it is
144: * really an editor temporary, generate a name for the
145: * file (this is the slowest thing since we must stat
146: * to find a unique name), and finally copy the file.
147: */
148: copyout(name)
149: char *name;
150: {
151: int i;
152: static int reenter;
153: char buf[BUFSIZ];
154:
155: (void)sprintf(pattern, "%s/Exaa`XXXXX", _PATH_PRESERVE);
156: /*
157: * The first time we put in the digits of our
158: * process number at the end of the pattern.
159: */
160: if (reenter == 0) {
161: mkdigits(pattern);
162: reenter++;
163: }
164:
165: /*
166: * If a file name was given, make it the standard
167: * input if possible.
168: */
169: if (name != 0) {
170: ignore(close(0));
171: /*
172: * Need read/write access for arcane reasons
173: * (see below).
174: */
175: if (open(name, 2) < 0)
176: return (-1);
177: }
178:
179: /*
180: * Get the header block.
181: */
182: ignorl(lseek(0, 0l, 0));
183: if (read(0, (char *) &H, sizeof H) != sizeof H) {
184: format:
185: if (name == 0)
186: fprintf(stderr, "Buffer format error\t");
187: return (-1);
188: }
189:
190: /*
191: * Consistency checsks so we don't copy out garbage.
192: */
193: if (H.Flines < 0) {
194: #ifdef DEBUG
195: fprintf(stderr, "Negative number of lines\n");
196: #endif
197: goto format;
198: }
199: if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
200: #ifdef DEBUG
201: fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
202: #endif
203: goto format;
204: }
205: if (name == 0 && H.Uid != getuid()) {
206: #ifdef DEBUG
207: fprintf(stderr, "Wrong user-id\n");
208: #endif
209: goto format;
210: }
211: if (lseek(0, 0l, 0)) {
212: #ifdef DEBUG
213: fprintf(stderr, "Negative number of lines\n");
214: #endif
215: goto format;
216: }
217:
218: /*
219: * If no name was assigned to the file, then give it the name
220: * LOST, by putting this in the header.
221: */
222: if (H.Savedfile[0] == 0) {
223: strcpy(H.Savedfile, "LOST");
224: ignore(write(0, (char *) &H, sizeof H));
225: H.Savedfile[0] = 0;
226: lseek(0, 0l, 0);
227: }
228:
229: /*
230: * File is good. Get a name and create a file for the copy.
231: */
232: mknext(pattern);
233: ignore(close(1));
234: if (creat(pattern, 0600) < 0) {
235: if (name == 0)
236: perror(pattern);
237: return (1);
238: }
239:
240: /*
241: * Make the target be owned by the owner of the file.
242: */
243: ignore(chown(pattern, H.Uid, 0));
244:
245: /*
246: * Copy the file.
247: */
248: for (;;) {
249: i = read(0, buf, BUFSIZ);
250: if (i < 0) {
251: if (name)
252: perror("Buffer read error");
253: ignore(unlink(pattern));
254: return (-1);
255: }
256: if (i == 0) {
257: if (name)
258: ignore(unlink(name));
259: notify(H.Uid, H.Savedfile, (int) name, H.Time);
260: return (0);
261: }
262: if (write(1, buf, i) != i) {
263: if (name == 0)
264: perror(pattern);
265: unlink(pattern);
266: return (-1);
267: }
268: }
269: }
270:
271: /*
272: * Blast the last 5 characters of cp to be the process number.
273: */
274: mkdigits(cp)
275: char *cp;
276: {
277: register int i, j;
278:
279: for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
280: *--cp = i % 10 | '0';
281: }
282:
283: /*
284: * Make the name in cp be unique by clobbering up to
285: * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
286: * Mktemp gets weird names too quickly to be useful here.
287: */
288: mknext(cp)
289: char *cp;
290: {
291: char *dcp;
292: struct stat stb;
293:
294: dcp = cp + strlen(cp) - 1;
295: while (isdigit(*dcp))
296: dcp--;
297: whoops:
298: if (dcp[0] == 'z') {
299: dcp[0] = 'a';
300: if (dcp[-1] == 'z') {
301: dcp[-1] = 'a';
302: if (dcp[-2] == 'z')
303: fprintf(stderr, "Can't find a name\t");
304: dcp[-2]++;
305: } else
306: dcp[-1]++;
307: } else
308: dcp[0]++;
309: if (stat(cp, &stb) == 0)
310: goto whoops;
311: }
312:
313: /*
314: * Notify user uid that his file fname has been saved.
315: */
316: notify(uid, fname, flag, time)
317: int uid;
318: char *fname;
319: time_t time;
320: {
321: struct passwd *pp = getpwuid(uid);
322: register FILE *mf;
323: char cmd[BUFSIZ];
324: char hostname[128];
325: char croak[128];
326: char *timestamp, *ctime();
327:
328: if (pp == NULL)
329: return;
330: gethostname(hostname, sizeof(hostname));
331: timestamp = ctime(&time);
332: timestamp[16] = 0; /* blast from seconds on */
333: sprintf(cmd, "%s %s", _PATH_BINMAIL, pp->pw_name);
334: setuid(getuid());
335: mf = popen(cmd, "w");
336: if (mf == NULL)
337: return;
338: setbuf(mf, cmd);
339: /*
340: * flag says how the editor croaked:
341: * "the editor was killed" is perhaps still not an ideal
342: * error message. Usually, either it was forcably terminated
343: * or the phone was hung up, but we don't know which.
344: */
345: sprintf(croak, flag
346: ? "the system went down"
347: : "the editor was killed");
348: if (fname[0] == 0) {
349: fname = "LOST";
350: fprintf(mf,
351: "Subject: editor saved ``LOST''\n");
352: fprintf(mf,
353: "You were editing a file without a name\n");
354: fprintf(mf,
355: "at <%s> on the machine ``%s'' when %s.\n", timestamp, hostname, croak);
356: fprintf(mf,
357: "Since the file had no name, it has been named \"LOST\".\n");
358: } else {
359: fprintf(mf,
360: "Subject: editor saved ``%s''\n", fname);
361: fprintf(mf,
362: "You were editing the file \"%s\"\n", fname);
363: fprintf(mf,
364: "at <%s> on the machine ``%s''\n", timestamp, hostname);
365: fprintf(mf,
366: "when %s.\n", croak);
367: }
368: fprintf(mf,
369: "\nYou can retrieve most of your changes to this file\n");
370: fprintf(mf,
371: "using the \"recover\" command of the editor.\n");
372: fprintf(mf,
373: "An easy way to do this is to give the command \"vi -r %s\".\n", fname);
374: fprintf(mf,
375: "This method also works using \"ex\" and \"edit\".\n");
376: pclose(mf);
377: }
378:
379: /*
380: * people making love
381: * never exactly the same
382: * just like a snowflake
383: */
384:
385: #ifdef lint
386: Ignore(a)
387: int a;
388: {
389:
390: a = a;
391: }
392:
393: Ignorl(a)
394: long a;
395: {
396:
397: a = a;
398: }
399: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.