9fans.net/go@v0.0.7/cmd/sam/shell.go (about) 1 // #include "sam.h" 2 // #include "parse.h" 3 4 package main 5 6 import ( 7 "io" 8 "os" 9 "os/exec" 10 ) 11 12 /* extern var mainloop jmp_buf */ 13 14 var errfile string 15 var plan9cmd String /* null terminated */ 16 var plan9buf Buffer 17 18 func setname(ecmd *exec.Cmd, f *File) { 19 var buf string 20 if f != nil { 21 buf = string(f.name.s) 22 } 23 // % to be like acme 24 ecmd.Env = append(os.Environ(), "samfile="+buf, "%="+buf) 25 } 26 27 func plan9(f *File, type_ rune, s *String, nest bool) int { 28 if len(s.s) == 0 && len(plan9cmd.s) == 0 { 29 error_(Enocmd) 30 } else if len(s.s) != 0 { 31 Strduplstr(&plan9cmd, s) 32 } 33 /* 34 var pipe1 [2]int 35 if type_ != '!' && pipe(pipe1) == -1 { 36 error_(Epipe) 37 } 38 */ 39 if type_ == '|' { 40 snarf(f, addr.r.p1, addr.r.p2, &plan9buf, 1) 41 } 42 43 ecmd := exec.Command(SHPATH, "-c", Strtoc(&plan9cmd)) 44 setname(ecmd, f) 45 46 ecmd.Stdin = os.Stdin 47 ecmd.Stdout = os.Stdout 48 ecmd.Stderr = os.Stderr 49 50 if downloaded { 51 errfile = samerr() 52 os.Remove(errfile) 53 ecmd.Stderr = nil 54 ecmd.Stdout = nil 55 ecmd.Stdin = nil 56 if fd, err := os.Create(errfile); err == nil { 57 ecmd.Stderr = fd 58 if type_ == '>' || type_ == '!' { 59 ecmd.Stdout = fd 60 } 61 } 62 } 63 64 var stdout IOFile 65 if type_ == '<' || type_ == '|' { 66 ecmd.Stdout = nil 67 p, err := ecmd.StdoutPipe() 68 if err != nil { 69 error_(Epipe) 70 } 71 stdout = p.(IOFile) 72 } 73 74 var stdin IOFile 75 if type_ == '>' || type_ == '|' { 76 ecmd.Stdin = nil 77 p, err := ecmd.StdinPipe() 78 if err != nil { 79 error_(Epipe) 80 } 81 stdin = p.(IOFile) 82 } 83 84 if type_ == '|' { 85 go func() { 86 defer func() { 87 stdin.Close() 88 e := recover() 89 if e == nil { 90 return 91 } 92 if e == &mainloop { 93 os.Exit(1) 94 } 95 panic(e) 96 }() 97 98 var m int 99 for l := 0; l < plan9buf.nc; l += m { 100 m = plan9buf.nc - l 101 if m > BLOCKSIZE-1 { 102 m = BLOCKSIZE - 1 103 } 104 bufread(&plan9buf, l, genbuf2[:m]) 105 c := []byte(string(genbuf2[:m])) 106 Write(stdin, c) 107 // free(c) 108 } 109 }() 110 } 111 112 xerr := ecmd.Start() 113 114 switch type_ { 115 case '<', '|': 116 if downloaded && addr.r.p1 != addr.r.p2 { 117 outTl(Hsnarflen, addr.r.p2-addr.r.p1) 118 } 119 snarf(f, addr.r.p1, addr.r.p2, &snarfbuf, 0) 120 logdelete(f, addr.r.p1, addr.r.p2) 121 iofile = stdout 122 f.tdot.p1 = -1 123 var nulls bool 124 f.ndot.r.p2 = addr.r.p2 + readio(f, &nulls, false, false) 125 f.ndot.r.p1 = addr.r.p2 126 closeio(-1) 127 128 case '>': 129 iofile = stdin 130 bpipeok = true 131 writeio(f) 132 bpipeok = false 133 closeio(-1) 134 } 135 136 if xerr == nil { 137 xerr = ecmd.Wait() 138 } 139 if type_ == '|' || type_ == '<' { 140 if xerr != nil { 141 warn(Wbadstatus) 142 } 143 } 144 if downloaded { 145 checkerrs() 146 } 147 if !nest { 148 dprint("!\n") 149 } 150 if xerr == nil { 151 return 0 152 } 153 return -1 154 } 155 156 func checkerrs() { 157 if info, err := os.Stat(errfile); err == nil && info.Size() > 0 { 158 f, err := os.Open(errfile) 159 if err == nil { 160 buf := make([]byte, BLOCKSIZE-10) 161 n, err := io.ReadFull(f, buf) 162 if err == nil && n > 0 { 163 nl := 0 164 p := 0 165 for ; nl < 25 && p < len(buf); p++ { 166 if buf[p] == '\n' { 167 nl++ 168 } 169 } 170 buf = buf[:p] 171 dprint("%s", buf) 172 if int64(len(buf)) < info.Size()-1 { // TODO(rsc): Why -1 173 dprint("(sam: more in %s)\n", errfile) 174 } 175 } 176 f.Close() 177 } 178 } else { 179 os.Remove(errfile) 180 } 181 }