xref: /plan9-contrib/sys/src/cmd/history.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
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	diff;
11 int	diffb;
12 char*	ndump;
13 char*	sflag;
14 
15 void	ysearch(char*);
16 long	starttime(char*);
17 void	lastbefore(ulong, char*, char*);
18 char*	prtime(ulong);
19 
20 void
21 main(int argc, char *argv[])
22 {
23 	char buf[100];
24 	Tm *tm;
25 	Dir dir;
26 	Waitmsg w;
27 	int i;
28 
29 	ndump = "dump";
30 	ARGBEGIN {
31 	default:
32 		goto usage;
33 	case 'v':
34 		verb = 1;
35 		break;
36 	case 'd':
37 		ndump = ARGF();
38 		break;
39 	case 'D':
40 		diff = 1;
41 		break;
42 	case 'b':
43 		diffb = 1;
44 		break;
45 	case 's':
46 		sflag = ARGF();
47 		break;
48 	case 'u':
49 		uflag = 1;
50 		break;
51 	} ARGEND
52 
53 	if(argc == 0) {
54 	usage:
55 		fprint(2, "usage: history [-vuD] [-d 9fsname] [-s yymmdd] files\n");
56 		exits(0);
57 	}
58 
59 	tm = localtime(time(0));
60 	sprint(buf, "/n/%s/%.4d/", ndump, tm->year+1900);
61 	if(dirstat(buf, &dir)) {
62 		if(verb)
63 			print("mounting dump\n");
64 		if(rfork(RFFDG|RFPROC) == 0) {
65 			execl("/bin/rc", "rc", "9fs", ndump, 0);
66 			exits(0);
67 		}
68 		while(wait(&w) != -1)
69 			;
70 	}
71 
72 	for(i=0; i<argc; i++)
73 		ysearch(argv[i]);
74 	exits(0);
75 }
76 
77 void
78 ysearch(char *file)
79 {
80 	char fil[400], buf[500], pair[2][500];
81 	Dir dir;
82 	ulong otime, dt;
83 	int toggle, started;
84 
85 	fil[0] = 0;
86 	if(file[0] != '/') {
87 		getwd(strchr(fil, 0), 100);
88 		strcat(fil, "/");
89 	}
90 	strcat(fil, file);
91 	dir.mtime = starttime(sflag);
92 	started = 0;
93 	toggle = 0;
94 	for(;;) {
95 		otime = dir.mtime;
96 		lastbefore(otime, fil, buf);
97 		if(dirstat(buf, &dir))
98 			return;
99 		dt = HOUR(12);
100 		while(otime <= dir.mtime) {
101 			if(verb)
102 				print("backup %ld, %ld\n", dir.mtime, otime-dt);
103 			lastbefore(otime-dt, fil, buf);
104 			if(dirstat(buf, &dir))
105 				return;
106 			dt += HOUR(12);
107 		}
108 		strcpy(pair[toggle], buf);
109 		if(diff && started){
110 			switch(rfork(RFFDG|RFPROC)){
111 			case 0:
112 				if(diffb)
113 					execl("/bin/diff", "diff", "-b", pair[toggle ^ 1], pair[toggle], 0);
114 				else
115 					execl("/bin/diff", "diff", pair[toggle ^ 1], pair[toggle], 0);
116 				fprint(2, "can't exec diff: %r\n");
117 				exits(0);
118 			case -1:
119 				fprint(2, "can't fork diff: %r\n");
120 				break;
121 			default:
122 				while(wait(nil) != -1)
123 					;
124 				break;
125 			}
126 		}
127 		print("%s %s %lld\n", prtime(dir.mtime), buf, dir.length);
128 		toggle ^= 1;
129 		started = 1;
130 	}
131 }
132 
133 void
134 lastbefore(ulong t, char *f, char *b)
135 {
136 	Tm *tm;
137 	Dir dir;
138 	int vers, try;
139 	ulong t0;
140 
141 	t0 = t;
142 	if(verb)
143 		print("%ld lastbefore %s\n", t0, f);
144 	for(try=0; try<10; try++) {
145 		tm = localtime(t);
146 		sprint(b, "/n/%s/%.4d/%.2d%.2d", ndump,
147 			tm->year+1900, tm->mon+1, tm->mday);
148 		if(dirstat(b, &dir) || dir.mtime > t0) {
149 			if(verb)
150 				print("%ld earlier %s\n", dir.mtime, b);
151 			t -= HOUR(24);
152 			continue;
153 		}
154 		for(vers=0;; vers++) {
155 			sprint(b, "/n/%s/%.4d/%.2d%.2d%d", ndump,
156 				tm->year+1900, tm->mon+1, tm->mday, vers+1);
157 			if(dirstat(b, &dir) || dir.mtime > t0)
158 				break;
159 			if(verb)
160 				print("%ld later %s\n", dir.mtime, b);
161 		}
162 		sprint(b, "/n/%s/%.4d/%.2d%.2d%s", ndump,
163 			tm->year+1900, tm->mon+1, tm->mday, f);
164 		if(vers)
165 			sprint(b, "/n/%s/%.4d/%.2d%.2d%d%s", ndump,
166 				tm->year+1900, tm->mon+1, tm->mday, vers, f);
167 		return;
168 	}
169 	strcpy(b, "XXX");	/* error */
170 }
171 
172 char*
173 prtime(ulong t)
174 {
175 	static char buf[100];
176 	char *b;
177 	Tm *tm;
178 
179 	if(uflag)
180 		tm = gmtime(t);
181 	else
182 		tm = localtime(t);
183 	b = asctime(tm);
184 	memcpy(buf, b+4, 24);
185 	buf[24] = 0;
186 	return buf;
187 }
188 
189 long
190 starttime(char *s)
191 {
192 	Tm *tm;
193 	long t, dt;
194 	int i, yr, mo, da;
195 
196 	t = time(0);
197 	if(s == 0)
198 		return t;
199 	for(i=0; i<6; i++)
200 		if(s[i] < '0' || s[i] > '9') {
201 			fprint(2, "bad start time: %s\n", s);
202 			return t;
203 		}
204 	yr = (s[0]-'0')*10 + s[1]-'0';
205 	mo = (s[2]-'0')*10 + s[3]-'0' - 1;
206 	da = (s[4]-'0')*10 + s[5]-'0';
207 
208 	t = 0;
209 	dt = YEAR(10);
210 	for(i=0; i<50; i++) {
211 		tm = localtime(t+dt);
212 		if(yr > tm->year ||
213 		  (yr == tm->year && mo > tm->mon) ||
214 		  (yr == tm->year && mo == tm->mon) && da > tm->mday) {
215 			t += dt;
216 			continue;
217 		}
218 		dt /= 2;
219 		if(dt == 0)
220 			break;
221 	}
222 	t += HOUR(12);	/* .5 day to get to noon of argument */
223 	return t;
224 }
225