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