OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [os/] [exec/] [exec.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4
 
5
// Package exec runs external commands. It wraps os.StartProcess to make it
6
// easier to remap stdin and stdout, connect I/O with pipes, and do other
7
// adjustments.
8
package exec
9
 
10
import (
11
        "bytes"
12
        "errors"
13
        "io"
14
        "os"
15
        "strconv"
16
        "syscall"
17
)
18
 
19
// Error records the name of a binary that failed to be be executed
20
// and the reason it failed.
21
type Error struct {
22
        Name string
23
        Err  error
24
}
25
 
26
func (e *Error) Error() string {
27
        return "exec: " + strconv.Quote(e.Name) + ": " + e.Err.Error()
28
}
29
 
30
// Cmd represents an external command being prepared or run.
31
type Cmd struct {
32
        // Path is the path of the command to run.
33
        //
34
        // This is the only field that must be set to a non-zero
35
        // value.
36
        Path string
37
 
38
        // Args holds command line arguments, including the command as Args[0].
39
        // If the Args field is empty or nil, Run uses {Path}.
40
        //
41
        // In typical use, both Path and Args are set by calling Command.
42
        Args []string
43
 
44
        // Env specifies the environment of the process.
45
        // If Env is nil, Run uses the current process's environment.
46
        Env []string
47
 
48
        // Dir specifies the working directory of the command.
49
        // If Dir is the empty string, Run runs the command in the
50
        // calling process's current directory.
51
        Dir string
52
 
53
        // Stdin specifies the process's standard input. If Stdin is
54
        // nil, the process reads from the null device (os.DevNull).
55
        Stdin io.Reader
56
 
57
        // Stdout and Stderr specify the process's standard output and error.
58
        //
59
        // If either is nil, Run connects the corresponding file descriptor
60
        // to the null device (os.DevNull).
61
        //
62
        // If Stdout and Stderr are are the same writer, at most one
63
        // goroutine at a time will call Write.
64
        Stdout io.Writer
65
        Stderr io.Writer
66
 
67
        // ExtraFiles specifies additional open files to be inherited by the
68
        // new process. It does not include standard input, standard output, or
69
        // standard error. If non-nil, entry i becomes file descriptor 3+i.
70
        //
71
        // BUG: on OS X 10.6, child processes may sometimes inherit extra fds.
72
        // http://golang.org/issue/2603
73
        ExtraFiles []*os.File
74
 
75
        // SysProcAttr holds optional, operating system-specific attributes.
76
        // Run passes it to os.StartProcess as the os.ProcAttr's Sys field.
77
        SysProcAttr *syscall.SysProcAttr
78
 
79
        // Process is the underlying process, once started.
80
        Process *os.Process
81
 
82
        err             error // last error (from LookPath, stdin, stdout, stderr)
83
        finished        bool  // when Wait was called
84
        childFiles      []*os.File
85
        closeAfterStart []io.Closer
86
        closeAfterWait  []io.Closer
87
        goroutine       []func() error
88
        errch           chan error // one send per goroutine
89
}
90
 
91
// Command returns the Cmd struct to execute the named program with
92
// the given arguments.
93
//
94
// It sets Path and Args in the returned structure and zeroes the
95
// other fields.
96
//
97
// If name contains no path separators, Command uses LookPath to
98
// resolve the path to a complete name if possible. Otherwise it uses
99
// name directly.
100
//
101
// The returned Cmd's Args field is constructed from the command name
102
// followed by the elements of arg, so arg should not include the
103
// command name itself. For example, Command("echo", "hello")
104
func Command(name string, arg ...string) *Cmd {
105
        aname, err := LookPath(name)
106
        if err != nil {
107
                aname = name
108
        }
109
        return &Cmd{
110
                Path: aname,
111
                Args: append([]string{name}, arg...),
112
                err:  err,
113
        }
114
}
115
 
116
// interfaceEqual protects against panics from doing equality tests on
117
// two interfaces with non-comparable underlying types
118
func interfaceEqual(a, b interface{}) bool {
119
        defer func() {
120
                recover()
121
        }()
122
        return a == b
123
}
124
 
125
func (c *Cmd) envv() []string {
126
        if c.Env != nil {
127
                return c.Env
128
        }
129
        return os.Environ()
130
}
131
 
132
func (c *Cmd) argv() []string {
133
        if len(c.Args) > 0 {
134
                return c.Args
135
        }
136
        return []string{c.Path}
137
}
138
 
139
func (c *Cmd) stdin() (f *os.File, err error) {
140
        if c.Stdin == nil {
141
                f, err = os.Open(os.DevNull)
142
                c.closeAfterStart = append(c.closeAfterStart, f)
143
                return
144
        }
145
 
146
        if f, ok := c.Stdin.(*os.File); ok {
147
                return f, nil
148
        }
149
 
150
        pr, pw, err := os.Pipe()
151
        if err != nil {
152
                return
153
        }
154
 
155
        c.closeAfterStart = append(c.closeAfterStart, pr)
156
        c.closeAfterWait = append(c.closeAfterWait, pw)
157
        c.goroutine = append(c.goroutine, func() error {
158
                _, err := io.Copy(pw, c.Stdin)
159
                if err1 := pw.Close(); err == nil {
160
                        err = err1
161
                }
162
                return err
163
        })
164
        return pr, nil
165
}
166
 
167
func (c *Cmd) stdout() (f *os.File, err error) {
168
        return c.writerDescriptor(c.Stdout)
169
}
170
 
171
func (c *Cmd) stderr() (f *os.File, err error) {
172
        if c.Stderr != nil && interfaceEqual(c.Stderr, c.Stdout) {
173
                return c.childFiles[1], nil
174
        }
175
        return c.writerDescriptor(c.Stderr)
176
}
177
 
178
func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
179
        if w == nil {
180
                f, err = os.OpenFile(os.DevNull, os.O_WRONLY, 0)
181
                c.closeAfterStart = append(c.closeAfterStart, f)
182
                return
183
        }
184
 
185
        if f, ok := w.(*os.File); ok {
186
                return f, nil
187
        }
188
 
189
        pr, pw, err := os.Pipe()
190
        if err != nil {
191
                return
192
        }
193
 
194
        c.closeAfterStart = append(c.closeAfterStart, pw)
195
        c.closeAfterWait = append(c.closeAfterWait, pr)
196
        c.goroutine = append(c.goroutine, func() error {
197
                _, err := io.Copy(w, pr)
198
                return err
199
        })
200
        return pw, nil
201
}
202
 
