1implement Rm; 2 3include "sys.m"; 4 sys: Sys; 5include "draw.m"; 6 7include "readdir.m"; 8 readdir: Readdir; 9 10include "arg.m"; 11 12Rm: module 13{ 14 init: fn(ctxt: ref Draw->Context, argv: list of string); 15}; 16 17stderr: ref Sys->FD; 18quiet := 0; 19force := 0; 20errcount := 0; 21 22usage() 23{ 24 sys->fprint(stderr, "Usage: rm [-fr] file ...\n"); 25 raise "fail: usage"; 26} 27allwrite := Sys->nulldir; 28 29init(nil: ref Draw->Context, args: list of string) 30{ 31 sys = load Sys Sys->PATH; 32 stderr = sys->fildes(2); 33 allwrite.mode = 8r777 | Sys->DMDIR; 34 35 arg := load Arg Arg->PATH; 36 if(arg == nil){ 37 sys->fprint(stderr, "rm: can't load %s: %r\n", Arg->PATH); 38 raise "fail:load"; 39 } 40 arg->init(args); 41 while((o := arg->opt()) != 0) 42 case o { 43 'r' => 44 readdir = load Readdir Readdir->PATH; 45 if(readdir == nil) 46 sys->fprint(stderr, "rm: can't load Readdir: %r\n"); # -r is regarded as optional 47 'f' => 48 quiet = 1; 49 'F' => 50 force = 1; 51 * => 52 usage(); 53 } 54 args = arg->argv(); 55 arg = nil; 56 sys->pctl(Sys->FORKNS, nil); 57 for(; args != nil; args = tl args) { 58 name := hd args; 59 if(sys->remove(name) < 0) { 60 e := sys->sprint("%r"); 61 (ok, d) := sys->stat(name); 62 if(readdir != nil && ok >= 0 && (d.mode & Sys->DMDIR) != 0) 63 rmdir(name); 64 else 65 err(name, e); 66 } 67 } 68 if(errcount > 0) 69 raise "fail:errors"; 70} 71 72rmdir(name: string) 73{ 74 if(force) 75 sys->wstat(name, allwrite); 76 (d, n) := readdir->init(name, Readdir->NONE|Readdir->COMPACT); 77 for(i := 0; i < n; i++){ 78 path := name+"/"+d[i].name; 79 if(d[i].mode & Sys->DMDIR) 80 rmdir(path); 81 else 82 remove(path); 83 } 84 remove(name); 85} 86 87remove(name: string) 88{ 89 if(sys->remove(name) < 0) 90 err(name, sys->sprint("%r")); 91} 92 93err(name, e: string) 94{ 95 if(!quiet) { 96 sys->fprint(stderr, "rm: %s: %s\n", name, e); 97 errcount++; 98 } 99} 100