]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/hjfs/cons.c
fix filetype detecton by suffix so that multiple dots dont confuse it. (thanks kvik)
[plan9front.git] / sys / src / cmd / hjfs / cons.c
1 #include <u.h>
2 #include <libc.h>
3 #include <thread.h>
4 #include <bio.h>
5 #include "dat.h"
6 #include "fns.h"
7
8 enum { MAXARGS = 16 };
9
10 typedef struct Cmd Cmd;
11 static int echo;
12 extern Fs *fsmain;
13
14 struct Cmd {
15         char *name;
16         int args;
17         int (*f)(int, char **);
18 };
19
20 static int
21 walkpath(Chan *ch, char *path, char **cr)
22 {
23         char buf[NAMELEN], *p, *fp;
24
25         fp = path;
26         if(*path != '/'){
27         noent:
28                 werrstr("%s: %s", fp, Enoent);
29                 return -1;
30         }
31         path++;
32         for(;;){
33                 p = strchr(path, '/');
34                 if(p == nil){
35                         if(cr != nil){
36                                 if(*path == 0){
37                                         werrstr("%s: trailing slash", fp);
38                                         return -1;
39                                 }
40                                 *cr = path;
41                                 break;
42                         }
43                         p = path + strlen(path);
44                 }
45                 if(*path == '/'){
46                         path++;
47                         continue;
48                 }
49                 if(*path == 0)
50                         break;
51                 if(p - path >= NAMELEN)
52                         goto noent;
53                 memset(buf, 0, sizeof buf);
54                 memcpy(buf, path, p - path);
55                 if(chanwalk(ch, buf) <= 0){
56                         werrstr("%s: %r", fp);
57                         return -1;
58                 }
59                 if(*p == 0)
60                         break;
61                 path = p + 1;
62         }
63         return 1;
64 }
65
66 int
67 cmdsync(int, char **)
68 {
69         sync(1);
70         dprint("sync\n");
71         return 0;
72 }
73
74 int
75 cmdhalt(int, char **)
76 {
77         shutdown();
78         return 0;
79 }
80
81 int
82 cmddump(int, char **)
83 {
84         fsdump(fsmain);
85         dprint("dumped\n");
86         return 0;
87 }
88
89 int
90 cmdallow(int, char **)
91 {
92         fsmain->flags |= FSNOPERM | FSCHOWN;
93         dprint("allow\n");
94         return 0;
95 }
96
97 int
98 cmdchatty(int, char **)
99 {
100         extern int chatty9p;
101
102         chatty9p = !chatty9p;
103         return 0;
104 }
105
106 static void
107 checkfile(FLoc *l, Buf *b)
108 {
109         Buf *c;
110         Dentry *d;
111         char *ftype;
112         int btype, rc;
113         uvlong i, r, blocks;
114
115         d = getdent(l, b);
116         if(d == nil){
117                 dprint("checkfile: bad entry: %r\n");
118                 return;
119         }
120         if((d->type & QTDIR) == 0){
121                 ftype = "file";
122                 btype = TRAW;
123                 blocks = HOWMANY(d->size);
124         }else{
125                 ftype = "directory";
126                 btype = TDENTRY;
127                 blocks = d->size;
128         }
129
130         for(i = 0; i < blocks; i++){
131                 rc = getblk(fsmain, l, b, i, &r, GBREAD);
132                 if(rc < 0){
133                         dprint("bad block %ulld of %ulld in %s %s with directory entry index %d in block %ulld: %r\n", i, blocks, ftype, d->name, l->deind, l->blk);
134                         continue;
135                 }
136                 if(rc == 0){
137                         dprint("block %ulld of %ulld not found in %s %s with directory index %d in block %ulld\n", i, blocks, ftype, d->name, l->deind, l->blk);
138                         continue;
139                 }
140                 c = getbuf(fsmain->d, r, btype, 0);
141                 if(c == nil)
142                         dprint("bad block %ulld of %ulld in %s %s with directory entry index %d in block %ulld: %r\n", i, blocks, ftype, d->name, l->deind, l->blk);
143                 putbuf(c);
144                 if(chref(fsmain, r, 0) == 0)
145                         dprint("block %ulld of %ulld in %s %s with directory entry index %d in block %ulld has a reference count of 0", i, blocks, ftype, d->name, l->deind, l->blk);
146         }
147 }
148
149 static int
150 checkblk(uvlong blk)
151 {
152         Dentry *d;
153         Buf *b;
154         FLoc l;
155         int i, type;
156
157         b = getbuf(fsmain->d, blk, TDONTCARE, 0);
158         if(b == nil)
159                 return -1;
160         switch(type = b->type){
161         case TSUPERBLOCK:
162                 if(blk != SUPERBLK)
163                         dprint("checkblk: should not have found superblock at %ulld\n", blk);
164                 break;
165         case TDENTRY:
166                 l.blk = blk;
167                 for(i = 0; i < DEPERBLK; i++){
168                         d = &b->de[i];
169                         if((d->mode & (DGONE | DALLOC)) == 0)
170                                 break;
171                         l.deind = i;
172                         l.Qid = d->Qid;
173                         checkfile(&l, b);
174                 }
175                 break;
176         }
177         putbuf(b);
178         return type;
179 }
180
181 int
182 cmdcheck(int, char**)
183 {
184         static ulong refs[REFPERBLK];
185         uvlong fblk, fend, blk;
186         uvlong ndentry, nindir, nraw, nref, nsuperblock;
187         int j;
188         Buf *b, *sb;
189
190         wlock(fsmain);
191         sb = getbuf(fsmain->d, SUPERBLK, TSUPERBLOCK, 0);
192         if(sb == nil){
193                 wunlock(fsmain);
194                 return -1;
195         }
196         fblk = sb->sb.fstart;
197         fend = sb->sb.fend;
198         putbuf(sb);
199
200         ndentry = 0;
201         nindir = 0;
202         nraw = 0;
203         nref = 0;
204         nsuperblock = 0;
205         for(blk = 0; fblk < fend; fblk++){
206                 b = getbuf(fsmain->d, fblk, TREF, 0);
207                 if(b == nil){
208                         blk += REFPERBLK;
209                         continue;
210                 }
211                 memcpy(refs, b->refs, sizeof(refs));
212                 putbuf(b);
213                 for(j = 0; j < REFPERBLK; j++, blk++){
214                         if(refs[j] > 0 && refs[j] != REFSENTINEL){
215                                 switch(checkblk(blk)){
216                                 case TDENTRY:
217                                         ndentry++;
218                                         break;
219                                 case TINDIR:
220                                         nindir++;
221                                         break;
222                                 case TRAW:
223                                         nraw++;
224                                         break;
225                                 case TREF:
226                                         nref++;
227                                         break;
228                                 case TSUPERBLOCK:
229                                         nsuperblock++;
230                                         break;
231                                 }
232                         }
233                 }
234         }
235         wunlock(fsmain);
236         dprint("%T block count %ulld\n", TDENTRY, ndentry);
237         dprint("%T block count %ulld\n", TINDIR, nindir);
238         dprint("%T block count %ulld\n", TRAW, nraw);
239         dprint("%T block count %ulld\n", TREF, nref);
240         dprint("%T block count %ulld\n", TSUPERBLOCK, nsuperblock);
241         return 1;
242 }
243
244 int
245 cmddisallow(int, char **)
246 {
247         fsmain->flags &= ~(FSNOPERM | FSCHOWN);
248         dprint("disallow\n");
249         return 0;
250 }
251
252 int
253 cmdnoauth(int, char **)
254 {
255         fsmain->flags ^= FSNOAUTH;
256         if((fsmain->flags & FSNOAUTH) == 0)
257                 dprint("auth enabled\n");
258         else
259                 dprint("auth disabled\n");
260         return 1;
261 }
262
263 int
264 cmdcreate(int argc, char **argv)
265 {
266         Chan *ch;
267         char *n;
268         short uid, gid;
269         ulong perm;
270         Dir di;
271
272         if(argc != 5 && argc != 6)
273                 return -9001;
274         perm = strtol(argv[4], &n, 8) & 0777;
275         if(*n != 0)
276                 return -9001;
277         if(argc == 6)
278                 for(n = argv[5]; *n != 0; n++)
279                         switch(*n){
280                         case 'l': perm |= DMEXCL; break;
281                         case 'd': perm |= DMDIR; break;
282                         case 'a': perm |= DMAPPEND; break;
283                         default: return -9001;
284                         }
285         if(name2uid(fsmain, argv[2], &uid) < 0)
286                 return -1;
287         if(name2uid(fsmain, argv[3], &gid) < 0)
288                 return -1;
289         ch = chanattach(fsmain, CHFNOPERM);
290         if(ch == nil)
291                 return -1;
292         ch->uid = uid;
293         if(walkpath(ch, argv[1], &n) < 0){
294                 chanclunk(ch);
295                 return -1;
296         }
297         if(chancreat(ch, n, perm, OREAD) < 0){
298                 chanclunk(ch);
299                 return -1;
300         }
301         nulldir(&di);
302         di.gid = argv[3];
303         chanwstat(ch, &di);
304         chanclunk(ch);
305         return 1;
306 }
307
308 int
309 cmdecho(int, char **argv)
310 {
311         echo = strcmp(argv[1], "on") == 0;
312         return 1;
313 }
314
315 int
316 cmddf(int, char **)
317 {
318         uvlong n;
319         uvlong i;
320         int j;
321         Buf *b, *sb;
322
323         wlock(fsmain);
324         sb = getbuf(fsmain->d, SUPERBLK, TSUPERBLOCK, 0);
325         if(sb == nil){
326                 wunlock(fsmain);
327                 return -1;
328         }
329         n = 0;
330         for(i = sb->sb.fstart; i < sb->sb.fend; i++){
331                 b = getbuf(fsmain->d, i, TREF, 0);
332                 if(b == nil)
333                         continue;
334                 for(j = 0; j < REFPERBLK; j++)
335                         if(b->refs[j] == 0)
336                                 n++;
337                 putbuf(b);
338         }
339         dprint("(blocks) free %ulld, used %ulld, total %ulld\n", n, sb->sb.size - n, sb->sb.size);
340         dprint("(MB) free %ulld, used %ulld, total %ulld\n", n * BLOCK / 1048576, (sb->sb.size - n) * BLOCK / 1048576, sb->sb.size * BLOCK / 1048576);
341         putbuf(sb);
342         wunlock(fsmain);
343         return 1;
344 }
345
346 int
347 cmddebugdeind(int, char **argv)
348 {
349         Chan *ch;
350         Buf *b;
351         Dentry *d;
352
353         ch = chanattach(fsmain, 0);
354         if(ch == nil)
355                 return -1;
356         ch->uid = -1;
357         if(walkpath(ch, argv[1], nil) < 0)
358                 goto error;
359         rlock(fsmain);
360         dprint("loc %ulld / %uld, offset %ulld\n", ch->loc->blk, ch->loc->deind, BLOCK * ch->loc->blk + (RBLOCK - BLOCK) + DENTRYSIZ * ch->loc->deind);
361         b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
362         if(b == nil){
363                 runlock(fsmain);
364                 goto error;
365         }
366         d = &b->de[ch->loc->deind];
367         dprint("name %s\n", d->name);
368         dprint("uid %d, muid %d, gid %d\n", d->uid, d->muid, d->gid);
369         dprint("mode %#o, qid %ulld, type %#x, version %d\n", d->mode, d->path, d->type, d->vers);
370         dprint("size %d\n", d->size);
371         dprint("atime %ulld, mtime %ulld\n", d->atime, d->mtime);
372         putbuf(b);
373         runlock(fsmain);
374         chanclunk(ch);
375         return 0;
376 error:
377         chanclunk(ch);
378         return -1;
379 }
380
381 int
382 cmddebugchdeind(int, char **argv)
383 {
384         Chan *ch;
385         uchar *c;
386         Buf *b;
387         int loc, new;
388
389         loc = strtol(argv[2], nil, 0);
390         new = strtol(argv[3], nil, 0);
391         if(loc >= DENTRYSIZ)
392                 return -9001;
393         ch = chanattach(fsmain, 0);
394         if(ch == nil)
395                 return -1;
396         ch->uid = -1;
397         if(walkpath(ch, argv[1], nil) < 0)
398                 goto error;
399         rlock(fsmain);
400         b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
401         if(b == nil){
402                 runlock(fsmain);
403                 goto error;
404         }
405         c = (uchar *) &b->de[ch->loc->deind];
406         dprint("loc %d, old value %#.2x, new value %#.2x\n", loc, c[loc], new);
407         c[loc] = new;
408         b->op |= BDELWRI;
409         putbuf(b);
410         runlock(fsmain);
411         chanclunk(ch);
412         return 0;
413 error:
414         chanclunk(ch);
415         return -1;
416 }
417
418 int
419 cmddebuggetblk(int argc, char **argv)
420 {
421         Chan *ch;
422         Buf *b;
423         int rc;
424         uvlong r, start, end, i;
425
426         if(argc != 3 && argc != 4)
427                 return -9001;
428         start = atoll(argv[2]);
429         if(argc == 4)
430                 end = atoll(argv[3]);
431         else
432                 end = start;
433         ch = chanattach(fsmain, 0);
434         if(ch == nil)
435                 return -1;
436         ch->uid = -1;
437         if(walkpath(ch, argv[1], nil) < 0)
438                 goto error;
439         rlock(fsmain);
440         b = getbuf(fsmain->d, ch->loc->blk, TDENTRY, 0);
441         if(b == nil){
442                 runlock(fsmain);
443                 goto error;
444         }
445         for(i = start; i <= end; i++){
446                 rc = getblk(fsmain, ch->loc, b, i, &r, GBREAD);
447                 if(rc > 0)
448                         dprint("getblk %ulld = %ulld\n", i, r);
449                 if(rc == 0)
450                         dprint("getblk %ulld not found\n", i);
451                 if(rc < 0)
452                         dprint("getblk %ulld: %r\n", i);
453         }
454         putbuf(b);
455         runlock(fsmain);
456         chanclunk(ch);
457         return 0;
458 error:
459         chanclunk(ch);
460         return -1;
461 }
462
463 int
464 cmdusers(int, char**)
465 {
466         readusers(fsmain);
467         return 0;
468 }
469
470 extern int cmdnewuser(int, char **);
471
472 Cmd cmds[] = {
473         {"allow", 1, cmdallow},
474         {"noauth", 1, cmdnoauth},
475         {"chatty", 1, cmdchatty},
476 //      {"check", 0, cmdcheck},
477         {"create", 0, cmdcreate},
478         {"disallow", 1, cmddisallow},
479         {"dump", 1, cmddump},
480         {"sync", 1, cmdsync},
481         {"halt", 1, cmdhalt},
482         {"newuser", 0, cmdnewuser},
483         {"users", 1, cmdusers},
484         {"echo", 2, cmdecho},
485         {"df", 1, cmddf},
486         {"debug-deind", 2, cmddebugdeind},
487         {"debug-getblk", 0, cmddebuggetblk},
488         {"debug-chdeind", 4, cmddebugchdeind},
489 };
490
491
492 static void
493 consproc(void *v)
494 {
495         Biobuf *in;
496         Cmd *c;
497         char *s;
498         char *args[MAXARGS];
499         int rc;
500         
501         in = (Biobuf *) v;
502         for(;;){
503                 s = Brdstr(in, '\n', 1);
504                 if(s == nil)
505                         continue;
506                 if(echo)
507                         dprint(">%s\n", s);
508                 rc = tokenize(s, args, MAXARGS);
509                 if(rc == 0)
510                         goto syntax;
511                 for(c = cmds; c < cmds + nelem(cmds); c++)
512                         if(strcmp(c->name, args[0]) == 0){
513                                 if(c->args != 0 && c->args != rc)
514                                         goto syntax;
515                                 if(c->f != nil){
516                                         rc = c->f(rc, args);
517                                         if(rc == -9001)
518                                                 goto syntax;
519                                         if(rc < 0)
520                                                 dprint("%r\n");
521                                         goto done;
522                                 }
523                         }
524         syntax:
525                 dprint("syntax error\n");
526         done:
527                 free(s);
528         }
529 }
530
531 void
532 initcons(char *service)
533 {
534         int fd, pfd[2];
535         static Biobuf bio;
536         char buf[512];
537
538         snprint(buf, sizeof(buf), "/srv/%s.cmd", service);
539         fd = create(buf, OWRITE|ORCLOSE, 0600);
540         if(fd < 0)
541                 return;
542         pipe(pfd);
543         fprint(fd, "%d", pfd[1]);
544         Binit(&bio, pfd[0], OREAD);
545         proccreate(consproc, &bio, mainstacksize);
546 }