]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/history.c
kbdfs: simplfy
[plan9front.git] / sys / src / cmd / history.c
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 }