From 3aad750dd36fde1af88c658a1b94bb6ae50d6f79 Mon Sep 17 00:00:00 2001 From: Tobias Ulmer Date: Thu, 29 Aug 2013 17:33:17 +0200 Subject: [PATCH] Consolidate e2util into e2lib, add error reporting and new functions Remove duplicate and unused functions. Add and verify error handling on all call-sites of the new or renamed functions. Signed-off-by: Tobias Ulmer --- doc/developer/config.ld | 2 +- generic/Makefile | 27 +- generic/e2lib.lua | 492 ++++++++++++++++++++-------- generic/e2option.lua | 3 +- generic/generic_git.lua | 24 +- generic/{e2util.c => le2lib.c} | 565 +++++++++------------------------ generic/plugin.lua | 2 +- generic/transport.lua | 6 +- global/e2-fetch-project.lua | 2 +- global/e2-install-e2.lua | 26 +- global/e2.lua | 5 +- local/e2-new-source.lua | 2 +- local/e2build.lua | 29 +- local/e2tool.lua | 31 +- plugins/cvs.lua | 18 +- plugins/files.lua | 6 +- plugins/git.lua | 16 +- 17 files changed, 624 insertions(+), 632 deletions(-) rename generic/{e2util.c => le2lib.c} (55%) diff --git a/doc/developer/config.ld b/doc/developer/config.ld index 647ac1f..3b2fd43 100644 --- a/doc/developer/config.ld +++ b/doc/developer/config.ld @@ -9,7 +9,7 @@ file = { "../../generic", "../../generic/test_sha1.lua", "../../generic/luafile_ll.c", "../../generic/sha1.c", - "../../generic/e2util.c", + "../../generic/le2lib.c", "../../generic/lsha1.c", "../../global/e2-su-2.2.c", "../../local/linux32.c", diff --git a/generic/Makefile b/generic/Makefile index d2ba8a8..ac4b215 100644 --- a/generic/Makefile +++ b/generic/Makefile @@ -32,48 +32,43 @@ include $(TOPLEVEL)/make.vars LUA_LIBS = strict.lua plugin.lua e2lib.lua LUA_LIBS += e2option.lua hash.lua tools.lua transport.lua cache.lua url.lua LUA_LIBS += generic_git.lua luafile.lua err.lua lock.lua +SO_LIBS = sha1.so luafile_ll.so le2lib.so CLEAN_FILES = *~ *.o *.so .PHONY: all install uninstall local install-local clean -all: sha1.so luafile_ll.so e2util.so +all: $(SO_LIBS) sha1.so: sha1.o lsha1.o luafile_ll.so: luafile_ll.o -e2util.so: e2util.o +le2lib.so: le2lib.o install: all install -d $(DESTDIR)$(LIBDIR) install -m 644 $(LUA_LIBS) $(DESTDIR)$(LIBDIR) - install -m 644 sha1.so $(DESTDIR)$(LIBDIR) - install -m 644 luafile_ll.so $(DESTDIR)$(LIBDIR) - install -m 644 e2util.so $(DESTDIR)$(LIBDIR) + install -m 644 $(SO_LIBS) $(DESTDIR)$(LIBDIR) uninstall: - rm -f $(DESTDIR)$(LIBDIR)/sha1.so - rm -f $(DESTDIR)$(LIBDIR)/luafile_ll.so - rm -f $(DESTDIR)$(LIBDIR)/e2util.so - set -e; for f in $(LUA_LIBS); do \ + set -e; for f in $(LUA_LIBS) $(SO_LIBS); do \ rm -f "$(DESTDIR)$(LIBDIR)/$$f"; \ done rmdir -p $(DESTDIR)$(LIBDIR) || true -local: sha1.so luafile_ll.so e2util.so +local: $(SO_LIBS) install-local: local install -d $(LOCALLIBDIR) - install -m 644 sha1.so $(LOCALLIBDIR) - install -m 644 luafile_ll.so $(LOCALLIBDIR) - install -m 644 e2util.so $(LOCALLIBDIR) + install -m 644 $(LUA_LIBS) $(LOCALLIBDIR) + install -m 644 $(SO_LIBS) $(LOCALLIBDIR) uninstall-local: - rm -f $(LOCALLIBDIR)/sha1.so - rm -f $(LOCALLIBDIR)/luafile_ll.so - rm -f $(LOCALLIBDIR)/e2util.so + set -e; for f in $(LUA_LIBS) $(SO_LIBS); do \ + rm -f "$(LOCALLIBDIR)/$$f"; \ + done rmdir -p $(LOCALLIBDIR) || true doc: diff --git a/generic/e2lib.lua b/generic/e2lib.lua index 20cb706..66280e9 100644 --- a/generic/e2lib.lua +++ b/generic/e2lib.lua @@ -48,13 +48,13 @@ local e2lib = {} package.loaded["e2lib"] = e2lib local buildconfig = require("buildconfig") -require("e2util") local lock = require("lock") local err = require("err") local plugin = require("plugin") local tools = require("tools") local cache = require("cache") local luafile = require("luafile") +local le2lib = require("le2lib") -- Module-level global variables -- @@ -116,9 +116,199 @@ along with this program. If not, see .]], debuglogfilebuffer = {}, } +--- Get current working directory. +-- @return Current working directory (string) or false on error. +-- @return Error object on failure. +function e2lib.cwd() + local path, errstring = le2lib.cwd() + + if not path then + return false, + err.new("cannot get current working directory: %s", errstring) + end + + return path +end + +--- Dirent table, returned by @{stat}. +-- @table dirent +-- @field dev Device-id (number). +-- @field ino Inode-number (number). +-- @field mode Permissions and access mode (number). +-- @field nlink Number of hard links (number). +-- @field uid User ID (number). +-- @field gid Group ID (number). +-- @field rdev Device id for char of block special files (number). +-- @field size File size (number). +-- @field atime access time (number). +-- @field mtime modification time (number). +-- @field ctime change time (number). +-- @field blksize block size (number). +-- @field type One of the following strings: block-special, character-special, +-- fifo-special, regular, directory, symbolic-link, socket, unknown. + + +--- Get file status information. +-- @param path Path to the file, including special files. +-- @param followlinks Whether symlinks should be followed, or information +-- about the link should be returned (boolean). +-- @return Dirent table containing attributes (see @{dirent}), or false on error +-- @return Error object on failure. +function e2lib.stat(path, followlinks) + local dirent, errstring = le2lib.stat(path, followlinks) + + if not dirent then + return false, err.new("stat failed: %s: %s", path, errstring) + end + + return dirent +end + +--- Checks if file exists. +-- If executable is true, it also checks whether the file is executable. +-- @param path Path to check. +-- @param executable Check if executable (true) or not (false). +-- @return True if file exists, false otherwise. +function e2lib.exists(path, executable) + return le2lib.exists(path, executable) +end + +--- Create a symlink. +-- @param oldpath Path to point to (string). +-- @param newpath New symlink path (string). +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.symlink(oldpath, newpath) + local rc, errstring = le2lib.symlink(oldpath, newpath) + + if not rc then + return false, err.new("creating symlink failed: %s -> %s: %s", + newpath, oldpath, errstring) + end + + return true +end + +--- Create a hardlink. +-- @param oldpath Path to existing file (string). +-- @param newpath Path to new file (string). +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.hardlink(oldpath, newpath) + local rc, errstring = le2lib.hardlink(oldpath, newpath) + + if not rc then + return false, err.new("creating hard link failed: %s -> %s: %s", + newpath, oldpath, errstring) + end + + return true +end + +--- Wait for process to terminate. +-- @param pid Process ID, -1 to wait for any child. +-- @return Exit status of process (WEXITSTATUS), or false on error. +-- @return Process ID of the terminated child or error object on failure. +function e2lib.wait(pid) + local rc, pid = le2lib.wait(pid) + + if not rc then + local errstring = pid + return false, err.new("waiting for child %d failed: %s", pid, errstring) + end + + return rc, pid +end + +--- Poll input output multiplexing. +-- Only indicates first selected file descriptor. +-- @param timeout Timeout in milliseconds (number). +-- @param fdvec Vector of file descriptors (table of numbers). +-- @return Returns 0 on timeout, < 0 on error and > 0 to indicate which file +-- descriptor triggered. +-- @return True if it's a POLLIN event. +-- @return True if it's a POLLOUT event. +function e2lib.poll(timeout, fdvec) + return le2lib.poll(timeout, fdvec) +end + +--- Set file descriptor in non-blocking mode. +-- @param fd Open file descriptor. +function e2lib.unblock(fd) + return le2lib.unblock(fd) +end + +--- Creates a new process. Returns both in the parent and in the child. +-- @return Process ID of the child or false on error in the parent process. +-- Returns zero in the child process. +-- @return Error object on failure. +function e2lib.fork() + local pid, errstring = le2lib.fork() + + if pid == false then + return false, err.new("failed to fork a new child: %s", errstring) + end + + return pid +end + +--- Set umask value. +-- @param mask New umask value. +-- @return Previous umask value. +function e2lib.umask(mask) + return le2lib.umask(mask) +end + +--- Set environment variable. +-- @param var Variable name (string). +-- @param val Variable content (string). +-- @param overwrite True to overwrite existing variable of same name. +-- @return True on success, false on error. +function e2lib.setenv(var, val, overwrite) + -- used in only once, questionable + return le2lib.setenv(var, val, overwrite) +end + +--- Reset signal handlers back to their default. +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.signal_reset() + local rc, errstring + + rc, errstring = le2lib.signal_reset() + if not rc then + return false, err.new("resetting signal handlers: %s", errstring) + end + + return true +end + +--- Get current process id. +-- @return Process ID (number) +function e2lib.getpid() + -- used only for tempfile generation + return le2lib.getpid() +end + +--- Send signal to process. +-- @param pid Process ID to signal (number). +-- @param sig Signal number. +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.kill(pid, sig) + local rc, errstring = le2lib.kill(pid, sig) + + if not rc then + return false, err.new("sending signal %d to process %d failed: %s", + sig, pid, errstring) + end + + return true +end + --- Interrupt handling. -- --- e2util sets up a SIGINT handler that calls back into this function. +-- le2lib sets up a SIGINT handler that calls back into this function. function e2lib.interrupt_hook() e2lib.abort("*interrupted by user*") end @@ -133,12 +323,12 @@ function e2lib.init() local traceflags = os.getenv("E2_TRACE") or "c" debug.sethook(e2lib.tracer, traceflags) - local rc, re = e2util.signal_reset() + local rc, re = e2lib.signal_reset() if not rc then e2lib.abort(re) end - e2util.closefrom(3) + e2lib.closefrom(3) -- ignore errors, no /proc should not prevent factory from working -- Overwrite io functions that create a file descriptor to set the @@ -399,7 +589,7 @@ end --- Set E2_CONFIG in the environment to file. Also sets commandline option. -- @param file Config file name (string). function e2lib.sete2config(file) - e2util.setenv("E2_CONFIG", file, 1) + e2lib.setenv("E2_CONFIG", file, 1) e2lib.globals.osenv["E2_CONFIG"] = file e2lib.globals.cmdline["e2-config"] = file end @@ -511,30 +701,16 @@ function e2lib.rotate_log(file) local rc, re local logdir = e2lib.dirname(file) local logfile = e2lib.basename(file) - local dir = e2util.directory(logdir, false) - if not dir then - return false, e:cat(string.format("%s: can't read directory", dir)) - end local files = {} - local dst - - if not e2util.stat(file) then - return true - end for f, re in e2lib.directory(logdir, false) do - local start, stop, extension - if not f then return false, e:cat(re) end - start, stop = string.find(f, logfile, 1, true) - if start and start == 1 then - extension = string.sub(f, stop+1) - if string.find(extension, "^%.[0-9]+$") then - table.insert(files, f) - end + local match = f:match(string.format("%s.[0-9]+", logfile)) + if match then + table.insert(files, 1, match) end end @@ -548,22 +724,22 @@ function e2lib.rotate_log(file) table.sort(files, comp) for _,f in ipairs(files) do - local n, src, dst - - src = e2lib.join(logdir, f) - n = f:match("%.([0-9]+)$") - assert(n, "could not match logfile number") - n = tonumber(n) - if n >= e2lib.globals.logrotate - 1 then - rc, re = e2lib.rm(src) - if not rc then - return false, e:cat(re) - end - else - dst = string.format("%s/%s.%d", logdir, logfile, n + 1) - rc, re = e2lib.mv(src, dst) - if not rc then - return false, e:cat(re) + local n = f:match(string.format("%s.([0-9]+)", logfile)) + if n then + n = tonumber(n) + if n >= e2lib.globals.logrotate - 1 then + local del = string.format("%s/%s.%d", logdir, logfile, n) + rc, re = e2lib.unlink(del) + if not rc then + return false, e:cat(re) + end + else + local src = string.format("%s/%s.%d", logdir, logfile, n) + local dst = string.format("%s/%s.%d", logdir, logfile, n + 1) + rc, re = e2lib.mv(src, dst) + if not rc then + return false, e:cat(re) + end end end end @@ -848,7 +1024,7 @@ function e2lib.read_global_config(e2_config_file) c.data = x end e2lib.logf(4, "reading global config file: %s", path) - local rc = e2util.exists(path) + local rc = e2lib.exists(path) if rc then e2lib.logf(3, "using global config file: %s", path) rc, re = e2lib.dofile2(path, c, true) @@ -899,7 +1075,7 @@ end function e2lib.read_extension_config() local e = err.new("reading extension config file: %s", e2lib.globals.extension_config) - local rc = e2util.exists(e2lib.globals.extension_config) + local rc = e2lib.exists(e2lib.globals.extension_config) if not rc then return false, e:append("config file does not exist") end @@ -939,7 +1115,7 @@ end -- or false and an err object on error. The iterator signals the -- end of the list by returning nil. function e2lib.directory(path, dotfiles, noerror) - local dir = e2util.directory(path, dotfiles) + local dir, errstring = le2lib.directory(path, dotfiles) if not dir then if noerror then dir = {} @@ -950,7 +1126,8 @@ function e2lib.directory(path, dotfiles, noerror) return function () if not error_signaled then error_signaled = true - return false, err.new("directory `%s' does not exist", p) + return false, err.new("reading directory `%s' failed: %s", + path, errstring) else return nil end @@ -1024,6 +1201,7 @@ function e2lib.callcmd_pipe(cmds, infile, outfile) for cmdidx = 1, c do local pipein, output local errin, errout + local pid rc, errin, errout = luafile.pipe() if not rc then @@ -1041,8 +1219,10 @@ function e2lib.callcmd_pipe(cmds, infile, outfile) end e2lib.logf(3, "+ %s", cmds[cmdidx]) - local pid = e2util.fork() - if pid == 0 then + pid, re = e2lib.fork() + if not pid then + return false, e:cat(re) + elseif pid == 0 then if cmdidx < c then -- everyone but the last pipein:close() @@ -1054,7 +1234,7 @@ function e2lib.callcmd_pipe(cmds, infile, outfile) end pids[pid] = cmdidx - e2util.unblock(errin:fileno()) + e2lib.unblock(errin:fileno()) ers[cmdidx] = errin errout:close() @@ -1078,7 +1258,7 @@ function e2lib.callcmd_pipe(cmds, infile, outfile) table.insert(fds, n) ifd[n] = i end - local i, r = e2util.poll(-1, fds) + local i, r = e2lib.poll(-1, fds) if i <= 0 then return false, err.new("poll error: %s", tostring(i)) @@ -1106,9 +1286,10 @@ function e2lib.callcmd_pipe(cmds, infile, outfile) c = #cmds rc = true while c > 0 do - local status, pid = e2util.wait(-1) + local status, pid = e2lib.wait(-1) if not status then - return false, err.new("waiting for child to exit failed: %s", pid) + re = pid + return false, e:cat(re) end local cmdidx = pids[pid] @@ -1136,9 +1317,10 @@ end -- captured via a pipe -- the capture function is called for every chunk of output that -- is captured from the pipe. --- @return unknown +-- @return Return status code of the command (number) or false on error. +-- @return Error object on failure. function e2lib.callcmd_capture(cmd, capture) - local rc, oread, owrite, devnull, pid + local rc, re, oread, owrite, devnull, pid local function autocapture(msg) e2lib.log(3, msg) @@ -1153,34 +1335,41 @@ function e2lib.callcmd_capture(cmd, capture) e2lib.abort("could not open /dev/null") end e2lib.logf(4, "+ %s", cmd) - pid = e2util.fork() - if pid == 0 then + pid, re = e2lib.fork() + if not pid then + return false, re + elseif pid == 0 then oread:close() rc = callcmd(devnull, owrite, owrite, cmd) os.exit(rc) else owrite:close() - --log("capturing...") while not oread:eof() do local x = oread:readline() if x then - --print("read: '" .. x .. "'") capture(x) end end oread:close() - rc = e2util.wait(pid) + rc, re = e2lib.wait(pid) + if not rc then + luafile.close(devnull) + return false, re + end + luafile.close(devnull) - --log("capturing done...") - --log("exit status was " .. rc) end + return rc end --- Call a command, log its output and catch the last lines for error reporting. -- @param cmd string: the command --- @return Return code of the command (number). --- @return Error object containing command line and last lines of output. +-- @return Return code of the command (number), or false on error. +-- @return Error object containing command line and last lines of output. It's +-- the callers responsibility to determine whether an error occured +-- based on the return code. If the return code is false, an error +-- within the function occured and a normal error object is returned. function e2lib.callcmd_log(cmd) local e = err.new("command %s failed:", cmd) local fifo = {} @@ -1196,7 +1385,10 @@ function e2lib.callcmd_log(cmd) end end - local rc = e2lib.callcmd_capture(cmd, logto) + local rc, re = e2lib.callcmd_capture(cmd, logto) + if not rc then + return false, e:cat(e) + end if #fifo == 0 then table.insert(fifo, "command failed silently, no output captured") @@ -1260,9 +1452,9 @@ end function e2lib.locate_project_root(path) local rc, re local e = err.new("checking for project directory failed") - local save_path = e2util.cwd() + local save_path, re = e2lib.cwd() if not save_path then - return false, e:append("cannot get current working directory") + return false, e:cat(re) end if path then rc = e2lib.chdir(path) @@ -1271,14 +1463,14 @@ function e2lib.locate_project_root(path) return false, e:cat(re) end else - path = e2util.cwd() + path, re = e2lib.cwd() if not path then e2lib.chdir(save_path) - return false, e:append("cannot get current working directory") + return false, e:cat(re) end end while true do - if e2util.exists(".e2") then + if e2lib.exists(".e2") then e2lib.logf(3, "project is located in: %s", path) e2lib.chdir(save_path) return path @@ -1291,10 +1483,10 @@ function e2lib.locate_project_root(path) e2lib.chdir(save_path) return false, e:cat(re) end - path = e2util.cwd() + path, re = e2lib.cwd() if not path then e2lib.chdir(save_path) - return false, e:append("cannot get current working directory") + return false, e:cat(re) end end e2lib.chdir(save_path) @@ -1382,7 +1574,7 @@ end function e2lib.mktempfile(template) if not template then template = string.format("%s/e2tmp.%d.XXXXXXXX", e2lib.globals.tmpdir, - e2util.getpid()) + e2lib.getpid()) end local cmd = string.format("mktemp '%s'", template) local mktemp = io.popen(cmd, "r") @@ -1404,11 +1596,18 @@ end -- temporary files. -- @param tmpfile File name to remove (string). function e2lib.rmtempfile(tmpfile) + local rc, re + for i,v in ipairs(e2lib.globals.tmpfiles) do if v == tmpfile then table.remove(e2lib.globals.tmpfiles, i) e2lib.logf(4, "removing temporary file: %s", tmpfile) - e2lib.rm(tmpfile, "-f") + if e2lib.exists(tmpfile) then + rc, re = e2lib.unlink(tmpfile) + if not rc then + e2lib.warnf(3, "could not remove tmpfile %q", tmpfile) + end + end end end end @@ -1422,7 +1621,7 @@ end function e2lib.mktempdir(template) if not template then template = string.format("%s/e2tmp.%d.XXXXXXXX", e2lib.globals.tmpdir, - e2util.getpid()) + e2lib.getpid()) end local cmd = string.format("mktemp -d '%s'", template) local mktemp = io.popen(cmd, "r") @@ -1444,11 +1643,18 @@ end -- list of temporary directories. -- @param tmpdir Directory name to remove (string). function e2lib.rmtempdir(tmpdir) + local rc, re + for i,v in ipairs(e2lib.globals.tmpdirs) do if v == tmpdir then table.remove(e2lib.globals.tmpdirs, i) e2lib.logf(4, "removing temporary directory: %s", tmpdir) - e2lib.rm(tmpdir, "-fr") + if e2lib.exists(tmpdir) then + rc, re = e2lib.unlink_recursive(tmpdir) + if not rc then + e2lib.warnf(3, "could not remove tmpdir %q", tmpdir) + end + end end end end @@ -1472,19 +1678,6 @@ function e2lib.rmtempfiles() end end ---- call the rm tool with flags and filename --- @param file string: the file parameter --- @param flags string: flags to pass to rm (optional) --- @return bool --- @return an error object on failure -function e2lib.rm(file, flags) - if not flags then - flags = "" - end - local args = string.format("%s %s", flags, file) - return e2lib.call_tool("rm", args) -end - --- call the touch tool with flags and filename -- @param file string: the file parameter -- @param flags string: flags to pass to touch (optional) @@ -1497,17 +1690,75 @@ function e2lib.touch(file, flags) return e2lib.call_tool("touch", args) end ---- call the rmdir command --- @param dir string: the directory name --- @param flags string: flags to pass to rmdir --- @return bool --- @return the last line ouf captured output -function e2lib.rmdir(dir, flags) - if not flags then - flags = "" +--- Remove regular and special files, except dirs. +-- @param pathname Path to file (string). +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.unlink(pathname) + local rc, errstring = le2lib.unlink(pathname) + + if not rc then + return false, err.new("could not remove file %s: %s", + pathname, errstring) end - local args = string.format("%s %s", flags, dir) - return e2lib.call_tool("rmdir", args) + + return true +end + +--- Remove directories and files recursively. +-- @param pathname Directory to delete. +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.unlink_recursive(pathname) + local de, rc, re + local filepath + + for file, re in e2lib.directory(pathname, true) do + if not file then + return false, re + end + + filepath = e2lib.join(pathname, file) + + de, re = e2lib.stat(filepath) + if not de then + return false, re + end + + if de.type == "directory" then + rc, re = e2lib.unlink_recursive(filepath) + if not rc then + return false, re + end + else + rc, re = e2lib.unlink(filepath) + if not rc then + return false, re + end + end + end + + rc, re = e2lib.rmdir(pathname) + if not rc then + return false, re + end + + return true +end + +--- Remove single empty directory. +-- @param dir Directory name (string). +-- @return True on success, false on error. +-- @return Error object on failure. +function e2lib.rmdir(dir) + local rc, errstring = le2lib.rmdir(dir) + + if not rc then + return false, err.new("could not remove directory %s: %s", + dir, errstring) + end + + return true end --- call the mkdir command @@ -1555,7 +1806,7 @@ function e2lib.call_tool(tool, args) call = string.format("%s %s %s", cmd, flags, args) rc, re = e2lib.callcmd_log(call) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, re end @@ -1589,7 +1840,7 @@ function e2lib.call_tool_argv(tool, argv) end rc, re = e2lib.callcmd_log(call) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, re end @@ -1657,7 +1908,7 @@ function e2lib.git(gitdir, subtool, args) call = string.format("GIT_DIR=%s %s %s %s", e2lib.shquote(gitdir), e2lib.shquote(git), e2lib.shquote(subtool), args) rc, re = e2lib.callcmd_log(call) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end @@ -1678,16 +1929,6 @@ function e2lib.svn(argv) return e2lib.call_tool_argv("svn", argv) end ---- call the ln command --- @param dst string: destination name --- @param link string: link name --- @return bool --- @return the last line of captured output -function e2lib.symlink(dst, link) - local args = string.format("-s '%s' '%s'", dst, link) - return e2lib.call_tool("ln", args) -end - --- call the chmod command -- @param mode string: the new mode -- @param path string: path @@ -1698,6 +1939,23 @@ function e2lib.chmod(mode, path) return e2lib.call_tool("chmod", args) end +--- Close all file descriptors equal or larger than "fd". +-- @param fd file descriptor (number) +-- @return True on success, false on error +-- @return Error object on failure. +-- @raise Error on invalid input. +function e2lib.closefrom(fd) + local rc, errstring + + rc, errstring = le2lib.closefrom(fd) + if not rc then + return false, err.new("closefrom(%d) failed: %s", + tonumber(fd), errstring) + end + + return true +end + --- call the mv command -- @param src string: source name -- @param dst string: destination name @@ -1724,20 +1982,6 @@ function e2lib.cp(src, dst, flags) return e2lib.call_tool("cp", args) end ---- call the ln command --- @param src string: source name --- @param dst string: destination name --- @param flags string: additional flags --- @return bool --- @return the last line ouf captured output -function e2lib.ln(src, dst, flags) - if not flags then - flags = "" - end - local args = string.format("%s '%s' '%s'", flags, src, dst) - return e2lib.call_tool("ln", args) -end - --- call the curl command -- @param argv table: argument vector -- @return bool @@ -1802,7 +2046,7 @@ end -- @param dir string: path -- @return bool function e2lib.isdir(dir) - local t = e2util.stat(dir, true) + local t = e2lib.stat(dir, true) if t and t.type == "directory" then return true end @@ -1814,7 +2058,7 @@ end -- @param dir string: path -- @return bool function e2lib.isfile(path) - local t = e2util.stat(path, true) + local t = e2lib.stat(path, true) if t and t.type == "regular" then return true end @@ -2076,7 +2320,7 @@ end -- @return an error object on failure function e2lib.chdir(path) local rc, re - rc, re = e2util.cd(path) + rc, re = le2lib.chdir(path) if not rc then return false, err.new("chdir %s failed: %s", path, re) end diff --git a/generic/e2option.lua b/generic/e2option.lua index 93c77e1..628c080 100644 --- a/generic/e2option.lua +++ b/generic/e2option.lua @@ -37,7 +37,6 @@ local err = require("err") local strict = require("strict") local tools = require("tools") local buildconfig = require("buildconfig") -require("e2util") local options = {} local aliases = {} @@ -224,7 +223,7 @@ local function userdefaultoptions(opts) end local file = home .. "/.e2/e2rc" - if not e2util.exists(file) then + if not e2lib.exists(file) then return true end diff --git a/generic/generic_git.lua b/generic/generic_git.lua index 1540b9f..e189eed 100644 --- a/generic/generic_git.lua +++ b/generic/generic_git.lua @@ -71,8 +71,8 @@ local function git_clone_url(surl, destdir, skip_checkout) local cmd = string.format("git clone %s --quiet %s %s", flags, e2lib.shquote(src), e2lib.shquote(destdir)) - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then return false, e:cat(re) end @@ -102,7 +102,7 @@ function generic_git.git_branch_new1(gitwc, track, branch, start_point) e2lib.shquote(gitwc), f_track, e2lib.shquote(branch), e2lib.shquote(start_point)) rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then e = err.new("creating new branch failed") return false, e:cat(re) end @@ -123,7 +123,7 @@ function generic_git.git_checkout1(gitwc, branch) cmd = string.format("cd %s && git checkout %s", e2lib.shquote(gitwc), e2lib.shquote(branch)) rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then e = err.new("git checkout failed") return false, e:cat(re) end @@ -209,7 +209,7 @@ function generic_git.git_init_db1(rurl) end rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end @@ -244,7 +244,7 @@ function generic_git.git_push1(gitdir, rurl, refspec) cmd = string.format("GIT_DIR=%s git push %s %s", e2lib.shquote(gitdir), e2lib.shquote(remote_git_url), e2lib.shquote(refspec)) rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end @@ -284,7 +284,7 @@ function generic_git.git_remote_add1(lurl, rurl, name) e2lib.shquote("/"..lrepo.path), e2lib.shquote(name), e2lib.shquote(giturl)) rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end @@ -411,9 +411,9 @@ function generic_git.git_config(gitdir, query) end local cmd = string.format("GIT_DIR=%s git config %s > %s", - e2lib.shquote(gitdir), e2lib.shquote(query), e2lib.shquote(tmpfile)) - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + e2lib.shquote(gitdir), e2lib.shquote(query), e2lib.shquote(tmpfile)) + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then e:append("git config failed") return nil, e end @@ -438,8 +438,8 @@ function generic_git.git_add(gitdir, args) end local cmd = string.format("GIT_DIR=%s git add %s", e2lib.shquote(gitdir), e2lib.shquote(args)) - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then return nil, e:cat(re) end return true, nil diff --git a/generic/e2util.c b/generic/le2lib.c similarity index 55% rename from generic/e2util.c rename to generic/le2lib.c index 651cd8a..c6f2242 100644 --- a/generic/e2util.c +++ b/generic/le2lib.c @@ -25,11 +25,6 @@ along with this program. If not, see . */ -/* - Low-level file-system and process operations. - */ - - #include #include #include @@ -47,16 +42,8 @@ #include #include - static char buffer[PATH_MAX + 1]; - -/* e2util.fork() -> pid - | nil, ERRORMESSAGE - - Forks a subprocess. - */ - static int lua_fork(lua_State *lua) { @@ -65,7 +52,7 @@ lua_fork(lua_State *lua) rc = fork(); if(rc < 0) { - lua_pushnil(lua); + lua_pushboolean(lua, 0); lua_pushstring(lua, strerror(errno)); return 2; } @@ -74,81 +61,23 @@ lua_fork(lua_State *lua) return 1; } - -/* e2util.cwd() -> STRING - - Returns the current working directory. - */ - static int get_working_directory(lua_State *lua) { char *cwd = getcwd(buffer, sizeof(buffer)); - if (cwd == NULL) - lua_pushnil(lua); - else - lua_pushstring(lua, buffer); - - return 1; -} - - -/* e2util.realpath(PATH) -> PATH' | nil - - If PATH names an existing object in the file-system, then this - function will return the absolute, canonical representation of PATH, - otherwise nil is returned. - */ + if (cwd == NULL) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); -static int -get_realpath(lua_State *lua) -{ - const char *p = luaL_checkstring(lua, 1); + return 2; + } - if (realpath(p, buffer) == NULL) - lua_pushnil(lua); - else - lua_pushstring(lua, buffer); + lua_pushstring(lua, buffer); return 1; } - -/* e2util.stat(PATH, [FOLLOWLINKS?]) -> TABLE | nil - - Returns stat(3) information for the file system object designated by PATH. - If FOLLOWLINKS? is not given or false, then the returned information will - apply to the actual symbolic link, if PATH designates one. Otherwise - the file pointed to by the link is taken. Returns a table with the - following entries: - - dev device-id (number) - ino inode-number (number) - mode permissions and access mode (number) - nlink number of hard links (number) - uid user id (number) - gid group id (number) - rdev device id for char of block special files (number) - size file size (number) - atime access time (number) - mtime modification time (number) - ctime change time (number) - blksize block size (number) - blocks number of blocks (number) - - type one of the following strings: - - block-special - character-special - fifo-special - regular - directory - symbolic-link - socket - unknown - */ - static int get_file_statistics(lua_State *lua) { @@ -164,7 +93,7 @@ get_file_statistics(lua_State *lua) } if (s < 0) { - lua_pushnil(lua); + lua_pushboolean(lua, 0); lua_pushstring(lua, strerror(errno)); return 2; } @@ -236,90 +165,58 @@ get_file_statistics(lua_State *lua) return 1; } - -/* e2util.readlink(PATH) -> PATH' | nil - - Returns the path pointed to by the symbolic link PATH or nil, if the - link does not exist. - */ - static int -read_symbolic_link(lua_State *lua) +get_directory(lua_State *lua) { const char *p = luaL_checkstring(lua, 1); - int len; - - len = readlink(p, buffer, sizeof(buffer)); + int df = lua_gettop(lua) > 1 && lua_toboolean(lua, 2); + DIR *dir = opendir(p); + struct dirent *de; + int i = 1; - if (len > -1) - lua_pushlstring(lua, buffer, len); - else - lua_pushnil(lua); + if (dir == NULL) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); - return 1; -} + return 2; + } + lua_newtable(lua); -/* e2util.directory(PATH, [DOTFILES?]) -> TABLE | nil + for (;;) { + errno = 0; + de = readdir(dir); - Returns an array with the contents of the directory designated by PATH. - If DOTFILES? is given and true then files beginning with "." are also - included in the directory listing. - */ + if (de == NULL) { + if (errno) { + lua_pop(lua, 1); /* remove table */ -static int -get_directory(lua_State *lua) -{ - const char *p = luaL_checkstring(lua, 1); - int df = lua_gettop(lua) > 1 && lua_toboolean(lua, 2); - DIR *dir = opendir(p); + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); - if (dir == NULL) - lua_pushnil(lua); - else { - struct dirent *de; - int i = 1; + closedir(dir); - lua_newtable(lua); + return 2; + } - for(;;) { - de = readdir(dir); + break; + } - if(de == NULL) break; + if (strcmp(de->d_name, ".") == 0 || + strcmp(de->d_name, "..") == 0) + continue; - if(df || de->d_name[0] != '.') { - lua_pushstring(lua, de->d_name); - lua_rawseti(lua, -2, i++); - } + if (df || de->d_name[0] != '.') { + lua_pushstring(lua, de->d_name); + lua_rawseti(lua, -2, i++); } - - closedir(dir); } - return 1; -} - + closedir(dir); -/* e2util.tempnam(DIR) -> PATH - - Returns a random temporary pathname. - */ - -static int -create_temporary_filename(lua_State *lua) -{ - const char *dir = luaL_checkstring(lua, 1); - lua_pushstring(lua, tempnam(dir, "e2")); return 1; } - -/* e2util.exists(PATH, [EXECUTABLE?]) -> BOOL - - Returns true if the file given in PATH exists. If EXECUTABLE? is given - and true, then it is also checked whether the file is executable. - */ - static int file_exists(lua_State *lua) { @@ -333,12 +230,6 @@ file_exists(lua_State *lua) return 1; } - -/* e2util.cd(PATH) - - Changes the current working directory to PATH. - */ - static int change_directory(lua_State *lua) { @@ -350,127 +241,45 @@ change_directory(lua_State *lua) lua_pushstring(lua, strerror(errno)); return 2; } + lua_pushboolean(lua, 1); - lua_pushnil(lua); - return 2; + return 1; } -/* e2util.symlink(OLDPATH, NEWPATH) - - Creates a symbolic link named NEWPATH which contains the string OLDPATH. - */ - static int create_symlink(lua_State *lua) { const char *old = luaL_checkstring(lua, 1); const char *new = luaL_checkstring(lua, 2); - lua_pushboolean(lua, symlink(old, new) == 0); - return 1; -} - + if (symlink(old, new) != 0) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); -/* e2util.pipe(COMMAND, [ARG...]) -> FDIN, FDOUT, FDERR, PID - | nil, ERRORMESSAGE + return 2; + } - Invokes a subcommand and returns two file-descriptors for writing to stdin - and/or reading from stdout/stderr of the executing subprocess, respectively. - File-descriptors are named as viewn from the child process. - */ + lua_pushboolean(lua, 1); + return 1; +} static int -run_pipe(lua_State *lua) +do_hardlink(lua_State *lua) { - int in[2], out[2], err[2]; - char **argv; - int n; - - if(pipe(in) != 0) - return 0; - - else if(pipe(out) != 0) { - close(in[0]); - close(in[1]); - return 0; - } - else if(pipe(err) != 0) { - close(out[0]); - close(out[1]); - close(in[0]); - close(in[1]); - return 0; - } - else { - fflush(0); - pid_t child = fork(); - - if (child < 0) { - close(in[0]); - close(in[1]); - close(out[0]); - close(out[1]); - close(err[0]); - close(err[1]); - goto fail; - } - else if (child == 0) { - close(in[1]); - - if(in[0] != STDIN_FILENO) { - dup2(in[0], STDIN_FILENO); - close(in[0]); - } - - close(out[0]); - - if (out[1] != STDOUT_FILENO) { - dup2(out[1], STDOUT_FILENO); - close(out[1]); - } - - close(err[0]); + const char *old = luaL_checkstring(lua, 1); + const char *new = luaL_checkstring(lua, 2); - if (err[1] != STDERR_FILENO) { - dup2(err[1], STDERR_FILENO); - close(err[1]); - } + if (link(old, new) != 0) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); - n = lua_gettop(lua); - argv = alloca(sizeof(*argv) * (n+1)); - argv[n] = NULL; - while (n > 0) { - argv[n-1] = (char *)luaL_checkstring(lua, n); - n -= 1; - } - execvp(argv[0], argv); - goto fail; - } - else { - close(in[0]); - close(out[1]); - close(err[1]); - lua_pushnumber(lua, in[1]); - lua_pushnumber(lua, out[0]); - lua_pushnumber(lua, err[0]); - lua_pushnumber(lua, child); - return 4; - } - } + return 2; + } -fail: - lua_pushnil(lua); - lua_pushstring(lua, strerror(errno)); - return 2; + lua_pushboolean(lua, 1); + return 1; } - -/* e2util.wait(PID) -> STATUS, PID - | nil, ERRORMESSAGE - - waits for process to terminate and returns exit code. - */ - static int process_wait(lua_State *lua) { @@ -478,104 +287,17 @@ process_wait(lua_State *lua) int rc, status; rc = waitpid(pid, &status, 0); if (rc < 0) { - lua_pushnil(lua); + lua_pushboolean(lua, 0); lua_pushstring(lua, strerror(errno)); return 2; } + lua_pushnumber(lua, WEXITSTATUS(status)); lua_pushnumber(lua, rc); - return 2; -} - - -/* e2util.read(FD, NUM) -> STRING - | nil, ERRORMESSAGE - - Reads characters from a file-descriptor. - */ - -static int -read_fd(lua_State *lua) -{ - int fd = luaL_checkinteger(lua, 1); - int n = luaL_checkinteger(lua, 2); - char *buf = (char *)malloc(n); - int m; - - if(buf == NULL) return 0; - - m = read(fd, buf, n); - - if (m < 0) { - lua_pushnil(lua); - lua_pushstring(lua, strerror(errno)); - free(buf); - return 2; - } - else - lua_pushlstring(lua, buf, m); - free(buf); - return 1; -} - - -/* e2util.write(FD, STRING, [NUM]) -> NUM' - | nil, ERRORMESSAGE - - Writes characters to a file-descriptor. - */ - -static int -write_fd(lua_State *lua) -{ - int fd = luaL_checkinteger(lua, 1); - size_t len; - const char *buf = luaL_checklstring(lua, 2, &len); - int n = lua_gettop(lua) > 2 ? luaL_checkinteger(lua, 3) : len; - int m; - - m = write(fd, buf, n); - - if (m < 0) { - lua_pushnil(lua); - lua_pushstring(lua, strerror(errno)); - return 2; - } - - lua_pushnumber(lua, m); - return 1; -} - - -/* e2util.close(FD) -> true - | false, ERRORMESSAGE - - Close file-descriptor, returning "false" if an error occurred or "true" - otherwise. - */ - -static int -close_fd(lua_State *lua) -{ - int fd = luaL_checkinteger(lua, 1); - - if (close(fd) < 0) { - lua_pushnil(lua); - lua_pushstring(lua, strerror(errno)); - return 2; - } - - lua_pushboolean(lua, 1); - return 1; + return 2; } -/* e2util.poll(TMO_MSEC, {FD...}) -> INDEX, POLLIN, POLLOUT - Returns 0 on timeout, <0 on error, otherwise indicates which FD triggered. - When muliple FDs triggered, only one is indicated. - With a FD given, two boolean values indicate read/writeability. - */ - static int poll_fd(lua_State *lua) { @@ -616,10 +338,6 @@ poll_fd(lua_State *lua) return 1; } -/* e2util.unblock(FD) - Set file to nonblocking mode - */ - static int unblock_fd(lua_State *lua) { @@ -629,26 +347,6 @@ unblock_fd(lua_State *lua) return 0; } - -/* e2util.isatty(FD) -> BOOL - - Returns true, if FD refers to a terminal device. - */ - -static int -is_terminal(lua_State *lua) -{ - int fd = luaL_checkinteger(lua, 1); - lua_pushboolean(lua, isatty(fd)); - return 1; -} - -/* e2util.umask(VAL) - - Set the umask to VAL - Returns the previous value of umask - */ - static int set_umask(lua_State *lua) { @@ -659,10 +357,6 @@ set_umask(lua_State *lua) return 1; } -/* e2util.setenv(var, val, overwrite) - -*/ - static int do_setenv(lua_State *lua) { @@ -676,10 +370,6 @@ do_setenv(lua_State *lua) } -/* e2util.unsetenv(var) - -*/ - static int do_unsetenv(lua_State *lua) { @@ -691,10 +381,6 @@ do_unsetenv(lua_State *lua) return 1; } -/* e2util.exec() - - call execvp() with the full argument list */ - static int do_exec(lua_State *lua) { @@ -718,23 +404,30 @@ do_exec(lua_State *lua) return 1; } -/* e2util.getpid() - - get the pid of the current process */ - static int do_getpid(lua_State *lua) { pid_t pid = getpid(); - if (pid < 0 ) - lua_pushnil(lua); - else - lua_pushinteger(lua, pid); + lua_pushinteger(lua, pid); return 1; } -/* e2util.signal_reset() - * Reset all (possible) signals back to their default settings - */ +static int +do_unlink(lua_State *lua) +{ + const char *pathname = luaL_checkstring(lua, 1); + + if (unlink(pathname) != 0) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); + + return 2; + } + + lua_pushboolean(lua, 1); + return 1; +} + +/* Reset all (possible) signals back to their default settings */ static int signal_reset(lua_State *L) { @@ -761,7 +454,6 @@ signal_reset(lua_State *L) } if (sigaction(s, &act, NULL) < 0) { - // fprintf(stderr, "%d is set to %p\n", s, (void *)act.sa_handler); lua_pushboolean(L, 0); lua_pushstring(L, strerror(errno)); return 2; @@ -773,15 +465,7 @@ signal_reset(lua_State *L) } -/* - * e2util.closefrom() closes all file descriptors >= * fd_from. - * closefrom() is commonly available on the BSDs, but on Linux we - * have to use this crutch (which fails when /proc is not mounted). - * - * Lua: - * e2util.closefrom(number) returns true OR false and an errno string. - * May throw an exception. - */ +/* closes all file descriptors >= fd */ static int closefrom(lua_State *L) { @@ -824,10 +508,44 @@ error: return 2; } -/* e2util.catch_interrupt() +static int +do_rmdir(lua_State *lua) +{ + const char *pathname = luaL_checkstring(lua, 1); + + if (rmdir(pathname) != 0) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); + + return 2; + } + + lua_pushboolean(lua, 1); + return 1; +} + +static int +do_kill(lua_State *lua) +{ + pid_t pid = luaL_checkinteger(lua, 1); + int sig = luaL_checkinteger(lua, 2); + + if (kill(pid, sig) < 0) { + lua_pushboolean(lua, 0); + lua_pushstring(lua, strerror(errno)); + + return 2; + } + + lua_pushboolean(lua, 1); + return 1; +} - Establish signal handler for SIGINT that aborts. */ +/* + * Hook that gets called once an interrupt has been requested. + * Calls e2lib.interrupt_hook() to deal with any cleanup that might be required. + */ static void lstop(lua_State *L, lua_Debug *ar) { lua_sethook(L, NULL, 0, 0); @@ -850,6 +568,10 @@ lstop(lua_State *L, lua_Debug *ar) { static lua_State *globalL; +/* + * Interrupt handler sets a hook to stop the interpreter from + * continuing normal execution at the next possible spot. + */ static void laction(int i) { /* Ignore further signals because lstop() should @@ -860,39 +582,42 @@ laction(int i) { static luaL_Reg lib[] = { + { "chdir", change_directory }, + { "closefrom", closefrom }, { "cwd", get_working_directory }, - { "realpath", get_realpath }, - { "stat", get_file_statistics }, - { "readlink", read_symbolic_link }, { "directory", get_directory }, - { "tempnam", create_temporary_filename }, { "exists", file_exists }, - { "cd", change_directory }, - { "symlink", create_symlink }, - { "pipe", run_pipe }, - { "wait", process_wait }, - { "read", read_fd }, - { "write", write_fd }, - { "close", close_fd }, - { "poll", poll_fd }, - { "unblock", unblock_fd }, { "fork", lua_fork }, - { "isatty", is_terminal }, - { "umask", set_umask }, - { "setenv", do_setenv }, - { "unsetenv", do_unsetenv }, - { "exec", do_exec }, { "getpid", do_getpid }, + { "hardlink", do_hardlink }, + { "kill", do_kill }, + { "poll", poll_fd }, + { "rmdir", do_rmdir }, + { "setenv", do_setenv }, { "signal_reset", signal_reset }, - { "closefrom", closefrom }, + { "stat", get_file_statistics }, + { "symlink", create_symlink }, + { "umask", set_umask }, + { "unblock", unblock_fd }, + { "unlink", do_unlink }, + { "wait", process_wait }, { NULL, NULL } }; -int luaopen_e2util(lua_State *lua) +int luaopen_le2lib(lua_State *lua) { - luaL_register(lua, "e2util", lib); + luaL_Reg *next; + + lua_newtable(lua); + for (next = &lib; next->name != NULL; next++) { + lua_pushcfunction(lua, next->func); + lua_setfield(lua, -2, next->name); + } + + /* Establish signal handler catching SIGINT for orderly shutdown */ globalL = lua; signal(SIGINT, laction); + return 1; } diff --git a/generic/plugin.lua b/generic/plugin.lua index 4a5b22c..40acc26 100644 --- a/generic/plugin.lua +++ b/generic/plugin.lua @@ -113,7 +113,7 @@ local function load_plugin(dir, p, ctx) e:append("a dependency of plugin %s is not a string", p) end - if not e2util.exists(string.format("%s/%s", dir, dep)) then + if not e2lib.exists(string.format("%s/%s", dir, dep)) then e:append("dependency %s of plugin %s is not installed", dep, p) end end diff --git a/generic/transport.lua b/generic/transport.lua index be7dc07..31febbb 100644 --- a/generic/transport.lua +++ b/generic/transport.lua @@ -303,7 +303,11 @@ function transport.push_file(sourcefile, durl, location, push_permissions, try_h local done = false local dst = e2lib.join(destdir, destname) if (not push_permissions) and try_hardlink then - rc, re = e2lib.ln(sourcefile, dst, "--force") + local dst = e2lib.join(destdir, destname) + if e2lib.exists(dst) then + e2lib.unlink(dst) -- ignore error, hardlink will fail + end + rc, re = e2lib.hardlink(sourcefile, dst) if rc then done = true else diff --git a/global/e2-fetch-project.lua b/global/e2-fetch-project.lua index 0744cc2..783c82e 100644 --- a/global/e2-fetch-project.lua +++ b/global/e2-fetch-project.lua @@ -195,7 +195,7 @@ local function e2_fetch_project(arg) local e2_install_e2 = string.format("%s %s/e2-install-e2", e2lib.shquote(buildconfig.LUA), e2lib.shquote(buildconfig.TOOLDIR)) rc, re = e2lib.callcmd_log(e2_install_e2) - if rc ~= 0 then + if not rc or rc ~= 0 then local e = err.new("installing local e2 failed") return false, e:cat(re) end diff --git a/global/e2-install-e2.lua b/global/e2-install-e2.lua index e794a02..71f7173 100644 --- a/global/e2-install-e2.lua +++ b/global/e2-install-e2.lua @@ -110,15 +110,19 @@ local function e2_install_e2(arg) -- version is 1 or 2 -- remove the old e2 source, installation and plugins, if it exists - rc, re = e2lib.rm(".e2/e2 .e2/bin .e2/lib .e2/plugins", "-fr") - if not rc then - return false, e:cat(re) + for _,dir in ipairs({".e2/e2", ".e2/bin", ".e2/lib", ".e2/plugins"}) do + if e2lib.exists(dir) then + rc, re = e2lib.unlink_recursive(dir) + if not rc then + return false, e:cat(re) + end + end end e2lib.logf(2, "installing local tools") local extensions - if e2util.exists(e2lib.globals.extension_config) then + if e2lib.exists(e2lib.globals.extension_config) then extensions, re = e2lib.read_extension_config() if not extensions then return false, e:cat(re) @@ -185,12 +189,16 @@ local function e2_install_e2(arg) local server = config.site.e2_server local location = string.format("%s/%s.git", config.site.e2_base, ex.name) local destdir = ex.name - rc, re = e2lib.rm(destdir, "-fr") - if not rc then - return false, e:cat(re) + + if e2lib.exists(destdir) then + rc, re = e2lib.unlink_recursive(destdir) + if not rc then + return false, e:cat(re) + end end + rc, re = generic_git.git_clone_from_server(scache, server, location, - destdir, false) + destdir, false) if not rc then return false, e:cat(re) end @@ -212,7 +220,7 @@ local function e2_install_e2(arg) local cmd = string.format("make PREFIX=%s BINDIR=%s local install-local", e2lib.shquote(buildconfig.PREFIX), e2lib.shquote(buildconfig.BINDIR)) rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end diff --git a/global/e2.lua b/global/e2.lua index 8d14885..fa6f7f7 100644 --- a/global/e2.lua +++ b/global/e2.lua @@ -32,7 +32,6 @@ local e2lib = require("e2lib") local e2option = require("e2option") local err = require("err") local buildconfig = require("buildconfig") -require("e2util") local function e2(arg) local rc, re = e2lib.init() @@ -81,7 +80,7 @@ local function e2(arg) end local env, cmd - if e2util.stat(e2call.globaltool) then + if e2lib.stat(e2call.globaltool) then e2call.tool = e2call.globaltool env = string.format("LUA_PATH='%s/?.lua' LUA_CPATH='%s/?.so'", buildconfig.LIBDIR, buildconfig.LIBDIR) @@ -89,7 +88,7 @@ local function e2(arg) e2call.arg_string) elseif not root then return false, err.new("%s is not a global tool and we're not in a project environment", e2call.toolname) - elseif root and e2util.stat(e2call.localtool) then + elseif root and e2lib.stat(e2call.localtool) then e2call.tool = e2call.localtool -- Search for .lc files, the local e2 may be of an older version env = "LUA_PATH='" .. root .. "/.e2/lib/e2/?.lc;" .. diff --git a/local/e2-new-source.lua b/local/e2-new-source.lua index 0c4fcda..01b2a03 100644 --- a/local/e2-new-source.lua +++ b/local/e2-new-source.lua @@ -76,7 +76,7 @@ local function path_to_url(path) end local u = url.parse(path) - local cwd = e2util.cwd() + local cwd = e2lib.cwd() if not u and cwd then return "file://" .. e2lib.join(cwd, path) end diff --git a/local/e2build.lua b/local/e2build.lua index 211b331..3f65fb1 100644 --- a/local/e2build.lua +++ b/local/e2build.lua @@ -72,10 +72,11 @@ local function linklast(info, r, return_flags) if not rc then return false, e:cat(re) end - rc, re = e2lib.rm(lnk, "-f") -- remove the old link - if not rc then - return false, e:cat(re) + + if e2lib.exists(lnk) then + e2lib.unlink(lnk) -- ignore errors, symlink will catch it end + rc, re = e2lib.symlink(dst, lnk) -- create the new link if not rc then return false, e:cat(re) @@ -434,7 +435,10 @@ local function runbuild(info, r, return_flags) out:flush() end e2tool.set_umask(info) - local rc = e2lib.callcmd_capture(cmd, logto) + rc, re = e2lib.callcmd_capture(cmd, logto) + if not rc then + return false, e:cat(re) + end e2tool.reset_umask(info) out:close() if rc ~= 0 then @@ -454,14 +458,14 @@ local function chroot_remove(info, r, return_flags) if not rc then return e:cat(re) end - rc, re = e2lib.rm(res.build_config.chroot_marker) + rc, re = e2lib.unlink(res.build_config.chroot_marker) if not rc then return false, e:cat(re) end local f = e2lib.join(info.root, "playground") - local s = e2util.stat(f) + local s = e2lib.stat(f) if s and s.type == "symbolic-link" then - local rc, e = e2lib.rm(f, "-f") + rc, re = e2lib.unlink(f) if not rc then return false, e:cat(re) end @@ -913,7 +917,7 @@ local function store_result(info, r, return_flags) e2lib.logf(3, "result file: %s", f) local s = e2lib.join(rfilesdir, f) local d = "result/files" - rc, re = e2lib.ln(s, d) + rc, re = e2lib.hardlink(s, d) if not rc then -- There are three reasons this might fail -- a) Legitimate IO etc. errors. @@ -1080,14 +1084,17 @@ local function collect_project(info, r, return_flags) return false, e:cat(re) end - local init_files = e2util.directory(e2lib.join(info.root, "/proj/init")) - for _,f in ipairs(init_files) do + for f, re in e2lib.directory(e2lib.join(info.root, "proj/init"), false) do + if not f then + return false, e:cat(re) + end + e2lib.logf(3, "init file: %s", f) local server = "." local location = e2lib.join("proj/init", f) local cache_flags = {} rc, re = info.cache:fetch_file(server, location, - destdir, nil, cache_flags) + destdir, nil, cache_flags) if not rc then return false, e:cat(re) end diff --git a/local/e2tool.lua b/local/e2tool.lua index 0975efa..3869de9 100644 --- a/local/e2tool.lua +++ b/local/e2tool.lua @@ -37,7 +37,6 @@ local environment = require("environment") local plugin = require("plugin") local url = require("url") local hash = require("hash") -require("e2util") local e2option = require("e2option") local generic_git = require("generic_git") local policy = require("policy") @@ -277,7 +276,7 @@ local function load_user_config(info, path, dest, index, var) local rc, re local e = err.new("loading configuration failed") e2lib.logf(3, "loading %s", path) - if not e2util.exists(path) then + if not e2lib.exists(path) then return false, e:append("file does not exist: %s", path) end @@ -609,14 +608,14 @@ end -- @param info function e2tool.set_umask(info) e2lib.logf(4, "setting umask to %04o", info.chroot_umask) - e2util.umask(info.chroot_umask) + e2lib.umask(info.chroot_umask) end -- set umask back to the value used on the host -- @param info function e2tool.reset_umask(info) e2lib.logf(4, "setting umask to %04o", info.host_umask) - e2util.umask(info.host_umask) + e2lib.umask(info.host_umask) end -- initialize the umask set/reset mechanism (i.e. store the host umask) @@ -626,7 +625,7 @@ local function init_umask(info) info.chroot_umask = 18 -- 022 octal -- save the umask value we run with - info.host_umask = e2util.umask(info.chroot_umask) + info.host_umask = e2lib.umask(info.chroot_umask) -- restore the previous umask value again e2tool.reset_umask(info) @@ -643,7 +642,12 @@ function e2tool.local_init(path, tool) local info = {} info.current_tool = tool - info.startup_cwd = e2util.cwd() + + rc, re = e2lib.cwd() + if not rc then + return false, e:cat(re) + end + info.startup_cwd = rc init_umask(info) @@ -920,9 +924,9 @@ local function gather_source_paths(info, basedir, sources) end local fullentry = e2lib.join(info.root, e2tool.sourcedir(entry)) - local s = e2util.stat(fullentry, false) + local s = e2lib.stat(fullentry, false) if s.type == "directory" then - if e2util.exists(e2tool.sourceconfig(entry)) then + if e2lib.exists(e2tool.sourceconfig(entry)) then table.insert(sources, entry) else -- try subfolder @@ -1110,9 +1114,9 @@ local function gather_result_paths(info, basedir, results) end local fullentry = e2lib.join(info.root, e2tool.resultdir(entry)) - local s = e2util.stat(fullentry, false) + local s = e2lib.stat(fullentry, false) if s.type == "directory" then - if e2util.exists(e2tool.resultconfig(entry)) then + if e2lib.exists(e2tool.resultconfig(entry)) then table.insert(results, entry) else -- try subfolder @@ -1464,7 +1468,7 @@ function e2tool.collect_project_info(info, skip_load_config) } for _,f in ipairs(deprecated_files) do local path = e2lib.join(info.root, f) - if e2util.exists(path) then + if e2lib.exists(path) then e2lib.warnf("WDEPRECATED", "File exists but is no longer used: `%s'", f) end end @@ -1970,10 +1974,9 @@ local function hashcache(info, file) if not p then return nil, e:cat(re) end - - local s, msg = e2util.stat(p) + local s, re = e2lib.stat(p) if not s then - return nil, err.new("%s: %s", p, msg) + return nil, e:cat(re) end local id = string.format("%s:%s", file.server, file.location) diff --git a/plugins/cvs.lua b/plugins/cvs.lua index 669fff1..89c89f5 100644 --- a/plugins/cvs.lua +++ b/plugins/cvs.lua @@ -197,7 +197,7 @@ function cvs.fetch_source(info, sourcename) e2lib.shquote(cvstool), cvsflags, e2lib.shquote(cvsroot), rev, e2lib.shquote(base), e2lib.shquote(src.module)) local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + if not rc or rc ~= 0 then return false, e:cat(re) end return true, nil @@ -254,8 +254,8 @@ function cvs.prepare_source(info, sourcename, source_set, buildpath) else return false, err.new("invalid build mode") end - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then return false, e:cat(re) end return true, nil @@ -282,13 +282,13 @@ function cvs.update(info, sourcename) return false, e:cat(re) end local cmd = string.format("cd %s && CVS_RSH=%s %s %s update -R", - e2lib.shquote(working), e2lib.shquote(rsh), e2lib.shquote(cvstool), - cvsflags) - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then - e:cat(re) - return false, e + e2lib.shquote(working), e2lib.shquote(rsh), e2lib.shquote(cvstool), + cvsflags) + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then + return false, e:cat(re) end + return true, nil end diff --git a/plugins/files.lua b/plugins/files.lua index 5b08374..9f5a3a4 100644 --- a/plugins/files.lua +++ b/plugins/files.lua @@ -365,9 +365,9 @@ function files.prepare_source(info, sourcename, sourceset, buildpath) if not symlink then symlink = buildpath .. "/" .. sourcename if file.unpack ~= sourcename then - if not e2util.symlink(file.unpack, symlink) then - return false, e:append("cannot create symlink: %s -> %s", symlink, - file.unpack) + rc, re = e2lib.symlink(file.unpack, symlink) + if not rc then + return false, e:cat(re) end end end diff --git a/plugins/git.lua b/plugins/git.lua index 9053b59..a915489 100644 --- a/plugins/git.lua +++ b/plugins/git.lua @@ -329,8 +329,16 @@ function git.prepare_source(info, sourcename, sourceset, buildpath) elseif sourceset == "working-copy" then -- warn for empty working-copy local working = string.format("%s/%s", info.root, src.working) - local d = e2util.directory(working, false) - if #d == 0 then + local empty = true + for f, re in e2lib.directory(working, false) do + if not f then + return false, e:cat(re) + end + + empty = false + break + end + if empty then e2lib.warnf("WOTHER", "in result: %s", src.name) e2lib.warnf("WOTHER", "working copy seems empty") end @@ -539,8 +547,8 @@ function git.toresult(info, sourcename, sourceset, directory) return false, e:append("sourceset not supported: %s", sourceset) end - local rc, re = e2lib.callcmd_log(cmd) - if rc ~= 0 then + rc, re = e2lib.callcmd_log(cmd) + if not rc or rc ~= 0 then return false, e:cat(re) end local fname = string.format("%s/%s", directory, makefile) -- 2.39.5