151 lines
4.3 KiB
Plaintext
151 lines
4.3 KiB
Plaintext
--:Minify:--
|
|
local name = syscall.getTask(syscall.getpid()).name
|
|
local cloptions = { R = false, help = false }
|
|
local args = {}
|
|
|
|
for _, v in ipairs({ ... }) do
|
|
if v:sub(1, 2) == "--" then
|
|
local opt = v:sub(3)
|
|
if cloptions[opt] == nil then
|
|
print(name .. ": unrecognized option '" .. v .. "'")
|
|
print("try '" .. name .. " --help' for more information.")
|
|
syscall.exit(1); return
|
|
end
|
|
cloptions[opt] = true
|
|
elseif v:sub(1, 1) == "-" then
|
|
for i = 2, #v do
|
|
local opt = v:sub(i, i)
|
|
if cloptions[opt] == nil then
|
|
print(name .. ": invalid option '-" .. opt .. "'")
|
|
print("try '" .. name .. " --help' for more information.")
|
|
syscall.exit(1); return
|
|
end
|
|
cloptions[opt] = true
|
|
end
|
|
else
|
|
table.insert(args, v)
|
|
end
|
|
end
|
|
|
|
if cloptions.help then
|
|
print("Usage: " .. name .. " [OPTION]... OWNER[:GROUP] FILE...")
|
|
print(" " .. name .. " [OPTION]... :GROUP FILE...")
|
|
print("Change the owner and/or group of each FILE.")
|
|
print("OWNER and GROUP may be names or numeric IDs.")
|
|
print("")
|
|
print("Options:")
|
|
print(" -R operate on files and directories recursively")
|
|
print(" --help display this help and exit")
|
|
return
|
|
end
|
|
|
|
if #args < 2 then
|
|
print(name .. ": missing operand")
|
|
print("try '" .. name .. " --help' for more information.")
|
|
syscall.exit(1); return
|
|
end
|
|
|
|
local spec = args[1]
|
|
local ownerStr, groupStr
|
|
|
|
if spec:sub(1,1) == ":" then
|
|
groupStr = spec:sub(2)
|
|
else
|
|
local colon = spec:find(":", 1, true)
|
|
if colon then
|
|
ownerStr = spec:sub(1, colon - 1)
|
|
groupStr = spec:sub(colon + 1)
|
|
if groupStr == "" then groupStr = nil end
|
|
else
|
|
ownerStr = spec
|
|
end
|
|
end
|
|
|
|
local function resolveUid(s)
|
|
if not s or s == "" then return nil end
|
|
local n = tonumber(s)
|
|
if n then return n end
|
|
local uid = syscall.getuidbyname and syscall.getuidbyname(s)
|
|
if uid then return uid end
|
|
print(name .. ": invalid user: '" .. s .. "'")
|
|
syscall.exit(1)
|
|
end
|
|
|
|
local function resolveGid(s)
|
|
if not s or s == "" then return nil end
|
|
local n = tonumber(s)
|
|
if n then return n end
|
|
local uid = syscall.getuidbyname and syscall.getuidbyname(s)
|
|
if uid then
|
|
local pwent = syscall.getpasswd(uid)
|
|
if pwent then return pwent.gid end
|
|
end
|
|
print(name .. ": invalid group: '" .. s .. "'")
|
|
syscall.exit(1)
|
|
end
|
|
|
|
local newUid = resolveUid(ownerStr)
|
|
local newGid = resolveGid(groupStr)
|
|
|
|
if newUid == nil and newGid == nil then
|
|
print(name .. ": no owner or group specified")
|
|
syscall.exit(1); return
|
|
end
|
|
|
|
local function chownPath(path)
|
|
local stat = syscall.stat(path)
|
|
if not stat then
|
|
print(name .. ": cannot stat '" .. path .. "': no such file or directory")
|
|
return false
|
|
end
|
|
local uid = newUid ~= nil and newUid or stat.owner
|
|
local gid = newGid ~= nil and newGid or stat.group
|
|
local ok, err = pcall(syscall.chown, path, uid, gid)
|
|
if not ok then
|
|
local msg = tostring(err)
|
|
if msg:find("EPERM") or msg:find("EACCES") then
|
|
msg = "operation not permitted (must be root)"
|
|
elseif msg:find("ENOENT") then
|
|
msg = "no such file or directory"
|
|
end
|
|
print(name .. ": cannot change owner of '" .. path .. "': " .. msg)
|
|
return false
|
|
end
|
|
return true
|
|
end
|
|
|
|
local function chownRecursive(path)
|
|
if not chownPath(path) then return end
|
|
if syscall.type(path) == "directory" then
|
|
local ok, list = pcall(syscall.listdir, path)
|
|
if ok then
|
|
for _, entry in ipairs(list) do
|
|
local child = path
|
|
if child:sub(-1) ~= "/" then child = child .. "/" end
|
|
chownRecursive(child .. entry)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local cwd = syscall.getcwd()
|
|
local function absPath(p)
|
|
if p:sub(1,1) ~= "/" then p = cwd .. "/" .. p end
|
|
return p
|
|
end
|
|
|
|
local exitCode = 0
|
|
for i = 2, #args do
|
|
local path = absPath(args[i])
|
|
if not syscall.exists(path) then
|
|
print(name .. ": cannot access '" .. args[i] .. "': No such file or directory")
|
|
exitCode = 1
|
|
elseif cloptions.R then
|
|
chownRecursive(path)
|
|
else
|
|
if not chownPath(path) then exitCode = 1 end
|
|
end
|
|
end
|
|
|
|
syscall.exit(exitCode)
|