Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
99 7u83 1
/*
2
 * This code contains changes by
3
 *      Gunnar Ritter, Freiburg i. Br., Germany, 2002. All rights reserved.
4
 *
5
 * Conditions 1, 2, and 4 and the no-warranty notice below apply
6
 * to these changes.
7
 *
8
 *
9
 * Copyright (c) 1980, 1993
10
 * 	The Regents of the University of California.  All rights reserved.
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgement:
22
 * 	This product includes software developed by the University of
23
 * 	California, Berkeley and its contributors.
24
 * 4. Neither the name of the University nor the names of its contributors
25
 *    may be used to endorse or promote products derived from this software
26
 *    without specific prior written permission.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38
 * SUCH DAMAGE.
39
 *
40
 *
41
 * Copyright(C) Caldera International Inc. 2001-2002. All rights reserved.
42
 *
43
 * Redistribution and use in source and binary forms, with or without
44
 * modification, are permitted provided that the following conditions
45
 * are met:
46
 *   Redistributions of source code and documentation must retain the
47
 *    above copyright notice, this list of conditions and the following
48
 *    disclaimer.
49
 *   Redistributions in binary form must reproduce the above copyright
50
 *    notice, this list of conditions and the following disclaimer in the
51
 *    documentation and/or other materials provided with the distribution.
52
 *   All advertising materials mentioning features or use of this software
53
 *    must display the following acknowledgement:
54
 *      This product includes software developed or owned by Caldera
55
 *      International, Inc.
56
 *   Neither the name of Caldera International, Inc. nor the names of
57
 *    other contributors may be used to endorse or promote products
58
 *    derived from this software without specific prior written permission.
59
 *
60
 * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA
61
 * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR
62
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
63
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64
 * ARE DISCLAIMED. IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE
65
 * LIABLE FOR ANY DIRECT, INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR
66
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
67
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
68
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
69
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
70
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
71
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
72
 */
73
 
74
#ifdef	__GNUC__
75
#define	UNUSED	__attribute__ ((unused))
76
#else
77
#define	UNUSED
78
#endif
79
 
80
#ifndef	lint
81
#ifdef	DOSCCS
82
char *copyright =
83
"@(#) Copyright (c) 1980 Regents of the University of California.\n\
84
 All rights reserved.\n";
85
#endif
86
static char sccsid[] UNUSED = "@(#)expreserve.c	1.23 (gritter) 11/27/04";
87
#endif
88
 
89
/* from expreserve.c	7.13.2 (2.11BSD GTE) 1996/10/26 */
90
 
91
#include <stdio.h>
92
#include <ctype.h>
93
#include <sys/param.h>
94
#include <sys/stat.h>
95
#include <sys/types.h>
96
#include <sys/utsname.h>
97
#include <dirent.h>
98
#include <limits.h>
99
#include <fcntl.h>
100
#include <unistd.h>
101
#include <string.h>
102
#include <stdlib.h>
103
#include <pwd.h>
104
#include <time.h>
105
 
106
#include "config.h"
107
 
108
#ifdef	LANGMSG
109
#include <nl_types.h>
110
#include <locale.h>
111
nl_catd	catd;
112
#else
113
#define	catgets(a, b, c, d)	(d)
114
#endif
115
 
116
#ifdef	BUFSIZ
117
#undef	BUFSIZ
118
#endif
119
#ifdef	LINE_MAX
120
#define	BUFSIZ	LINE_MAX	/* POSIX line size */
121
#else	/* !LINE_MAX */
122
#ifdef	VMUNIX
123
#define	BUFSIZ	1024
124
#else	/* !VMUNIX */
125
#ifdef	u370
126
#define	BUFSIZ	4096
127
#else	/* !u370 */
128
#define	BUFSIZ	512
129
#endif	/* !u370 */
130
#endif
131
#endif	/* !VMUNIX */
132
 
133
#ifdef	LARGEF
134
typedef	off_t	bloc;
135
#else
136
typedef	short	bloc;
137
#endif
138
 
139
#ifdef	VMUNIX
140
#ifdef	LARGEF
141
typedef	off_t	bbloc;
142
#else
143
typedef	int	bbloc;
144
#endif
145
#else
146
typedef	short	bbloc;
147
#endif
148
 
149
#ifdef	notdef
150
#define TMP	"/tmp"
151
#else
152
#define	TMP	"/var/tmp"
153
#endif
154
 