203
// Run starts the specified command and waits for it to complete.
204
//
205
// The returned error is nil if the command runs, has no problems
206
// copying stdin, stdout, and stderr, and exits with a zero exit
207
// status.
208
//
209
// If the command fails to run or doesn't complete successfully, the
210
// error is of type *ExitError. Other error types may be
211
// returned for I/O problems.
212
func (c *Cmd) Run() error {
213
        if err := c.Start(); err != nil {
214
                return err
215
        }
216
        return c.Wait()
217
}
218
 
219
// Start starts the specified command but does not wait for it to complete.
220
func (c *Cmd) Start() error {
221
        if c.err != nil {
222
                return c.err
223
        }
224
        if c.Process != nil {
225
                return errors.New("exec: already started")
226
        }
227
 
228
        type F func(*Cmd) (*os.File, error)
229
        for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
230
                fd, err := setupFd(c)
231
                if err != nil {
232
                        return err
233
                }
234
                c.childFiles = append(c.childFiles, fd)
235
        }
236
        c.childFiles = append(c.childFiles, c.ExtraFiles...)
237
 
238
        var err error
239
        c.Process, err = os.StartProcess(c.Path, c.argv(), &os.ProcAttr{
240
                Dir:   c.Dir,
241
                Files: c.childFiles,
242
                Env:   c.envv(),
243
                Sys:   c.SysProcAttr,
244
        })
245
        if err != nil {
246
                return err
247
        }
248
 
249
        for _, fd := range c.closeAfterStart {
250
                fd.Close()
251
        }
252
 
253
        c.errch = make(chan error, len(c.goroutine))
254
        for _, fn := range c.goroutine {
255
                go func(fn func() error) {
256
                        c.errch <- fn()
257
                }(fn)
258
        }
259
 
260
        return nil
261
}
262
 
263
// An ExitError reports an unsuccessful exit by a command.
264
type ExitError struct {
265
        *os.Waitmsg
266
}
267
 
268
func (e *ExitError) Error() string {
269
        return e.Waitmsg.String()
270
}
271
 
