aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzqqw2020-10-26 02:11:42 +0000
committerzqqw2020-10-26 02:11:42 +0000
commit0601052833bfb97cc178cdbd7aa150ecec4c7e5b (patch)
tree3dfe606433ea45dc48e106a8caf0d221f1e1a5f2
parentf2a93bea278e9f43cad98ca8e74f9a423f36e333 (diff)
execRedirect - pipe stdout from child
-rw-r--r--src/common.nim28
-rw-r--r--src/feature/syncinstall.nim23
-rw-r--r--src/main.nim2
-rw-r--r--src/pacman.nim4
-rw-r--r--src/utils.nim93
5 files changed, 109 insertions, 41 deletions
diff --git a/src/common.nim b/src/common.nim
index f7de141..71073cd 100644
--- a/src/common.nim
+++ b/src/common.nim
@@ -346,8 +346,8 @@ proc getGitFiles*(repoPath: string, gitSubdir: Option[string],
dropPrivileges: bool): seq[string] =
if gitSubdir.isSome:
forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@",
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@",
gitSubdir.unsafeGet & "/")
else:
quit(1)))
@@ -355,8 +355,8 @@ proc getGitFiles*(repoPath: string, gitSubdir: Option[string],
.map(s => s[gitSubdir.unsafeGet.len + 1 .. ^1])
else:
forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@")
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(gitCmd, "-C", repoPath, "ls-tree", "-r", "--name-only", "@")
else:
quit(1)))
.output
@@ -380,16 +380,16 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string],
(firstCommit, false)
else:
(forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(gitCmd, "-C", repoPath,
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(gitCmd, "-C", repoPath,
"rev-list", "--max-parents=0", "@")
else:
quit(1)))
.output.optLast, true)
let (realLastThreeCommits, _) = forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(gitCmd, "-C", repoPath,
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(gitCmd, "-C", repoPath,
"rev-list", "--max-count=3", "@")
else:
quit(1)))
@@ -408,8 +408,8 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string],
none(string)
else:
let foundVersion = forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(pkgLibDir & "/bisect",
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(pkgLibDir & "/bisect",
compareMethod, repoPath & "/" & gitSubdir, version)
else:
quit(1)))
@@ -452,8 +452,8 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string],
"bisect", "run", pkgLibDir & "/bisect", compareMethod, gitSubdir, version)
let commit = forkWaitRedirect(() => (block:
- if not dropPrivileges or dropPrivileges():
- execResult(gitCmd, "-C", repoPath,
+ if not dropPrivileges or dropPrivRedirect():
+ execRedirect(gitCmd, "-C", repoPath,
"rev-list", "--max-count=1", "refs/bisect/bad")
else:
quit(1)))
@@ -477,8 +477,8 @@ proc bisectVersion(repoPath: string, debug: bool, firstCommit: Option[string],
proc obtainSrcInfo*(path: string): string =
let (output, code) = forkWaitRedirect(() => (block:
- if dropPrivileges() and chdir(path) == 0:
- execResult(makePkgCmd, "--printsrcinfo")
+ if dropPrivRedirect() and chdir(path) == 0:
+ execRedirect(makePkgCmd, "--printsrcinfo")
else:
quit(1)))
diff --git a/src/feature/syncinstall.nim b/src/feature/syncinstall.nim
index 813eb45..8f26d0d 100644
--- a/src/feature/syncinstall.nim
+++ b/src/feature/syncinstall.nim
@@ -305,6 +305,17 @@ template dropPrivilegesAndChdir(path: Option[string], body: untyped): int =
printError(config.color, tr"failed to drop privileges")
quit(1)
+template dropPrivRedirectAndChdir(path: Option[string], body: untyped): int =
+ if dropPrivRedirect():
+ if path.isNone or chdir(path.unsafeGet) == 0:
+ body
+ else:
+ printError(config.color, tr"chdir failed: $#" % [path.unsafeGet])
+ quit(1)
+ else:
+ printError(config.color, tr"failed to drop privileges")
+ quit(1)
+
template createViewTag(repo: string, base: string): string =
"view-" & repo & "/" & base
@@ -376,8 +387,8 @@ proc editLoop(config: Config, repo: string, base: string, repoPath: string,
let (hasChanges, noTag) = if repo == config.aurRepo: (block:
let revisions = forkWaitRedirect(() => (block:
- dropPrivilegesAndChdir(none(string)):
- execResult(gitCmd, "-C", repoPath, "rev-list", tag & "..@")))
+ dropPrivRedirectAndChdir(none(string)):
+ execRedirect(gitCmd, "-C", repoPath, "rev-list", tag & "..@")))
if revisions.code != 0:
(false, true)
@@ -385,8 +396,8 @@ proc editLoop(config: Config, repo: string, base: string, repoPath: string,
(false, false)
else: (block:
let diff = forkWaitRedirect(() => (block:
- dropPrivilegesAndChdir(none(string)):
- execResult(gitCmd, "-C", repoPath, "diff", tag & "..@", gitSubdir.get("."))))
+ dropPrivRedirectAndChdir(none(string)):
+ execRedirect(gitCmd, "-C", repoPath, "diff", tag & "..@", gitSubdir.get("."))))
(diff.output.len > 0, false)))
else:
(false, true)
@@ -436,8 +447,8 @@ proc buildLoop(config: Config, pkgInfos: seq[PackageInfo], skipDeps: bool,
let envExt = getEnv("PKGEXT")
let confExt = if envExt.len == 0:
forkWaitRedirect(() => (block:
- dropPrivilegesAndChdir(none(string)):
- execResult(bashCmd, "-c",
+ dropPrivRedirectAndChdir(none(string)):
+ execRedirect(bashCmd, "-c",
"source \"$@\" && echo \"$PKGEXT\"",
"bash", workConfFile)))
.output.optFirst.get("")
diff --git a/src/main.nim b/src/main.nim
index d8ad5a5..73030d2 100644
--- a/src/main.nim
+++ b/src/main.nim
@@ -177,7 +177,7 @@ proc handleHelp(operation: OperationType) =
.map(o => @["-" & o.pair.short.get])
.optFirst.get(@[]) & @["-h"]
- let (lines, _) = forkWaitRedirect(() => execResult(pacmanCmd & operationArgs))
+ let (lines, _) = forkWaitRedirect(() => execRedirect(pacmanCmd & operationArgs))
for line in lines:
echo(line.replace(re"\bpacman\b", "pakku"))
diff --git a/src/pacman.nim b/src/pacman.nim
index ed80311..5f1cb4a 100644
--- a/src/pacman.nim
+++ b/src/pacman.nim
@@ -407,8 +407,8 @@ proc obtainPacmanConfig*(args: seq[Argument]): PacmanConfig =
{x}
let hasKeyserver = forkWaitRedirect(() => (block:
- if dropPrivileges():
- execResult(gpgConfCmd, "--list-options", "gpg")
+ if dropPrivRedirect():
+ execRedirect(gpgConfCmd, "--list-options", "gpg")
else:
quit(1)))
.output
diff --git a/src/utils.nim b/src/utils.nim
index da9618b..1f58b8f 100644
--- a/src/utils.nim
+++ b/src/utils.nim
@@ -1,5 +1,5 @@
import
- hashes, options, os, posix, sequtils, strutils, sugar, tables
+ hashes, options, os, posix, sequtils, strutils, sugar, tables, osproc, streams, strtabs
type
HaltError* = object of CatchableError
@@ -170,22 +170,18 @@ proc forkWaitInternal(call: () -> int, beforeWait: () -> void): int =
proc forkWait*(call: () -> int): int =
forkWaitInternal(call, proc = discard)
-proc forkWaitRedirect*(call: () -> int): tuple[output: seq[string], code: int] =
- var fd: array[2, cint]
- discard pipe(fd)
+var dPriv: bool = false
+var writeFlag: bool = false
+var fd: array[2, cint]
+proc forkWaitRedirect*(call: () -> int): tuple[output: seq[string], code: int] =
+ if pipe(fd) == -1:
+ raiseOSError(osLastError())
var data = newSeq[char]()
-
- let code = forkWaitInternal(() => (block:
+ writeFlag = true
+ let code = forkWaitInternal(() => (block: # "call" child process
discard close(fd[0])
- discard close(1)
- discard dup(fd[1])
- discard close(fd[1])
- discard close(0)
- discard open("/dev/null")
- discard close(2)
- discard open("/dev/null")
- call()), () => (block:
+ call()), () => (block: # "beforewait" parent process
discard close(fd[1])
var buffer: array[80, char]
while true:
@@ -194,24 +190,21 @@ proc forkWaitRedirect*(call: () -> int): tuple[output: seq[string], code: int] =
break
data &= buffer[0 .. count - 1]
discard close(fd[0])))
-
+ writeFlag = false
var output = newStringOfCap(data.len)
for c in data:
output &= c
-
let lines = if output.len == 0:
@[]
elif output.len > 0 and $output[^1] == "\n":
output[0 .. ^2].split("\n")
else:
output.split("\n")
-
(lines, code)
proc getgrouplist*(user: cstring, group: Gid, groups: ptr cint, ngroups: var cint): cint
{.importc, header: "<grp.h>".}
-
proc setgroups*(size: csize_t, groups: ptr cint): cint
{.importc, header: "<grp.h>".}
@@ -250,6 +243,70 @@ except:
proc canDropPrivileges*(): bool =
initialUser.isSome
+proc dropPrivRedirect*(): bool =
+ dPriv = true
+ return true
+
+proc execRedirect*(args: varargs[string]): int =
+ var
+ code: int
+ p: owned(Process)
+ argSeq: seq[string] = @args
+ iUser: User
+ envs: StringTableRef = nil
+
+ if dPriv == true:
+ if initialUser.isSome:
+ iUser = initialUser.unsafeGet
+ envs = newStringTable(modeCaseSensitive)
+ if iUser.name != "":
+ var groups = iUser.groups.map(x => x.cint)
+ if setgroups(cast[csize_t](iUser.groups.len), addr(groups[0])) < 0:
+ envs = nil
+ if setgid((Gid) iUser.gid) != 0:
+ envs = nil
+ if setuid((Uid) iUser.uid) != 0:
+ envs = nil
+ for key, value in envPairs():
+ if key in ["SUDO_COMMAND", "SUDO_USER", "SUDO_UID", "SUDO_GID", "PKEXEC_UID"]:
+ continue
+ if key in ["USER", "USERNAME", "LOGNAME"]:
+ envs[key] = iUser.name
+ continue
+ if key in ["HOME"]:
+ envs[key] = iUser.home
+ continue
+ if key in ["SHELL"]:
+ envs[key] = iUser.shell
+ continue
+ envs[key] = value
+ if envs == nil:
+ echo "Error: failed to drop privileges"
+ return -1
+ discard close(fd[0])
+ argSeq.delete(0)
+ try:
+ p = startProcess(command = args[0], args = argSeq, env = envs, options = {poStdErrToStdOut, poUsePath})
+ except:
+ echo "Error: " & getCurrentExceptionMsg()
+ return -1
+ var outp = outputStream(p)
+ close(inputStream(p))
+ var line = newStringOfCap(120).TaintedString
+ while true:
+ if outp.readLine(line):
+ if writeFlag == false:
+ echo line.string
+ else:
+ discard write(fd[1], line.string.cstring, len(line.string))
+ discard write(fd[1], "\n".cstring, 1)
+ else:
+ code = peekExitCode(p)
+ if code != -1: break
+ close(p)
+ discard close(fd[1])
+ return code
+
proc dropPrivileges*(): bool =
if initialUser.isSome:
let user = initialUser.unsafeGet