155
#ifndef VMUNIX
156
#define	LBLKS	125
157
#else
158
#ifdef	LARGEF
159
#define	LBLKS	20000
160
#else
161
#define	LBLKS	900
162
#endif
163
#endif
164
#ifdef	_POSIX_PATH_MAX
165
#define	FNSIZE	_POSIX_PATH_MAX
166
#else
167
#define	FNSIZE	128
168
#endif
169
 
170
#ifdef VMUNIX
171
#define	HBLKS	(1 + (FNSIZE + LBLKS * sizeof(bloc)) / BUFSIZ)
172
#else
173
#define HBLKS	1
174
#endif
175
 
176
char xstr[1];			/* make loader happy */
177
 
178
extern void notify(uid_t, char *, int, time_t);
179
extern int copyout(char *);
180
extern void mkdigits(char *);
181
extern void mknext(char *);
182
 
183
/*
184
 * Expreserve - preserve a file in /usr/preserve
185
 * Bill Joy UCB November 13, 1977
186
 *
187
 * This routine is very naive - it doesn't remove anything from
188
 * /usr/preserve... this may mean that we leave
189
 * stuff there... the danger in doing anything with /usr/preserve
190
 * is that the clock may be screwed up and we may get confused.
191
 *
192
 * We are called in two ways - first from the editor with no argumentss
193
 * and the standard input open on the temp file. Second with an argument
194
 * to preserve the entire contents of /tmp (root only).
195
 *
196
 * BUG: should do something about preserving Rx... (register contents)
197
 *      temporaries.
198
 */
199
 
200
struct 	header {
201
	time_t	Time;			/* Time temp file last updated */
202
	uid_t	Uid;
203
	bbloc	Flines;			/* Number of lines in file */
204
	char	Savedfile[FNSIZE];	/* The current file name */
205
	bloc	Blocks[LBLKS];		/* Blocks where line pointers stashed */
206
} H;
207
 
208
#define	ignore(a)	a
209
#define	ignorl(a)	a
210
 
211
#define eq(a, b) (strcmp(a, b) == 0)
212
 
213
int 
214
main(int argc, char **argv)
215
{
216
	register DIR *tf;
217
	struct dirent *dirent;
218
	struct stat stbuf;
219
 
220
#ifdef	LANGMSG
221
	setlocale(LC_MESSAGES, "");
222
	catd = catopen(CATNAME, NL_CAT_LOCALE);
223
#endif
224
	/*
225
	 * If only one argument, then preserve the standard input.
226
	 */
227
	if (argc == 1) {
228
		if (copyout((char *) 0))
229
			exit(1);
230
		exit(0);
231
	}
232
 
233
	/*
234
	 * If not super user, then can only preserve standard input.
235
	 */
236
	if (getuid()) {
237
		fprintf(stderr, catgets(catd, 3, 1, "NOT super user\n"));
238
		exit(1);
239
	}
240
 
241
	/*
242
	 * ... else preserve all the stuff in /tmp, removing
243
	 * it as we go.
244
	 */
245
	if (chdir(TMP) < 0) {
246
		perror(TMP);
247
		exit(1);
248
	}
249
 
250
	tf = opendir(".");
251
	if (tf == NULL) {
252
		perror(TMP);
253
		exit(1);
254
	}
255
	while ((dirent = readdir(tf)) != NULL) {
256
		/* Ex temporaries must begin with Ex. */
257
		if (dirent->d_name[0] != 'E' || dirent->d_name[1] != 'x')
258
			continue;
259
		if (stat(dirent->d_name, &stbuf))
260
			continue;
261
		if ((stbuf.st_mode & S_IFMT) != S_IFREG)
262
			continue;
263
		/*
264
		 * Save the bastard.
265
		 */
266
		ignore(copyout(dirent->d_name));
267
	}
268
	closedir(tf);
269
	return 0;
270
}
271
 
272
#ifdef	notdef
273
char	pattern[] =	"/usr/preserve/Exaa`XXXXX";
274
#else
275
char	pattern[] =	"/var/preserve/Exa`XXXXXXXXXX";
276
#endif
277
 
278
/*
279
 * Notify user uid that his file fname has been saved.
280
 */
