Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	<u.h>
2
#include	<libc.h>
3
 
4
#define	MINUTE(x)	((long)(x)*60L)
5
#define	HOUR(x)		(MINUTE(x)*60L)
6
#define	YEAR(x)		(HOUR(x)*24L*360L)
7
 
8
int	verb;
9
int	uflag;
10
int	force;
11
int	diff;
12
char*	sflag;
13
char*	dargv[20] = {
14
	"diff",
15
};
16
int	ndargv = 1;
17
 
18
void	usage(void);
19
void	ysearch(char*, char*);
20
long	starttime(char*);
21
void	lastbefore(ulong, char*, char*, char*);
22
char*	prtime(ulong);
23
void	darg(char*);
24
 
25
void
26
main(int argc, char *argv[])
27
{
28
	int i;
29
	char *ndump;
30
 
31
	ndump = nil;
32
	ARGBEGIN {
33
	default:
34
		usage();
35
	case 'a':
36
		darg("-a");
37
		break;
38
	case 'b':
39
		darg("-b");
40
		break;
41
	case 'c':
42
		darg("-c");
43
		break;
44
	case 'e':
45
		darg("-e");
46
		break;
47
	case 'm':
48
		darg("-m");
49
		break;
50
	case 'n':
51
		darg("-n");
52
		break;
53
	case 'w':
54
		darg("-w");
55
		break;
56
	case 'D':
57
		diff = 1;
58
		break;
59
	case 'd':
60
		ndump = ARGF();
61
		break;
62
	case 'f':
63
		force = 1;
64
		break;
65
	case 's':
66
		sflag = ARGF();
67
		break;
68
	case 'u':
69
		uflag = 1;
70
		break;
71
	case 'v':
72
		verb = 1;
73
		break;
74
	} ARGEND
75
 
76
	if(argc == 0)
77
		usage();
78
 
79
	for(i=0; i<argc; i++)
80
		ysearch(argv[i], ndump);
81
	exits(0);
82
}
83
 
84
void
85
darg(char* a)
86
{
87
	if(ndargv >= nelem(dargv)-3)
88
		return;
89
	dargv[ndargv++] = a;
90
}
91
 
92
void
93
usage(void)
94
{
95
	fprint(2, "usage: history [-bDfuv] [-d dumpfilesystem] [-s yyyymmdd] files\n");
96
	exits("usage");
97
}
98
 
99
void
100
ysearch(char *file, char *ndump)
101
{
102
	char fil[400], buf[500], nbuf[100], pair[2][500], *p;
103
	Tm *tm;
104
	Waitmsg *w;
105
	Dir *dir, *d;
106
	ulong otime, dt;
107
	int toggle, started, missing;
108
 
109
	fil[0] = 0;
110
	if(file[0] != '/') {
111
		getwd(strchr(fil, 0), 100);
112
		strcat(fil, "/");
113
	}
114
	strcat(fil, file);
115
	if(memcmp(fil, "/n/", 3) == 0){
116
		p = strchr(fil+3, '/');
117
		if(p == nil)
118
			p = fil+strlen(fil);
119
		if(ndump == nil){
120
			if(p-fil >= sizeof nbuf-10){
121
				fprint(2, "%s: dump name too long", fil);
122
				return;
123
			}
124
			memmove(nbuf, fil+3, p-(fil+3));
125
			nbuf[p-(fil+3)] = 0;
126
			strcat(nbuf, "dump");
127
			ndump = nbuf;
128
		}
129
		memmove(fil, p, strlen(p)+1);
130
	}
131
	if(ndump == nil)
132
		ndump = "dump";
133
 
134
	tm = localtime(time(0));
135
	snprint(buf, sizeof buf, "/n/%s/%.4d/", ndump, tm->year+1900);
136
	if(access(buf, AREAD) < 0) {
137
		if(verb)
138
			print("mounting dump %s\n", ndump);
139
		if(rfork(RFFDG|RFPROC) == 0) {
140
			execl("/bin/rc", "rc", "9fs", ndump, nil);
141
			exits(0);
142
		}
143
		w = wait();
144
		if(w == nil){
145
			fprint(2, "history: wait error: %r\n");
146
			exits("wait");
147
		}
148
		if(w->msg[0] != '\0'){
149
			fprint(2, "9fs failed: %s\n", w->msg);
150
			exits(w->msg);
151
		}
152
		free(w);
153
	}
154
 
155
	started = 0;
156
	dir = dirstat(file);
157
	if(dir == nil)
158
		fprint(2, "history: warning: %s does not exist\n", file);
159
	else{
160
		print("%s %s %lld [%s]\n", prtime(dir->mtime), file, dir->length, dir->muid);
161
		started = 1;
162
		strecpy(pair[1], pair[1]+sizeof pair[1], file);
163
	}
164
	free(dir);
165
	otime = starttime(sflag);
166
	toggle = 0;
167
	for(;;) {
168
		lastbefore(otime, fil, buf, ndump);
169
		dir = dirstat(buf);
170
		if(dir == nil) {
171
			if(!force)
172
				return;
173
			dir = malloc(sizeof(Dir));
174
			nulldir(dir);
175
			dir->mtime = otime + 1;
176
		}
177
		dt = HOUR(12);
178
		missing = 0;
179
		while(otime <= dir->mtime){
180
			if(verb)
181
				print("backup %ld, %ld\n", dir->mtime, otime-dt);
182
			lastbefore(otime-dt, fil, buf, ndump);
183
			d = dirstat(buf);
184
			if(d == nil){
185
				if(!force)
186
					return;
187
				if(!missing)
188
					print("removed %s\n", buf);
189
				missing = 1;
190
			}else{
191
				free(dir);
192
				dir = d;
193
			}
194
			dt += HOUR(12);
195
		}
196
		strcpy(pair[toggle], buf);
197
		if(diff && started){
198
			switch(rfork(RFFDG|RFPROC)){
199
			case 0:
200
				dargv[ndargv] = pair[toggle];
201
				dargv[ndargv+1] = pair[toggle ^ 1];
202
				exec("/bin/diff", dargv);
203
				fprint(2, "can't exec diff: %r\n");
204
				exits(0);
205
			case -1:
206
				fprint(2, "can't fork diff: %r\n");
207
				break;
208
			default:
209
				while(waitpid() != -1)
210
					;
211
				break;
212
			}
213
		}
214
		print("%s %s %lld [%s]\n", prtime(dir->mtime), buf, dir->length, dir->muid);
215
		toggle ^= 1;
216
		started = 1;
217
		otime = dir->mtime;
218
		free(dir);
219
	}
220
}
221
 
