gopkg.in/hugelgupf/u-root.v7@v7.0.0-20180831062900-6a07824681b2/cmds/scp/scp.go (about)

     1  // Copyright 2012-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  // Scp copies files between hosts on a network.
     6  //
     7  // Synopsis:
     8  //     scp [-t|-f] [FILE]
     9  //
    10  // Description:
    11  //     If -t is given, decode SCP protocol from stdin and write to FILE.
    12  //     If -f is given, stream FILE over SCP protocol to stdout.
    13  //
    14  // Options:
    15  //     -t: Act as the target
    16  //     -f: Act as the source
    17  //     -v: Passed if SCP is verbose, ignored
    18  package main
    19  
    20  import (
    21  	"flag"
    22  	"fmt"
    23  	"io"
    24  	"log"
    25  	"os"
    26  )
    27  
    28  const (
    29  	SUCCESS = 0
    30  )
    31  
    32  var (
    33  	isTarget = flag.Bool("t", false, "Act as the target")
    34  	isSource = flag.Bool("f", false, "Act as the source")
    35  	_        = flag.Bool("v", false, "Ignored")
    36  )
    37  
    38  func scpSource(w io.Writer, path string) error {
    39  	f, err := os.Open(path)
    40  	if err != nil {
    41  		return err
    42  	}
    43  	defer f.Close()
    44  	s, err := f.Stat()
    45  	if err != nil {
    46  		return err
    47  	}
    48  	w.Write([]byte(fmt.Sprintf("C0%o %d %s\n", s.Mode(), s.Size(), path)))
    49  	if response() != SUCCESS {
    50  		log.Fatalf("response was not success")
    51  	}
    52  	_, err = io.Copy(w, f)
    53  	if err != nil {
    54  		log.Fatalf("copy error: %v", err)
    55  	}
    56  	reply(SUCCESS)
    57  
    58  	if response() != SUCCESS {
    59  		log.Fatalf("response was not success")
    60  	}
    61  	return nil
    62  }
    63  
    64  func scpSink(r io.Reader, path string) error {
    65  	var mode os.FileMode
    66  	var size int64
    67  	filename := ""
    68  
    69  	if _, err := fmt.Fscanf(r, "C0%o %d %s\n", &mode, &size, &filename); err != nil {
    70  		return err
    71  	}
    72  	f, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, mode)
    73  	if err != nil {
    74  		log.Fatalf("open error: %v", err)
    75  	}
    76  	reply(SUCCESS)
    77  	defer f.Close()
    78  
    79  	_, err = io.CopyN(f, r, size)
    80  	if err != nil {
    81  		log.Fatalf("copy error: %v", err)
    82  	}
    83  	reply(SUCCESS)
    84  	return nil
    85  }
    86  
    87  func reply(r byte) {
    88  	os.Stdout.Write([]byte{r})
    89  }
    90  
    91  func response() byte {
    92  	b := make([]byte, 1)
    93  	os.Stdout.Read(b)
    94  	return b[0]
    95  }
    96  
    97  func main() {
    98  	flag.Parse()
    99  
   100  	if flag.NArg() == 0 {
   101  		log.Fatalf("no file provided")
   102  	}
   103  
   104  	if *isSource == *isTarget {
   105  		log.Fatalf("-t or -f needs to be supplied, and not both")
   106  	}
   107  
   108  	if *isSource {
   109  		// Sink->Source is started with a response
   110  		if response() != SUCCESS {
   111  			log.Fatalf("response was not success")
   112  		}
   113  		if err := scpSource(os.Stdout, flag.Args()[0]); err != nil {
   114  			log.Fatalf("scp: %v", err)
   115  		}
   116  	} else if *isTarget {
   117  		// Sink->Source starts with a response
   118  		reply(SUCCESS)
   119  		for {
   120  			if err := scpSink(os.Stdin, flag.Args()[0]); err != nil {
   121  				log.Fatalf("scp: %v", err)
   122  			}
   123  		}
   124  	}
   125  }