281
void
282
notify(uid_t uid, char *fname, int flag, time_t time)
283
{
284
	struct passwd *pp = getpwuid(uid);
285
	register FILE *mf;
286
	char	cmd[BUFSIZ];
287
	struct utsname ut;
288
	char *hostname;
289
	char	croak[128];
290
	char	*timestamp;
291
 
292
	if (pp == NULL)
293
		return;
294
	uname(&ut);
295
	hostname = ut.nodename;
296
	timestamp = ctime(&time);
297
	timestamp[16] = 0;	/* blast from seconds on */
298
	putenv("MAILRC=/dev/null");
299
	sprintf(cmd, "/bin/mail %s", pp->pw_name);
300
	setuid(getuid());
301
	mf = popen(cmd, "w");
302
	if (mf == NULL)
303
		return;
304
	setbuf(mf, cmd);
305
	/*
306
	 *	flag says how the editor croaked:
307
	 * "the editor was killed" is perhaps still not an ideal
308
	 * error message.  Usually, either it was forcably terminated
309
	 * or the phone was hung up, but we don't know which.
310
	 */
311
	sprintf(croak, flag
312
		? catgets(catd, 3, 2, "the system went down")
313
		: catgets(catd, 3, 3, "the editor was killed"));
314
	if (fname[0] == 0) {
315
		fname = "LOST";
316
		fprintf(mf, catgets(catd, 3, 4,
317
				"Subject: editor saved ``LOST''\n"));
318
		fprintf(mf, catgets(catd, 3, 5,
319
				"You were editing a file without a name\n"));
320
		fprintf(mf, catgets(catd, 3, 6,
321
			"at <%s> on the machine ``%s'' when %s.\n"),
322
			timestamp, hostname, croak);
323
		fprintf(mf, catgets(catd, 3, 7,
324
		"Since the file had no name, it has been named \"LOST\".\n"));
325
	} else {
326
		fprintf(mf, catgets(catd, 3, 8,
327
				"Subject: editor saved ``%s''\n"), fname);
328
		fprintf(mf, catgets(catd, 3, 9,
329
			"You were editing the file \"%s\"\n"), fname);
330
		fprintf(mf, catgets(catd, 3, 10,
331
			"at <%s> on the machine ``%s''\n"),
332
			timestamp, hostname);
333
		fprintf(mf, catgets(catd, 3, 11, "when %s.\n"), croak);
334
	}
335
	fprintf(mf, catgets(catd, 3, 12,
336
		"\nYou can retrieve most of your changes to this file\n"));
337
	fprintf(mf, catgets(catd, 3, 13,
338
			"using the \"recover\" command of the editor.\n"));
339
	fprintf(mf, catgets(catd, 3, 14,
340
"An easy way to do this is to give the command \"vi -r %s\".\n"), fname);
341
	fprintf(mf, catgets(catd, 3, 15,
342
		"This method also works using \"ex\" and \"edit\".\n"));
343
	pclose(mf);
344
}
345
 
346
/*
347
 * Copy file name into /usr/preserve/...
348
 * If name is (char *) 0, then do the standard input.
349
 * We make some checks on the input to make sure it is
350
 * really an editor temporary, generate a name for the
351
 * file (this is the slowest thing since we must stat
352
 * to find a unique name), and finally copy the file.
353
 */