272
// Wait waits for the command to exit.
273
// It must have been started by Start.
274
//
275
// The returned error is nil if the command runs, has no problems
276
// copying stdin, stdout, and stderr, and exits with a zero exit
277
// status.
278
//
279
// If the command fails to run or doesn't complete successfully, the
280
// error is of type *ExitError. Other error types may be
281
// returned for I/O problems.
282
func (c *Cmd) Wait() error {
283
        if c.Process == nil {
284
                return errors.New("exec: not started")
285
        }
286
        if c.finished {
287
                return errors.New("exec: Wait was already called")
288
        }
289
        c.finished = true
290
        msg, err := c.Process.Wait(0)
291
 
292
        var copyError error
293
        for _ = range c.goroutine {
294
                if err := <-c.errch; err != nil && copyError == nil {
295
                        copyError = err
296
                }
297
        }
298
 
299
        for _, fd := range c.closeAfterWait {
300
                fd.Close()
301
        }
302
 
303
        if err != nil {
304
                return err
305
        } else if !msg.Exited() || msg.ExitStatus() != 0 {
306
                return &ExitError{msg}
307
        }
308
 
309
        return copyError
310
}
311
 
312
// Output runs the command and returns its standard output.
313
func (c *Cmd) Output() ([]byte, error) {
314
        if c.Stdout != nil {
315
                return nil, errors.New("exec: Stdout already set")
316
        }
317
        var b bytes.Buffer
318
        c.Stdout = &b
319
        err := c.Run()
320
        return b.Bytes(), err
321
}
322
 
323
// CombinedOutput runs the command and returns its combined standard
324
// output and standard error.
325
func (c *Cmd) CombinedOutput() ([]byte, error) {
326
        if c.Stdout != nil {
327
                return nil, errors.New("exec: Stdout already set")
328
        }
329
        if c.Stderr != nil {
330
                return nil, errors.New("exec: Stderr already set")
331
        }
332
        var b bytes.Buffer
333
        c.Stdout = &b
334
        c.Stderr = &b
335
        err := c.Run()
336
        return b.Bytes(), err
337
}
338
 
339
// StdinPipe returns a pipe that will be connected to the command's
340
// standard input when the command starts.
341
func (c *Cmd) StdinPipe() (io.WriteCloser, error) {
342
        if c.Stdin != nil {
343
                return nil, errors.New("exec: Stdin already set")
344
        }
345
        if c.Process != nil {
346
                return nil, errors.New("exec: StdinPipe after process started")
347
        }
348
        pr, pw, err := os.Pipe()
349
        if err != nil {
350
                return nil, err
351
        }
352
        c.Stdin = pr
353
        c.closeAfterStart = append(c.closeAfterStart, pr)
354
        c.closeAfterWait = append(c.closeAfterWait, pw)
355
        return pw, nil
356
}
357
 
358
// StdoutPipe returns a pipe that will be connected to the command's
359
// standard output when the command starts.
360
// The pipe will be closed automatically after Wait sees the command exit.
361
func (c *Cmd) StdoutPipe() (io.ReadCloser, error) {
362
        if c.Stdout != nil {
363
                return nil, errors.New("exec: Stdout already set")
364
        }
365
        if c.Process != nil {
366
                return nil, errors.New("exec: StdoutPipe after process started")
367
        }
368
        pr, pw, err := os.Pipe()
369
        if err != nil {
370
                return nil, err
371
        }
372
        c.Stdout = pw
373
        c.closeAfterStart = append(c.closeAfterStart, pw)
374
        c.closeAfterWait = append(c.closeAfterWait, pr)
375
        return pr, nil
376
}
377
 
378
// StderrPipe returns a pipe that will be connected to the command's
379
// standard error when the command starts.
380
// The pipe will be closed automatically after Wait sees the command exit.
381
func (c *Cmd) StderrPipe() (io.ReadCloser, error) {
382
        if c.Stderr != nil {
383
                return nil, errors.New("exec: Stderr already set")
384
        }
385
        if c.Process != nil {
386
                return nil, errors.New("exec: StderrPipe after process started")
387
        }
388
        pr, pw, err := os.Pipe()
389
        if err != nil {
390
                return nil, err
391
        }
392
        c.Stderr = pw
393
        c.closeAfterStart = append(c.closeAfterStart, pw)
394
        c.closeAfterWait = append(c.closeAfterWait, pr)
395
        return pr, nil
396
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.