222
void
223
lastbefore(ulong t, char *f, char *b, char *ndump)
224
{
225
	Tm *tm;
226
	Dir *dir;
227
	int vers, try;
228
	ulong t0, mtime;
229
	int i, n, fd;
230
 
231
	t0 = t;
232
	if(verb)
233
		print("%ld lastbefore %s\n", t0, f);
234
	mtime = 0;
235
	for(try=0; try<30; try++) {
236
		tm = localtime(t);
237
		sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump,
238
			tm->year+1900, tm->mon+1, tm->mday);
239
		dir = dirstat(b);
240
		if(dir){
241
			mtime = dir->mtime;
242
			free(dir);
243
		}
244
		if(dir==nil || mtime > t0) {
245
			if(verb)
246
				print("%ld earlier %s\n", mtime, b);
247
			t -= HOUR(24);
248
			continue;
249
		}
250
		if(strstr(ndump, "snap")){
251
			fd = open(b, OREAD);
252
			if(fd < 0)
253
				continue;
254
			n = dirreadall(fd, &dir);
255
			close(fd);
256
			if(n == 0)
257
				continue;
258
			for(i = n-1; i > 0; i--){
259
				if(dir[i].mtime > t0)
260
					break;
261
			}
262
			sprint(b, "/n/%s/%.4d/%.2d%.2d/%s%s", ndump,
263
				tm->year+1900, tm->mon+1, tm->mday, dir[i].name, f);
264
			free(dir);
265
		} else {
266
			for(vers=0;; vers++) {
267
				sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump,
268
					tm->year+1900, tm->mon+1, tm->mday, vers+1);
269
				dir = dirstat(b);
270
				if(dir){
271
					mtime = dir->mtime;
272
					free(dir);
273
				}
274
				if(dir==nil || mtime > t0)
275
					break;
276
				if(verb)
277
					print("%ld later %s\n", mtime, b);
278
			}
279
			sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump,
280
				tm->year+1900, tm->mon+1, tm->mday, f);
281
			if(vers)
282
				sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump,
283
					tm->year+1900, tm->mon+1, tm->mday, vers, f);
284
		}
285
		return;
286
	}
287
	strcpy(b, "XXX");	/* error */
288
}
289
 
290
char*
291
prtime(ulong t)
292
{
293
	static char buf[100];
294
	char *b;
295
	Tm *tm;
296
 
297
	if(uflag)
298
		tm = gmtime(t);
299
	else
300
		tm = localtime(t);
301
	b = asctime(tm);
302
	memcpy(buf, b+4, 24);
303
	buf[24] = 0;
304
	return buf;
305
}
306
 
307
long
308
starttime(char *s)
309
{
310
	Tm *tm;
311
	long t, dt;
312
	int i, yr, mo, da;
313
 
314
	t = time(0);
315
	if(s == 0)
316
		return t;
317
	for(i=0; s[i]; i++)
318
		if(s[i] < '0' || s[i] > '9') {
319
			fprint(2, "bad start time: %s\n", s);
320
			return t;
321
		}
322
	if(strlen(s)==6){
323
		yr = (s[0]-'0')*10 + s[1]-'0';
324
		mo = (s[2]-'0')*10 + s[3]-'0' - 1;
325
		da = (s[4]-'0')*10 + s[5]-'0';
326
		if(yr < 70)
327
			yr += 100;
328
	}else if(strlen(s)==8){
329
		yr = (((s[0]-'0')*10 + s[1]-'0')*10 + s[2]-'0')*10 + s[3]-'0';
330
		yr -= 1900;
331
		mo = (s[4]-'0')*10 + s[5]-'0' - 1;
332
		da = (s[6]-'0')*10 + s[7]-'0';
333
	}else{
334
		fprint(2, "bad start time: %s\n", s);
335
		return t;
336
	}
337
	t = 0;
338
	dt = YEAR(10);
339
	for(i=0; i<50; i++) {
340
		tm = localtime(t+dt);
341
		if(yr > tm->year ||
342
		  (yr == tm->year && mo > tm->mon) ||
343
		  (yr == tm->year && mo == tm->mon) && da > tm->mday) {
344
			t += dt;
345
			continue;
346
		}
347
		dt /= 2;
348
		if(dt == 0)
349
			break;
350
	}
351
	t += HOUR(12);	/* .5 day to get to noon of argument */
352
	return t;
353
}