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