Skip to content
This repository was archived by the owner on Aug 30, 2024. It is now read-only.

Commit c8cec8e

Browse files
Verify rsync protocol version match prior to proceeding (#71)
* Verify rsync protocol version match prior to proceeding. `sync.Version()` proceeds with a warning that there may be a version mismatch if it timesout. `syncCmd.version` assumes rsync is present in the path. `wsep.RemoteExecer` isn't available publicly on GitHub, so I took a best guess with it and `wsep.ExitError`. * Add context to sync.Version. * Correct syncCmd.version, sync.Version. Passing `s.ReadLine` to `strings.Split` was a mistake since it returns three values. Having access to `wsep` helped the compiler find the bugs. * Update local, remote version checks to avoid blanks. * Remove go from io.Copy in internal/sync/sync.go#Version * Return error directly in internal/sync/sync.go#Version * Update [vV]ersion comment strings; remove extraneous error check.
1 parent 9b58d37 commit c8cec8e

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

cmd/coder/sync.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package main
22

33
import (
4+
"bytes"
5+
"fmt"
6+
"log"
47
"os"
8+
"os/exec"
59
"path/filepath"
610
"strings"
711

@@ -29,6 +33,23 @@ func (cmd *syncCmd) RegisterFlags(fl *pflag.FlagSet) {
2933
fl.BoolVarP(&cmd.init, "init", "i", false, "do initial transfer and exit")
3034
}
3135

36+
// version returns local rsync protocol version as a string.
37+
func (_ *syncCmd) version() string {
38+
cmd := exec.Command("rsync", "--version")
39+
out, err := cmd.CombinedOutput()
40+
if err != nil {
41+
log.Fatal(err)
42+
}
43+
44+
firstLine, err := bytes.NewBuffer(out).ReadString('\n')
45+
if err != nil {
46+
log.Fatal(err)
47+
}
48+
versionString := strings.Split(firstLine, "protocol version ")
49+
50+
return versionString[1]
51+
}
52+
3253
func (cmd *syncCmd) Run(fl *pflag.FlagSet) {
3354
var (
3455
local = fl.Arg(0)
@@ -71,6 +92,16 @@ func (cmd *syncCmd) Run(fl *pflag.FlagSet) {
7192
LocalDir: absLocal,
7293
Client: entClient,
7394
}
95+
96+
localVersion := cmd.version()
97+
remoteVersion, rsyncErr := s.Version()
98+
99+
if rsyncErr != nil {
100+
flog.Info("Unable to determine remote rsync version. Proceeding cautiously.")
101+
} else if localVersion != remoteVersion {
102+
flog.Fatal(fmt.Sprintf("rsync protocol mismatch. %s.", localVersion, rsyncErr))
103+
}
104+
74105
for err == nil || err == sync.ErrRestartSync {
75106
err = s.Run()
76107
}

internal/sync/sync.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package sync
22

33
import (
4+
"bytes"
45
"context"
56
"errors"
67
"fmt"
@@ -10,6 +11,7 @@ import (
1011
"os/exec"
1112
"path"
1213
"path/filepath"
14+
"strings"
1315
"sync"
1416
"sync/atomic"
1517
"time"
@@ -261,6 +263,44 @@ const (
261263
maxAcceptableDispatch = time.Millisecond * 50
262264
)
263265

266+
// Version returns remote protocol version as a string.
267+
// Or, an error if one exists.
268+
func (s Sync) Version() (string, error) {
269+
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
270+
defer cancel()
271+
272+
conn, err := s.Client.DialWsep(ctx, s.Env)
273+
if err != nil {
274+
return "", err
275+
}
276+
defer conn.Close(websocket.CloseNormalClosure, "")
277+
278+
execer := wsep.RemoteExecer(conn)
279+
process, err := execer.Start(ctx, wsep.Command{
280+
Command: "rsync",
281+
Args: []string{"--version"},
282+
})
283+
if err != nil {
284+
return "", err
285+
}
286+
buf := &bytes.Buffer{}
287+
io.Copy(buf, process.Stdout())
288+
289+
err = process.Wait()
290+
if err != nil {
291+
return "", err
292+
}
293+
294+
firstLine, err := buf.ReadString('\n')
295+
if err != nil {
296+
return "", err
297+
}
298+
299+
versionString := strings.Split(firstLine, "protocol version ")
300+
301+
return versionString[1], nil
302+
}
303+
264304
// Run starts the sync synchronously.
265305
// Use this command to debug what wasn't sync'd correctly:
266306
// rsync -e "coder sh" -nicr ~/Projects/cdr/coder-cli/. ammar:/home/coder/coder-cli/

0 commit comments

Comments
 (0)