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  }