github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/tee/tee.go (about)

     1  // Copyright 2013-2018 the u-root 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  // Tee transcribes the standard input to the standard output and makes copies
     6  // in the files.
     7  //
     8  // Synopsis:
     9  //
    10  //	tee [-ai] FILES...
    11  //
    12  // Options:
    13  //
    14  //	-a, --append: append the output to the files rather than rewriting them
    15  //	-i, --ignore-interrupts: ignore the SIGINT signal
    16  package main
    17  
    18  import (
    19  	"fmt"
    20  	"io"
    21  	"log"
    22  	"os"
    23  	"os/signal"
    24  
    25  	flag "github.com/spf13/pflag"
    26  )
    27  
    28  var (
    29  	cat    = flag.BoolP("append", "a", false, "append the output to the files rather than rewriting them")
    30  	ignore = flag.BoolP("ignore-interrupts", "i", false, "ignore the SIGINT signal")
    31  )
    32  
    33  type command struct {
    34  	stdin  io.Reader
    35  	stdout io.Writer
    36  	stderr io.Writer
    37  	args   []string
    38  	cat    bool
    39  	ignore bool
    40  }
    41  
    42  func newCommand(cat, ignore bool, args []string) *command {
    43  	return &command{
    44  		stdin:  os.Stdin,
    45  		stdout: os.Stdout,
    46  		stderr: os.Stderr,
    47  		cat:    cat,
    48  		ignore: ignore,
    49  		args:   args,
    50  	}
    51  }
    52  
    53  func (c *command) run() error {
    54  	oflags := os.O_WRONLY | os.O_CREATE
    55  	if c.cat {
    56  		oflags |= os.O_APPEND
    57  	}
    58  
    59  	if c.ignore {
    60  		signal.Ignore(os.Interrupt)
    61  	}
    62  
    63  	files := make([]*os.File, 0, len(c.args))
    64  	writers := make([]io.Writer, 0, len(c.args)+1)
    65  	for _, fname := range c.args {
    66  		f, err := os.OpenFile(fname, oflags, 0o666)
    67  		if err != nil {
    68  			return fmt.Errorf("error opening %s: %v", fname, err)
    69  		}
    70  		files = append(files, f)
    71  		writers = append(writers, f)
    72  	}
    73  	writers = append(writers, c.stdout)
    74  
    75  	mw := io.MultiWriter(writers...)
    76  	if _, err := io.Copy(mw, c.stdin); err != nil {
    77  		return fmt.Errorf("error: %v", err)
    78  	}
    79  
    80  	for _, f := range files {
    81  		if err := f.Close(); err != nil {
    82  			fmt.Fprintf(c.stderr, "tee: error closing file %q: %v\n", f.Name(), err)
    83  		}
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  func main() {
    90  	flag.Parse()
    91  	if err := newCommand(*cat, *ignore, flag.Args()).run(); err != nil {
    92  		log.Fatalf("tee: %v", err)
    93  	}
    94  }