blob: 5c5bc4c62284aca8e5d3b3858311fcaa5f451a1c [file] [log] [blame]
Cosmos Nicolaou62613842014-08-25 21:57:37 -07001package modules
2
3import (
Cosmos Nicolaou62613842014-08-25 21:57:37 -07004 "fmt"
5 "io"
6 "os"
7 "sync"
James Ring9d9489d2015-01-27 15:48:07 -08008 "time"
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -07009
Jiri Simsa764efb72014-12-25 20:57:03 -080010 "v.io/core/veyron2/vlog"
Cosmos Nicolaou62613842014-08-25 21:57:37 -070011)
12
13type pipe struct {
14 r, w *os.File
15}
16type functionHandle struct {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070017 mu sync.Mutex
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070018 name string
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070019 main Main
20 stdin, stdout pipe
21 stderr *os.File
22 err error
23 sh *Shell
24 wg sync.WaitGroup
Cosmos Nicolaou62613842014-08-25 21:57:37 -070025}
26
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070027func newFunctionHandle(name string, main Main) command {
28 return &functionHandle{name: name, main: main}
Cosmos Nicolaou62613842014-08-25 21:57:37 -070029}
30
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070031func (fh *functionHandle) Stdout() io.Reader {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070032 fh.mu.Lock()
33 defer fh.mu.Unlock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070034 return fh.stdout.r
Cosmos Nicolaou62613842014-08-25 21:57:37 -070035}
36
37func (fh *functionHandle) Stderr() io.Reader {
38 fh.mu.Lock()
39 defer fh.mu.Unlock()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070040 return os.NewFile(fh.stderr.Fd(), "stderr")
Cosmos Nicolaou62613842014-08-25 21:57:37 -070041}
42
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070043func (fh *functionHandle) Stdin() io.Writer {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070044 fh.mu.Lock()
45 defer fh.mu.Unlock()
46 return fh.stdin.w
47}
48
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070049func (fh *functionHandle) CloseStdin() {
50 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070051 fh.stdin.w.Close()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070052 fh.mu.Unlock()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070053}
54
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070055func (fh *functionHandle) envelope(sh *Shell, env []string, args ...string) ([]string, []string) {
56 return args, env
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070057}
58
Ryan Browna08a2212015-01-15 15:40:10 -080059func (fh *functionHandle) start(sh *Shell, agent *os.File, env []string, args ...string) (Handle, error) {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070060 fh.mu.Lock()
61 defer fh.mu.Unlock()
Ryan Browna08a2212015-01-15 15:40:10 -080062 // In process commands need their own reference to a principal.
63 if agent != nil {
64 agent.Close()
65 }
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070066 fh.sh = sh
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070067 for _, p := range []*pipe{&fh.stdin, &fh.stdout} {
Cosmos Nicolaou62613842014-08-25 21:57:37 -070068 var err error
69 if p.r, p.w, err = os.Pipe(); err != nil {
70 return nil, err
71 }
72 }
Bogdan Caprita490a4512014-11-20 21:12:19 -080073 stderr, err := newLogfile("stderr", args[0])
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070074 if err != nil {
75 return nil, err
76 }
77 fh.stderr = stderr
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070078 fh.wg.Add(1)
79
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070080 go func(env []string) {
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070081 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070082 stdin := fh.stdin.r
83 stdout := fh.stdout.w
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070084 stderr := fh.stderr
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070085 main := fh.main
86 fh.mu.Unlock()
87
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070088 cenv := envSliceToMap(env)
89 vlog.VI(1).Infof("Start: %q args: %v", fh.name, args)
90 vlog.VI(2).Infof("Start: %q env: %v", fh.name, cenv)
91 err := main(stdin, stdout, stderr, cenv, args...)
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -070092 if err != nil {
93 fmt.Fprintf(stderr, "%s\n", err)
94 }
95
96 fh.mu.Lock()
97 fh.stdin.r.Close()
98 fh.stdout.w.Close()
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070099 fh.err = err
100 fh.mu.Unlock()
101 fh.wg.Done()
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700102 }(env)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700103 return fh, nil
104}
105
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700106func (eh *functionHandle) Pid() int {
107 return os.Getpid()
108}
109
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700110func (fh *functionHandle) Shutdown(stdout_w, stderr_w io.Writer) error {
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700111 fh.mu.Lock()
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700112 vlog.VI(1).Infof("Shutdown: %q", fh.name)
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700113 fh.stdin.w.Close()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700114 stdout := fh.stdout.r
115 stderr := fh.stderr
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700116 fh.mu.Unlock()
117
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700118 // Read stdout until EOF to ensure that we read all of it.
Bogdan Caprita490a4512014-11-20 21:12:19 -0800119 if stdout_w != nil {
120 io.Copy(stdout_w, stdout)
121 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700122 fh.wg.Wait()
123
124 fh.mu.Lock()
125 funcErr := fh.err
126 fh.mu.Unlock()
127
128 // Safe to close stderr now.
Robin Thellend1c8a8282014-12-09 10:38:36 -0800129 stderrName := stderr.Name()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700130 stderr.Close()
Robin Thellend1c8a8282014-12-09 10:38:36 -0800131 defer os.Remove(stderrName)
Bogdan Caprita490a4512014-11-20 21:12:19 -0800132 if stderr_w != nil {
Robin Thellend1c8a8282014-12-09 10:38:36 -0800133 if stderr, err := os.Open(stderrName); err == nil {
Bogdan Caprita490a4512014-11-20 21:12:19 -0800134 io.Copy(stderr_w, stderr)
135 stderr.Close()
136 } else {
Robin Thellend1c8a8282014-12-09 10:38:36 -0800137 fmt.Fprintf(os.Stderr, "failed to open %q: %s\n", stderrName, err)
Bogdan Caprita490a4512014-11-20 21:12:19 -0800138 }
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700139 }
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700140
141 fh.mu.Lock()
Cosmos Nicolaou9ca249d2014-09-18 15:07:12 -0700142 fh.stdout.r.Close()
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700143 fh.sh.Forget(fh)
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700144 fh.mu.Unlock()
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700145 return funcErr
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700146}
James Ring9d9489d2015-01-27 15:48:07 -0800147
148func (fh *functionHandle) WaitForReady(time.Duration) error {
149 return nil
150}