354
int
355
copyout(char *name)
356
{
357
	int i;
358
	char buf[BUFSIZ];
359
	static int reenter;
360
 
361
	/*
362
	 * The first time we put in the digits of our
363
	 * process number at the end of the pattern.
364
	 */
365
	if (reenter == 0) {
366
		mkdigits(pattern);
367
		reenter++;
368
	}
369
 
370
	/*
371
	 * If a file name was given, make it the standard
372
	 * input if possible.
373
	 */
374
	if (name != 0) {
375
		ignore(close(0));
376
		/*
377
		 * Need read/write access for arcane reasons
378
		 * (see below).
379
		 */
380
		if (open(name, O_RDWR) < 0)
381
			return (-1);
382
	}
383
 
384
	/*
385
	 * Get the header block.
386
	 */
387
	ignorl(lseek(0, (off_t) 0, SEEK_SET));
388
	if (read(0, (char *) &H, sizeof H) != sizeof H) {
389
format:
390
		if (name == 0)
391
			fprintf(stderr, catgets(catd, 3, 16,
392
						"Buffer format error\t"));
393
		return (-1);
394
	}
395
 
396
	/*
397
	 * Consistency checsks so we don't copy out garbage.
398
	 */
399
	if (H.Flines < 0) {
400
#ifdef DEBUG
401
		fprintf(stderr, "Negative number of lines\n");
402
#endif
403
		goto format;
404
	}
405
	if (H.Blocks[0] != HBLKS || H.Blocks[1] != HBLKS+1) {
406
#ifdef DEBUG
407
		fprintf(stderr, "Blocks %d %d\n", H.Blocks[0], H.Blocks[1]);
408
#endif
409
		goto format;
410
	}
411
	if (name == 0 && H.Uid != getuid()) {
412
#ifdef DEBUG
413
		fprintf(stderr, "Wrong user-id\n");
414
#endif
415
		goto format;
416
	}
417
	if (lseek(0, (off_t) 0, SEEK_SET)) {
418
#ifdef DEBUG
419
		fprintf(stderr, "Negative number of lines\n");
420
#endif
421
		goto format;
422
	}
423
 
424
	/*
425
	 * If no name was assigned to the file, then give it the name
426
	 * LOST, by putting this in the header.
427
	 */
428
	if (H.Savedfile[0] == 0) {
429
		strcpy(H.Savedfile, "LOST");
430
		ignore(write(0, (char *) &H, sizeof H));
431
		H.Savedfile[0] = 0;
432
		lseek(0, (off_t) 0, SEEK_SET);
433
	}
434
 
435
	/*
436
	 * File is good.  Get a name and create a file for the copy.
437
	 */
438
	mknext(pattern);
439
	ignore(close(1));
440
	if (open(pattern, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC
441
#ifdef	O_NOFOLLOW
442
				|O_NOFOLLOW
443
#endif	/* O_NOFOLLOW */
444
				, 0600) < 0) {
445
		if (name == 0)
446
			perror(pattern);
447
		return (1);
448
	}
449
 
450
	/*
451
	 * Make the target be owned by the owner of the file.
452
	 */
453
	ignore(chown(pattern, H.Uid, 0));
454
 
455
	/*
456
	 * Copy the file.
457
	 */
458
	for (;;) {
459
		i = read(0, buf, BUFSIZ);
460
		if (i < 0) {
461
			if (name)
462
				perror(catgets(catd, 3, 17,
463
						"Buffer read error"));
464
			ignore(unlink(pattern));
465
			return (-1);
466
		}
467
		if (i == 0) {
468
			if (name)
469
				ignore(unlink(name));
470
			notify(H.Uid, H.Savedfile, name != 0, H.Time);
471
			return (0);
472
		}
473
		if (write(1, buf, i) != i) {
474
			if (name == 0)
475
				perror(pattern);
476
			unlink(pattern);
477
			return (-1);
478
		}
479
	}
480
}
481
 
482
/*
483
 * Blast the last 5 characters of cp to be the process number.
484
 */
485
void
486
mkdigits(char *cp)
487
{
488
	register pid_t i;
489
	register int j;
490
 
491
#ifdef	notdef
492
	for (i = getpid(), j = 5, cp += strlen(cp); j > 0; i /= 10, j--)
493
		*--cp = i % 10 | '0';
494
#else
495
	for (i = getpid(), j = 10, cp += strlen(cp); j > 0; i /= 10, j--)
496
		*--cp = i % 10 | '0';
497
#endif
498
}
499
 
500
/*
501
 * Make the name in cp be unique by clobbering up to
502
 * three alphabetic characters into a sequence of the form 'aab', 'aac', etc.
503
 * Mktemp gets weird names too quickly to be useful here.
504
 */
505
void
506
mknext(char *cp)
507
{
508
	char *dcp;
509
	struct stat stb;
510
 
511
	dcp = cp + strlen(cp) - 1;
512
	while (isdigit(*dcp & 0377))
513
		dcp--;
514
whoops:
515
	if (dcp[0] == 'z') {
516
		dcp[0] = 'a';
517
		if (dcp[-1] == 'z') {
518
#ifdef	notdef
519
			dcp[-1] = 'a';
520
			if (dcp[-2] == 'z')
521
#endif
522
				fprintf(stderr, catgets(catd, 3, 18,
523
						"Can't find a name\t"));
524
#ifdef	notdef
525
			dcp[-2]++;
526
#endif
527
		} else
528
			dcp[-1]++;
529
	} else
530
		dcp[0]++;
531
	if (stat(cp, &stb) == 0)
532
		goto whoops;
533
}
534
 
535
/*
536
 *	people making love
537
 *	never exactly the same
538
 *	just like a snowflake 
539
 */
540
 
541
#ifdef lint
542
void
543
Ignore(int a)
544
{
545
 
546
	a = a;
547
}
548
 
549
void
550
Ignorl(long a)
551
{
552
 
553
	a = a;
554
}
555
#endif