1implement Chmod; 2 3include "sys.m"; 4include "draw.m"; 5include "string.m"; 6 7Chmod: module 8{ 9 init: fn(ctxt: ref Draw->Context, argv: list of string); 10}; 11 12sys: Sys; 13stderr: ref Sys->FD; 14 15str: String; 16 17User: con 8r700; 18Group: con 8r070; 19Other: con 8r007; 20All: con User | Group | Other; 21 22Read: con 8r444; 23Write: con 8r222; 24Exec: con 8r111; 25 26usage() 27{ 28 sys->fprint(stderr, "usage: chmod [8r]777 file ... or chmod [augo][+-=][rwxal] file ...\n"); 29 raise "fail:usage"; 30} 31 32init(nil: ref Draw->Context, argv: list of string) 33{ 34 sys = load Sys Sys->PATH; 35 stderr = sys->fildes(2); 36 37 str = load String String->PATH; 38 if(str == nil){ 39 sys->fprint(stderr, "chmod: cannot load %s: %r\n", String->PATH); 40 raise "fail:bad module"; 41 } 42 43 if(len argv < 3) 44 usage(); 45 argv = tl argv; 46 m := hd argv; 47 argv = tl argv; 48 49 mask := All; 50 if (str->prefix("8r", m)) 51 m = m[2:]; 52 (mode, s) := str->toint(m, 8); 53 if(s != "" || m == ""){ 54 ok := 0; 55 (ok, mask, mode) = parsemode(m); 56 if(!ok){ 57 sys->fprint(stderr, "chmod: bad mode '%s'\n", m); 58 usage(); 59 } 60 } 61 ndir := sys->nulldir; 62 for(; argv != nil; argv = tl argv){ 63 f := hd argv; 64 (ok, dir) := sys->stat(f); 65 if(ok < 0){ 66 sys->fprint(stderr, "chmod: cannot stat %s: %r\n", f); 67 continue; 68 } 69 ndir.mode = (dir.mode & ~mask) | (mode & mask); 70 if(sys->wstat(f, ndir) < 0) 71 sys->fprint(stderr, "chmod: cannot wstat %s: %r\n", f); 72 } 73} 74 75parsemode(spec: string): (int, int, int) 76{ 77 mask := Sys->DMAPPEND | Sys->DMEXCL | Sys->DMTMP; 78loop: for(i := 0; i < len spec; i++){ 79 case spec[i] { 80 'u' => 81 mask |= User; 82 'g' => 83 mask |= Group; 84 'o' => 85 mask |= Other; 86 'a' => 87 mask |= All; 88 * => 89 break loop; 90 } 91 } 92 if(i == len spec) 93 return (0, 0, 0); 94 if(i == 0) 95 mask |= All; 96 97 op := spec[i++]; 98 if(op != '+' && op != '-' && op != '=') 99 return (0, 0, 0); 100 101 mode := 0; 102 for(; i < len spec; i++){ 103 case spec[i]{ 104 'r' => 105 mode |= Read; 106 'w' => 107 mode |= Write; 108 'x' => 109 mode |= Exec; 110 'a' => 111 mode |= Sys->DMAPPEND; 112 'l' => 113 mode |= Sys->DMEXCL; 114 't' => 115 mode |= Sys->DMTMP; 116 * => 117 return (0, 0, 0); 118 } 119 } 120 if(op == '+' || op == '-') 121 mask &= mode; 122 if(op == '-') 123 mode = ~mode; 124 return (1, mask, mode); 125} 126