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