]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/disk/kfs/con.c
Add Erik Quanstrom's smart tool for ATA SMART.
[plan9front.git] / sys / src / cmd / disk / kfs / con.c
1 #include        "all.h"
2 #include        "9p1.h"
3
4 static  char    elem[NAMELEN];
5 static  Filsys* cur_fs;
6 static  char    conline[100];
7
8 void
9 consserve(void)
10 {
11         con_session();
12         cmd_exec("cfs");
13         cmd_exec("user");
14 }
15
16 int
17 cmd_exec(char *arg)
18 {
19         char *s, *c;
20         int i;
21
22         for(i=0; s = command[i].string; i++) {
23                 for(c=arg; *s; c++)
24                         if(*c != *s++)
25                                 goto brk;
26                 if(*c == '\0' || *c == ' ' || *c == '\t'){
27                         cons.arg = c;
28                         (*command[i].func)();
29                         return 1;
30                 }
31         brk:;
32         }
33         return 0;
34 }
35
36 void
37 cmd_check(void)
38 {
39         char *s;
40         int flags;
41
42         flags = 0;
43         for(s = cons.arg; *s; s++){
44                 while(*s == ' ' || *s == '\t')
45                         s++;
46                 if(*s == '\0')
47                         break;
48                 switch(*s){
49                 /* rebuild the free list */
50                 case 'f':       flags |= Cfree;                 break;
51                 /* fix bad tags */
52                 case 't':       flags |= Ctag;                  break;
53                 /* fix bad tags and clear the contents of the block */
54                 case 'c':       flags |= Cream;                 break;
55                 /* delete all redundant references to a block */
56                 case 'd':       flags |= Cbad;                  break;
57                 /* read and check tags on all blocks */
58                 case 'r':       flags |= Crdall;                break;
59                 /* write all of the blocks you touch */
60                 case 'w':       flags |= Ctouch;                break;
61                 /* print all directories as they are read */
62                 case 'p':       flags |= Cpdir;                 break;
63                 /* print all files as they are read */
64                 case 'P':       flags |= Cpfile;                break;
65                 /* quiet, just report really nasty stuff */
66                 case 'q':       flags |= Cquiet;                break;
67                 }
68         }
69         check(cur_fs, flags);
70 }
71
72 enum
73 {
74         Sset    = (1<<0),
75         Setc    = (1<<1),
76 };
77 void
78 cmd_stats(void)
79 {
80         cprint("work stats\n");
81         cprint("        work = %A rps\n", (Filta){&cons.work, 1});
82         cprint("        rate = %A tBps\n", (Filta){&cons.rate, 1000});
83         cprint("        hits = %A iops\n", (Filta){&cons.bhit, 1});
84         cprint("        read = %A iops\n", (Filta){&cons.bread, 1});
85         cprint("        init = %A iops\n", (Filta){&cons.binit, 1});
86 /*      for(i = 0; i < MAXTAG; i++)
87                 cprint("        tag %G = %A iops\n", i, (Filta){&cons.tags[i], 1});
88 */
89 }
90
91 void
92 cmd_sync(void)
93 {
94         rlock(&mainlock);
95         syncall();
96         runlock(&mainlock);
97 }
98
99 void
100 cmd_halt(void)
101 {
102         wlock(&mainlock);
103         syncall();
104         superok(cur_fs->dev, superaddr(cur_fs->dev), 1);
105         print("kfs: file system halted\n");
106 }
107
108 void
109 cmd_start(void)
110 {
111         superok(cur_fs->dev, superaddr(cur_fs->dev), 0);
112         wunlock(&mainlock);
113         print("kfs: file system started\n");
114 }
115
116 void
117 cmd_help(void)
118 {
119         int i;
120
121         for(i=0; command[i].string; i++)
122                 cprint("        %s %s\n", command[i].string, command[i].args);
123         cprint("check options:\n"
124                 " r     read all blocks\n"
125                 " f     rebuild the free list\n"
126                 " t     fix all bad tags\n"
127                 " c     fix bad tags and zero the blocks\n"
128                 " d     delete all redundant references to blocks\n"
129                 " p     print directories as they are checked\n"
130                 " P     print all files as they are checked\n"
131                 " w     write all blocks that are read\n");
132 }
133
134 void
135 cmd_create(void)
136 {
137         int uid, gid, err;
138         long perm;
139         char oelem[NAMELEN];
140         char name[NAMELEN];
141
142         if(err = con_clone(FID1, FID2)){
143                 cprint("clone failed: %s\n", errstring[err]);
144                 return;
145         }
146         if(skipbl(1)){
147                 cprint("skipbl\n");
148                 return;
149         }
150         oelem[0] = 0;
151         while(nextelem()) {
152                 if(oelem[0])
153                         if(err = con_walk(FID2, oelem)){
154                                 cprint("walk failed: %s\n", errstring[err]);
155                                 return;
156                         }
157                 memmove(oelem, elem, NAMELEN);
158         }
159         if(skipbl(1))
160                 return;
161         uid = strtouid(cname(name));
162         if(uid == 0){
163                 cprint("unknown user %s\n", name);
164                 return;
165         }
166         gid = strtouid(cname(name));
167         if(gid == 0){
168                 cprint("unknown group %s\n", name);
169                 return;
170         }
171         perm = number(0777, 8);
172         skipbl(0);
173         for(; *cons.arg; cons.arg++){
174                 if(*cons.arg == 'l')
175                         perm |= PLOCK;
176                 else
177                 if(*cons.arg == 'a')
178                         perm |= PAPND;
179                 else
180                 if(*cons.arg == 'd')
181                         perm |= PDIR;
182                 else
183                         break;
184         }
185         err = con_create(FID2, elem, uid, gid, perm, 0);
186         if(err)
187                 cprint("can't create %s: %s\n", elem, errstring[err]);
188 }
189
190 void
191 cmd_clri(void)
192 {
193         if(con_clone(FID1, FID2))
194                 return;
195         if(skipbl(1))
196                 return;
197         while(nextelem())
198                 if(con_walk(FID2, elem)){
199                         cprint("can't walk %s\n", elem);
200                         return;
201                 }
202         con_clri(FID2);
203 }
204
205 void
206 cmd_rename(void)
207 {
208         ulong perm;
209         Dentry d;
210         char stat[DIRREC];
211         char oelem[NAMELEN], noelem[NAMELEN], nxelem[NAMELEN];
212         int err;
213
214         if(con_clone(FID1, FID2))
215                 return;
216         if(skipbl(1))
217                 return;
218         oelem[0] = 0;
219         while(nextelem()) {
220                 if(oelem[0])
221                         if(con_walk(FID2, oelem)){
222                                 cprint("file does not exits");
223                                 return;
224                         }
225                 memmove(oelem, elem, NAMELEN);
226         }
227         if(skipbl(1))
228                 return;
229         if(cons.arg[0]=='/'){
230                 if(con_clone(FID1, FID3))
231                         return;
232                 noelem[0] = 0;
233                 while(nextelem()){
234                         if(noelem[0])
235                                 if(con_walk(FID3, noelem)){
236                                         cprint("target path %s does not exist", noelem);
237                                         return;
238                                 }
239                         memmove(noelem, elem, NAMELEN);
240                 }
241                 if(!con_walk(FID3, elem)){
242                         cprint("target %s already exists\n", elem);
243                         return;
244                 }
245                 if(con_walk(FID2, oelem)){
246                         cprint("src %s does not exist\n", oelem);
247                         return;
248                 }
249                 /*
250                  * we know the target does not exist,
251                  * the source does exist.
252                  * to do the rename, create the target and then
253                  * copy the directory entry directly.  then remove the source.
254                  */
255                 if(err = con_stat(FID2, stat)){
256                         cprint("can't stat file: %s\n", errstring[err]);
257                         return;
258                 }
259                 convM2D9p1(stat, &d);
260                 perm = (d.mode&0777)|((d.mode&0x7000)<<17);
261                 if(err = con_create(FID3, elem, d.uid, d.gid, perm, (d.mode&DDIR)?OREAD:ORDWR)){
262                         cprint("can't create %s: %s\n", elem, errstring[err]);
263                         return;
264                 }
265                 if(err = con_swap(FID2, FID3)){
266                         cprint("can't swap data: %s\n", errstring[err]);
267                         return;
268                 }
269                 if(err = con_remove(FID2)){
270                         cprint("can't remove file: %s\n", errstring[err]);
271                         return;
272                 }               
273         }else{
274                 cname(nxelem);
275                 if(strchr(nxelem, '/')){
276                         cprint("bad rename target: not full path, but contains slashes\n");
277                         return;
278                 }
279                 if(!con_walk(FID2, nxelem))
280                         cprint("file %s already exists\n", nxelem);
281                 else if(con_walk(FID2, oelem))
282                         cprint("file does not already exist\n");
283                 else if(err = con_stat(FID2, stat))
284                         cprint("can't stat file: %s\n", errstring[err]);
285                 else{
286                         convM2D9p1(stat, &d);
287                         strncpy(d.name, nxelem, NAMELEN);
288                         convD2M9p1(&d, stat);
289                         if(err = con_wstat(FID2, stat))
290                                 cprint("can't move file: %s\n", errstring[err]);
291                 }
292         }       
293 }
294
295 void
296 cmd_remove(void)
297 {
298         if(con_clone(FID1, FID2))
299                 return;
300         if(skipbl(1))
301                 return;
302         while(nextelem())
303                 if(con_walk(FID2, elem)){
304                         cprint("can't walk %s\n", elem);
305                         return;
306                 }
307         con_remove(FID2);
308 }
309
310 void
311 cmd_cfs(void)
312 {
313         Filsys *fs;
314
315         if(*cons.arg != ' ') {
316                 fs = &filesys[0];               /* default */
317         } else {
318                 if(skipbl(1)){
319                         cprint("skipbl\n");
320                         return;
321                 }
322                 if(!nextelem())
323                         fs = &filesys[0];       /* default */
324                 else
325                         fs = fsstr(elem);
326         }
327         if(fs == 0) {
328                 cprint("unknown file system %s\n", elem);
329                 return;
330         }
331         if(con_attach(FID1, "adm", fs->name))
332                 panic("FID1 attach to root");
333         cur_fs = fs;
334 }
335
336 /*
337  * find out the length of a file
338  * given the mesg version of a stat buffer
339  * we call this because convM2D is different
340  * for the file system than in the os
341  */
342 static uvlong
343 statlen(char *ap)
344 {
345         uchar *p;
346         ulong ll, hl;
347
348         p = (uchar*)ap;
349         p += 3*28+5*4;
350         ll = p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
351         hl = p[4] | (p[5]<<8) | (p[6]<<16) | (p[7]<<24);
352         return ll | ((uvlong) hl << 32);
353 }
354
355 int
356 adduser(char *user, int isgroup)
357 {
358         char stat[DIRREC];
359         char msg[100];
360         Uid *u;
361         int i, c, nu;
362
363         /*
364          * check uniq of name
365          * and get next uid
366          */
367         cmd_exec("cfs");
368         cmd_exec("user");
369         if(isgroup)
370                 nu = 9000;
371         else
372                 nu = 0;
373         for(i=0, u=uid; i<conf.nuid; i++,u++) {
374                 c = u->uid;
375                 if(c == 0)
376                         break;
377                 if(strcmp(uidspace+u->offset, user) == 0)
378                         return 1;
379                 if(c >= 9000 && !isgroup)
380                         continue;
381                 if(c > nu)
382                         nu = c;
383         }
384         nu++;
385         if(isgroup){
386                 if(nu >= 0x10000) {
387                         cprint("out of group ids\n");
388                         return 0;
389                 }
390         } else {
391                 if(nu >= 9000) {
392                         cprint("out of user ids\n");
393                         return 0;
394                 }
395         }
396
397         /*
398          * write onto adm/users
399          */
400         if(con_clone(FID1, FID2)
401         || con_path(FID2, "/adm/users")
402         || con_open(FID2, 1)) {
403                 cprint("can't open /adm/users\n");
404                 return 0;
405         }
406
407         sprint(msg, "%d:%s:%s:\n", nu, user, user);
408         cprint("add user %s", msg);
409         c = strlen(msg);
410         i = con_stat(FID2, stat);
411         if(i){
412                 cprint("can't stat /adm/users: %s\n", errstring[i]);
413                 return 0;
414         }
415         i = con_write(FID2, msg, statlen(stat), c);
416         if(i != c){
417                 cprint("short write on /adm/users: %d %d\n", c, i);
418                 return 0;
419         }
420         return 1;
421 }
422
423 void
424 cmd_newuser(void)
425 {
426         char user[NAMELEN], param[NAMELEN], msg[100];
427         int i, c;
428
429         /*
430          * get uid
431          */
432         cname(user);
433         cname(param);
434         for(i=0; i<NAMELEN; i++) {
435                 c = user[i];
436                 if(c == 0)
437                         break;
438                 if(c >= '0' && c <= '9'
439                 || c >= 'a' && c <= 'z'
440                 || c >= 'A' && c <= 'Z')
441                         continue;
442                 cprint("bad character in name: 0x%x\n", c);
443                 return;
444         }
445         if(i < 2) {
446                 cprint("name too short: %s\n", user);
447                 return;
448         }
449         if(i >= NAMELEN) {
450                 cprint("name too long: %s\n", user);
451                 return;
452         }
453
454         switch(param[0]){
455         case 0:
456                 if(!adduser(user, 0))
457                         return;
458                 cmd_exec("user");
459                 break;
460         case ':':
461                 adduser(user, 1);
462                 cmd_exec("user");
463                 return;
464         case '#':
465                 adduser(user, 0);
466                 cmd_exec("user");
467                 return;
468         }
469
470         /*
471          * create directories
472          */
473         cmd_exec("user");
474         sprint(msg, "create /usr/%s %s %s 775 d", user, user, user);
475         cmd_exec(msg);
476         sprint(msg, "create /usr/%s/tmp %s %s 775 d", user, user, user);
477         cmd_exec(msg);
478         sprint(msg, "create /usr/%s/lib %s %s 775 d", user, user, user);
479         cmd_exec(msg);
480         sprint(msg, "create /usr/%s/bin %s %s 775 d", user, user, user);
481         cmd_exec(msg);
482         sprint(msg, "create /usr/%s/bin/rc %s %s 775 d", user, user, user);
483         cmd_exec(msg);
484         sprint(msg, "create /usr/%s/bin/mips %s %s 775 d", user, user, user);
485         cmd_exec(msg);
486         sprint(msg, "create /usr/%s/bin/386 %s %s 775 d", user, user, user);
487         cmd_exec(msg);
488         sprint(msg, "create /usr/%s/bin/power %s %s 775 d", user, user, user);
489         cmd_exec(msg);
490         sprint(msg, "create /usr/%s/bin/alpha %s %s 775 d", user, user, user);
491         cmd_exec(msg);
492 }
493
494 void
495 cmd_checkuser(void)
496 {
497         uchar buf[DIRREC], *p;
498         static char utime[4];
499
500         if(con_clone(FID1, FID2)
501         || con_path(FID2, "/adm/users")
502         || con_open(FID2, 0)
503         || con_stat(FID2, (char*)buf))
504                 return;
505         p = buf + 3*NAMELEN + 4*4;
506         if(memcmp(utime, p, 4) == 0)
507                 return;
508         memmove(utime, p, 4);
509         cmd_user();
510 }
511
512 void
513 cmd_allow(void)
514 {
515         wstatallow = 1;
516 }
517
518 void
519 cmd_disallow(void)
520 {
521         wstatallow = 0;
522 }
523
524 void
525 cmd_chat(void)
526 {
527         chat = 1 - chat;
528 }
529
530 void
531 cmd_atime(void)
532 {
533         noatime = !noatime;
534         if(noatime)
535                 cprint("atimes will not be updated\n");
536         else
537                 cprint("atimes will be updated\n");
538 }
539
540 void
541 cmd_noneattach(void)
542 {
543         allownone = !allownone;
544         if(allownone) 
545                 cprint("none can attach to new connections\n");
546         else
547                 cprint("none can only attach on authenticated connections\n");
548 }
549
550 void
551 cmd_listen(void)
552 {
553         char addr[NAMELEN];
554
555         if(skipbl(0))
556                 strcpy(addr, "tcp!*!564");      /* 9fs */
557         else
558                 cname(addr);
559
560         if(netserve(addr))
561                 cprint("announce %s failed\n", addr);
562         else
563                 cprint("announce %s\n", addr);
564 }
565
566 void
567 cmd_nowritegroup(void)
568 {
569         writegroup = 0;
570 }
571
572 Command command[] =
573 {
574         "allow",        cmd_allow,      "",
575         "allowoff",     cmd_disallow,   "",
576         "atime",                cmd_atime,      "",
577         "cfs",          cmd_cfs,        "[filesys]",
578         "chat",         cmd_chat,       "",
579         "check",        cmd_check,      "[cdfpPqrtw]",
580         "clri",         cmd_clri,       "filename",
581         "create",       cmd_create,     "filename user group perm [ald]",
582         "disallow",     cmd_disallow,   "",
583         "halt",         cmd_halt,       "",
584         "help",         cmd_help,       "",
585         "listen",               cmd_listen,     "[address]",
586         "newuser",      cmd_newuser,    "username",
587         "noneattach",   cmd_noneattach, "",
588         "nowritegroup", cmd_nowritegroup,       "",
589         "remove",       cmd_remove,     "filename",
590         "rename",       cmd_rename,     "file newname",
591         "start",        cmd_start, "",
592         "stats",        cmd_stats,      "[fw]",
593         "sync",         cmd_sync,       "",
594         "user",         cmd_user,       "",
595         0
596 };
597
598 int
599 skipbl(int err)
600 {
601         if(*cons.arg != ' ') {
602                 if(err)
603                         cprint("syntax error\n");
604                 return 1;
605         }
606         while(*cons.arg == ' ')
607                 cons.arg++;
608         return 0;
609 }
610
611 char*
612 _cname(char *name)
613 {
614         int i, c;
615
616         memset(name, 0, NAMELEN);
617         for(i=0;; i++) {
618                 c = *cons.arg;
619                 switch(c) {
620                 case ' ':
621                 case '\t':
622                 case '\n':
623                 case '\0':
624                         return name;
625                 }
626                 if(i < NAMELEN-1)
627                         name[i] = c;
628                 cons.arg++;
629         }
630 }
631
632 char*
633 cname(char *name)
634 {
635         skipbl(0);
636         return _cname(name);
637 }
638
639 int
640 nextelem(void)
641 {
642         char *e;
643         int i, c;
644
645         e = elem;
646         while(*cons.arg == '/')
647                 cons.arg++;
648         c = *cons.arg;
649         if(c == 0 || c == ' ')
650                 return 0;
651         for(i = 0; c = *cons.arg; i++) {
652                 if(c == ' ' || c == '/')
653                         break;
654                 if(i == NAMELEN) {
655                         cprint("path name component too long\n");
656                         return 0;
657                 }
658                 *e++ = c;
659                 cons.arg++;
660         }
661         *e = 0;
662         return 1;
663 }
664
665 long
666 number(int d, int base)
667 {
668         int c, sign, any;
669         long n;
670
671         sign = 0;
672         any = 0;
673         n = 0;
674
675         c = *cons.arg;
676         while(c == ' ') {
677                 cons.arg++;
678                 c = *cons.arg;
679         }
680         if(c == '-') {
681                 sign = 1;
682                 cons.arg++;
683                 c = *cons.arg;
684         }
685         while((c >= '0' && c <= '9') ||
686               (base == 16 && c >= 'a' && c <= 'f') ||
687               (base == 16 && c >= 'A' && c <= 'F')) {
688                 n *= base;
689                 if(c >= 'a' && c <= 'f')
690                         n += c - 'a' + 10;
691                 else
692                 if(c >= 'A' && c <= 'F')
693                         n += c - 'A' + 10;
694                 else
695                         n += c - '0';
696                 cons.arg++;
697                 c = *cons.arg;
698                 any = 1;
699         }
700         if(!any)
701                 return d;
702         if(sign)
703                 n = -n;
704         return n;
705 }