Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
executable file 197 lines (161 sloc) 5.3 KB
#!/bin/sh
_=[[
. "${0%/*}/regress.sh"
exec runlua -r5.2 "$0" "$@"
]]
local unix = require"unix"
local regress = require"regress".export".*"
regress.setmpsafe(true)
local fmt = string.format
local pow = math.pow or function (x, y) return x^y end
local function checkf(what, v, ...)
if v then
info("%s: OK", what)
return v, ...
else
regress.panic("%s: %s", what, ...)
end
end
local function stroflags(flags)
local names = {}
for k,v in pairs(unix) do
if type(k) == "string" and type(v) == "number" then
if k:match"^O_" and 0 ~= unix.bitand(flags, v) then
names[#names + 1] = k
flags = unix.bitand(flags, unix.compl(v))
end
end
end
-- NB: on AIX flags can be greater than 2^32-1
for i=0,31 do
local flag = pow(2, i)
if 0 ~= unix.bitand(flag, flags) then
names[#names + 1] = fmt("0x%.8x", flag)
end
end
return table.concat(names,"|")
end
local function strsigname(signo)
for k,v in pairs(unix) do
if type(k) == "string" and k:match"^SIG[^_]" and v == signo then
return k
end
end
return fmt("SIG(%d)", signo)
end
local NSLAVES = 3
local NHUPS = NSLAVES
local NALRMS = NSLAVES - NHUPS --> 0
local CLOSE_MTTY = { [1] = true, [2] = false, [3] = true }
local CLOSE_STTY = { [1] = true, [2] = true, [3] = true }
local REOPEN_STTY = { [1] = true, [2] = false, [3] = false }
local pipe_rd, pipe_wr = check(unix.fpipe())
pipe_wr:setvbuf"line"
local mtty_pid = unix.fork()
if mtty_pid > 0 then
info("forked leader %d", mtty_pid)
check(unix.close(pipe_wr))
local _, how, status = check(unix.waitpid(mtty_pid))
check(how == "exited" and status == 0, "session leader died (%s with %d)", how, status or -1)
local rcvd = { SIGHUP = 0, SIGALRM = 0 }
for sig in pipe_rd:lines() do
if rcvd[sig] then
rcvd[sig] = rcvd[sig] + 1
else
info("%s: unexpected signal", sig)
end
end
check(NHUPS == rcvd.SIGHUP, "expected %d SIGHUPs, got %d", NHUPS, rcvd.SIGHUP)
check(NALRMS == rcvd.SIGALRM, "expected %d SIGALRMSs, got %d", NALRMS, rcvd.SIGALRM)
say"OK"
os.exit(0)
end
check(unix.close(pipe_rd))
regress.logpid = true
--
-- Become leader of new session and process group, disassociated from any
-- controlling terminal.
--
checkf("setsid", unix.setsid())
info("%d is session leader", unix.getpid())
--
-- Create a new pty master/slave pair.
--
-- POSIX leaves as implemented-defined how to assign a controlling terminal
-- to a session. See 11.1.3 The Controlling Terminal in IEEE Std
-- 1003.1-2013. AFAIU, some systems require TIOCSCTTY, while others
-- automatically make the first pty opened the controlling terminal.
--
-- For our test, if TIOCSCTTY is defined then we'll open the pty with
-- O_NOCTTY and use TIOCSCTTY. Otherwise we won't specify O_NOCTTY and
-- assume that opening the slave pty will make it the controlling terminal.
-- Note that these are not the only possible implementation permutations.
--
local mtty_flags = unix.bitor(unix.O_RDWR, unix.O_NOCTTY)
local mtty_how = fmt("posix_openpt(%s)", stroflags(mtty_flags))
local mtty = checkf(mtty_how, unix.posix_openpt(unix.bitor(unix.O_RDWR, unix.O_NOCTTY)))
checkf("grantpt", unix.grantpt(mtty))
checkf("unlockpt", unix.unlockpt(mtty))
local stty_path = checkf("ptsname", unix.ptsname(mtty))
local stty_flags = unix.bitor(unix.O_RDWR, unix.TIOCSCTTY and unix.O_NOCTTY or 0)
local stty_how = fmt("open(%s, %s)", stty_path, stroflags(stty_flags))
local stty = checkf(stty_how, unix.open(stty_path, stty_flags))
--
-- Set slave pty as controlling terminal of our session. The foreground
-- process group of the terminal will be initialized to our current process
-- group.
--
info("tcgetpgrp: %s", tostring(unix.tcgetpgrp(stty)))
if unix.TIOCSCTTY then
checkf("TIOCSCTTY", unix.ioctl(stty, unix.TIOCSCTTY))
info("tcgetpgrp: %s", tostring(unix.tcgetpgrp(stty)))
end
-- tcsetpgrp is probably a noop at this point
checkf("tcsetpgrp", unix.tcsetpgrp(stty, unix.getpgrp()))
info("tcgetpgrp: %s", tostring(unix.tcgetpgrp(stty)))
--
-- Fork children to test SIGHUP.
--
-- POSIX doesn't require SIGHUP to be sent to processes in the foreground
-- process group. It only requires SIGHUP to be sent to the controlling
-- terminal. See 11.1.10 Modem Disconnect in IEEE Std 1003.1-2013. But
-- sending SIGHUP to the foreground process group is historical behavior and
-- what we're expecting to happen.
--
for i=1,NSLAVES do
unix.sigprocmask(unix.SIG_BLOCK, "*");
local stty_pid = check(unix.fork())
if stty_pid == 0 then
-- it shouldn't matter whether we close the master tty
if CLOSE_MTTY[i] then
checkf("close", unix.close(mtty))
info"closed master tty"
end
-- we expect SIGHUP to be sent to all processes if at least
-- one process has the slave tty open
if CLOSE_STTY[i] then
checkf(fmt("close(%s)", stty_path), unix.close(stty))
if REOPEN_STTY[i] then
stty = checkf(stty_how, unix.open(stty_path, stty_flags))
else
info("skipping slave tty reopen")
end
end
local timeout = 3
unix.alarm(timeout);
local unblock = unix.sigemptyset()
unix.sigaddset(unblock, unix.SIGHUP)
unix.sigaddset(unblock, unix.SIGALRM)
local signo = check(unix.sigtimedwait(unblock, timeout + 1))
info("rcvd %s", strsigname(signo))
pipe_wr:write(strsigname(signo), "\n")
info"exiting"
os.exit(0)
else
info("leader forked %d", stty_pid)
end
end
-- give children time to finish any tty manipulations
unix.sleep(1)
info"exiting"
os.exit(0)