[mike@mwxm4]
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -127,8 +128,30 @@ var sshExec = func(remote string, capture bool) ([]byte, error) {
|
||||
return out, err
|
||||
}
|
||||
|
||||
// errRemoteBang is what a command carrying a '!' comes back with, so a caller
|
||||
// sees a failure rather than a command that quietly did something else.
|
||||
var errRemoteBang = errors.New("remote command contains '!'")
|
||||
|
||||
// remoteRejected reports whether a command must not be sent at all, and says
|
||||
// why. '!' is the one character shq cannot protect: csh expands history *before*
|
||||
// it looks at quotes, and it does so non-interactively too — `echo 'fix!now'`
|
||||
// answers "Event not found" on the tcsh server. No spelling survives both csh
|
||||
// and sh, so the only safe move is not to send one. This is the place every
|
||||
// remote command passes.
|
||||
func remoteRejected(remote string) bool {
|
||||
if !strings.ContainsRune(remote, '!') {
|
||||
return false
|
||||
}
|
||||
errorln("not sending a command with '!' in it — the server's login shell " +
|
||||
"would expand it instead of passing it on: " + remote)
|
||||
return true
|
||||
}
|
||||
|
||||
// ssh runs a single remote command over ssh with inherited stdio.
|
||||
func ssh(remote string) error {
|
||||
if remoteRejected(remote) {
|
||||
return errRemoteBang
|
||||
}
|
||||
_, err := sshExec(remote, false)
|
||||
return err
|
||||
}
|
||||
@@ -144,6 +167,9 @@ func sshOK(remote string) bool {
|
||||
|
||||
// sshOut runs a remote command and returns its stdout split into lines.
|
||||
func sshOut(remote string) ([]string, error) {
|
||||
if remoteRejected(remote) {
|
||||
return nil, errRemoteBang
|
||||
}
|
||||
out, err := sshExec(remote, true)
|
||||
lines := strings.Split(string(out), "\n")
|
||||
for len(lines) > 0 && lines[len(lines)-1] == "" {
|
||||
@@ -152,10 +178,27 @@ func sshOut(remote string) ([]string, error) {
|
||||
return lines, err
|
||||
}
|
||||
|
||||
// serverPath anchors a path on the git server at the configured gitpath.
|
||||
//
|
||||
// Every remote command has to name its target outright, because the login
|
||||
// directory of the git user is not necessarily the directory holding the bare
|
||||
// repositories. With `gituser = git` and `gitpath = /home/git` the two are the
|
||||
// same place and a bare "." worked by luck; with `gituser = root` and
|
||||
// `gitpath = /root/mgsh` it lists the home directory, where there is nothing to
|
||||
// find.
|
||||
func serverPath(rel string) string {
|
||||
base := strings.TrimRight(cfg.GitPath, "/")
|
||||
rel = strings.TrimPrefix(strings.TrimSpace(rel), "./")
|
||||
if rel == "" || rel == "." {
|
||||
return base
|
||||
}
|
||||
return base + "/" + rel
|
||||
}
|
||||
|
||||
// serverRepoNames lists the bare repositories on the git server, without the
|
||||
// ".git" suffix.
|
||||
func serverRepoNames() ([]string, error) {
|
||||
lines, err := sshOut("/bin/ls .")
|
||||
lines, err := sshOut("/bin/ls " + shq(serverPath(".")))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -169,10 +212,11 @@ func serverRepoNames() ([]string, error) {
|
||||
}
|
||||
|
||||
// serverEntryExists reports whether entry is present in the remote directory
|
||||
// path (relative to the git user's home). The error is returned rather than
|
||||
// folded into the bool so a failed lookup is never mistaken for "not there".
|
||||
// path (relative to gitpath, which serverPath resolves). The error is returned
|
||||
// rather than folded into the bool so a failed lookup is never mistaken for
|
||||
// "not there".
|
||||
func serverEntryExists(path, entry string) (bool, error) {
|
||||
lines, err := sshOut("/bin/ls " + shq(path))
|
||||
lines, err := sshOut("/bin/ls " + shq(serverPath(path)))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user