Skip to content

Commit 576bc5a

Browse files
committed
Add os.login_tty() for Unix.
Signed-off-by: Soumendra Ganguly <[email protected]>
1 parent be36e06 commit 576bc5a

File tree

5 files changed

+250
-16
lines changed

5 files changed

+250
-16
lines changed

Doc/library/os.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -991,6 +991,17 @@ as internal buffering of data.
991991
.. versionadded:: 3.3
992992

993993

994+
.. function:: login_tty(fd)
995+
996+
Prepare the tty of which fd is a file descriptor for a new login session.
997+
Make the calling process a session leader; make the tty the controlling tty,
998+
the stdin, the stdout, and the stderr of the calling process; close fd.
999+
1000+
.. availability:: Unix.
1001+
1002+
.. versionadded:: 3.11
1003+
1004+
9941005
.. function:: lseek(fd, pos, how)
9951006

9961007
Set the current position of file descriptor *fd* to position *pos*, modified

Modules/clinic/posixmodule.c.h

Lines changed: 40 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Modules/posixmodule.c

Lines changed: 92 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7196,22 +7196,21 @@ os_sched_getaffinity_impl(PyObject *module, pid_t pid)
71967196
# define DEV_PTY_FILE "/dev/ptmx"
71977197
#endif
71987198

7199-
#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX)
7200-
#ifdef HAVE_PTY_H
7199+
#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX)
7200+
#if defined(HAVE_PTY_H)
72017201
#include <pty.h>
7202-
#else
7203-
#ifdef HAVE_LIBUTIL_H
7202+
#if defined(HAVE_UTMP_H)
7203+
#include <utmp.h>
7204+
#endif /* HAVE_UTMP_H */
7205+
#elif defined(HAVE_LIBUTIL_H)
72047206
#include <libutil.h>
7205-
#else
7206-
#ifdef HAVE_UTIL_H
7207+
#elif defined(HAVE_UTIL_H)
72077208
#include <util.h>
7208-
#endif /* HAVE_UTIL_H */
7209-
#endif /* HAVE_LIBUTIL_H */
72107209
#endif /* HAVE_PTY_H */
7211-
#ifdef HAVE_STROPTS_H
7210+
#if defined(HAVE_STROPTS_H)
72127211
#include <stropts.h>
72137212
#endif
7214-
#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX) */
7213+
#endif /* if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) */
72157214

72167215

72177216
#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)
@@ -7314,6 +7313,86 @@ os_openpty_impl(PyObject *module)
73147313
#endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */
73157314

73167315

7316+
#if defined(HAVE_SETSID)
7317+
#if defined(TIOCSCTTY) || defined(HAVE_TTYNAME)
7318+
#define HAVE_FALLBACK_LOGIN_TTY 1
7319+
#endif /* defined(TIOCSCTTY) || defined(HAVE_TTYNAME) */
7320+
#endif /* HAVE_SETSID */
7321+
7322+
#if defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY)
7323+
/*[clinic input]
7324+
os.login_tty
7325+
7326+
fd: fildes
7327+
/
7328+
7329+
Prepare the tty of which fd is a file descriptor for a new login session.
7330+
7331+
Make the calling process a session leader; make the tty the
7332+
controlling tty, the stdin, the stdout, and the stderr of the
7333+
calling process; close fd.
7334+
[clinic start generated code]*/
7335+
7336+
static PyObject *
7337+
os_login_tty_impl(PyObject *module, int fd)
7338+
/*[clinic end generated code: output=495a79911b4cc1bc input=5f298565099903a2]*/
7339+
{
7340+
#if defined(HAVE_LOGIN_TTY)
7341+
if (login_tty(fd) == -1) {
7342+
return posix_error();
7343+
}
7344+
#else /* defined(HAVE_FALLBACK_LOGIN_TTY) */
7345+
/* Establish a new session. */
7346+
if (setsid() == -1) {
7347+
return posix_error();
7348+
}
7349+
7350+
/* The tty becomes the controlling terminal. */
7351+
#if defined(TIOCSCTTY)
7352+
if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) {
7353+
return posix_error();
7354+
}
7355+
#else /* defined(HAVE_TTYNAME) */
7356+
/* Fallback method (archaic); from Advanced Programming in the UNIX(R)
7357+
* Environment, Third edition, 2013, Section 9.6 - Controlling Terminal:
7358+
* "Systems derived from UNIX System V allocate the controlling
7359+
* terminal for a session when the session leader opens the first
7360+
* terminal device that is not already associated with a session, as
7361+
* long as the call to open does not specify the O_NOCTTY flag." */
7362+
char *tmppath = ttyname(fd);
7363+
if (tmppath == NULL) {
7364+
return posix_error();
7365+
}
7366+
7367+
#define CLOSE_IF_NOT_FD(otherfd) \
7368+
if (fd != otherfd) { \
7369+
close(otherfd); \
7370+
} \
7371+
7372+
CLOSE_IF_NOT_FD(0);
7373+
CLOSE_IF_NOT_FD(1);
7374+
CLOSE_IF_NOT_FD(2);
7375+
7376+
int tmpfd = open(tmppath, O_RDWR);
7377+
if (tmpfd == -1) {
7378+
return posix_error();
7379+
}
7380+
close(tmpfd);
7381+
#endif /* defined(TIOCSCTTY) */
7382+
7383+
/* The tty becomes stdin/stdout/stderr */
7384+
if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1) {
7385+
return posix_error();
7386+
}
7387+
if (fd > 2) {
7388+
close(fd);
7389+
}
7390+
#endif /* defined(HAVE_LOGIN_TTY) */
7391+
Py_RETURN_NONE;
7392+
}
7393+
#endif /* defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) */
7394+
7395+
73177396
#ifdef HAVE_FORKPTY
73187397
/*[clinic input]
73197398
os.forkpty
@@ -7349,8 +7428,9 @@ os_forkpty_impl(PyObject *module)
73497428
/* parent: release the import lock. */
73507429
PyOS_AfterFork_Parent();
73517430
}
7352-
if (pid == -1)
7431+
if (pid == -1) {
73537432
return posix_error();
7433+
}
73547434
return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd);
73557435
}
73567436
#endif /* HAVE_FORKPTY */
@@ -14745,6 +14825,7 @@ static PyMethodDef posix_methods[] = {
1474514825
OS_SCHED_SETAFFINITY_METHODDEF
1474614826
OS_SCHED_GETAFFINITY_METHODDEF
1474714827
OS_OPENPTY_METHODDEF
14828+
OS_LOGIN_TTY_METHODDEF
1474814829
OS_FORKPTY_METHODDEF
1474914830
OS_GETEGID_METHODDEF
1475014831
OS_GETEUID_METHODDEF

configure

Lines changed: 99 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8176,7 +8176,7 @@ sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/ioctl.h \
81768176
sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \
81778177
sys/param.h sys/random.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
81788178
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
8179-
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
8179+
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h utmp.h \
81808180
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
81818181
linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
81828182
sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \
@@ -14023,7 +14023,7 @@ fi
1402314023

1402414024

1402514025

14026-
# check for openpty and forkpty
14026+
# check for openpty, login_tty, and forkpty
1402714027

1402814028
for ac_func in openpty
1402914029
do :
@@ -14119,6 +14119,103 @@ fi
1411914119
fi
1412014120

1412114121

14122+
fi
14123+
done
14124+
14125+
for ac_func in login_tty
14126+
do :
14127+
ac_fn_c_check_func "$LINENO" "login_tty" "ac_cv_func_login_tty"
14128+
if test "x$ac_cv_func_login_tty" = xyes; then :
14129+
cat >>confdefs.h <<_ACEOF
14130+
#define HAVE_LOGIN_TTY 1
14131+
_ACEOF
14132+
14133+
else
14134+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for login_tty in -lutil" >&5
14135+
$as_echo_n "checking for login_tty in -lutil... " >&6; }
14136+
if ${ac_cv_lib_util_login_tty+:} false; then :
14137+
$as_echo_n "(cached) " >&6
14138+
else
14139+
ac_check_lib_save_LIBS=$LIBS
14140+
LIBS="-lutil $LIBS"
14141+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
14142+
/* end confdefs.h. */
14143+
14144+
/* Override any GCC internal prototype to avoid an error.
14145+
Use char because int might match the return type of a GCC
14146+
builtin and then its argument prototype would still apply. */
14147+
#ifdef __cplusplus
14148+
extern "C"
14149+
#endif
14150+
char login_tty ();
14151+
int
14152+
main ()
14153+
{
14154+
return login_tty ();
14155+
;
14156+
return 0;
14157+
}
14158+
_ACEOF
14159+
if ac_fn_c_try_link "$LINENO"; then :
14160+
ac_cv_lib_util_login_tty=yes
14161+
else
14162+
ac_cv_lib_util_login_tty=no
14163+
fi
14164+
rm -f core conftest.err conftest.$ac_objext \
14165+
conftest$ac_exeext conftest.$ac_ext
14166+
LIBS=$ac_check_lib_save_LIBS
14167+
fi
14168+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_login_tty" >&5
14169+
$as_echo "$ac_cv_lib_util_login_tty" >&6; }
14170+
if test "x$ac_cv_lib_util_login_tty" = xyes; then :
14171+
$as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h
14172+
LIBS="$LIBS -lutil"
14173+
else
14174+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for login_tty in -lbsd" >&5
14175+
$as_echo_n "checking for login_tty in -lbsd... " >&6; }
14176+
if ${ac_cv_lib_bsd_login_tty+:} false; then :
14177+
$as_echo_n "(cached) " >&6
14178+
else
14179+
ac_check_lib_save_LIBS=$LIBS
14180+
LIBS="-lbsd $LIBS"
14181+
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
14182+
/* end confdefs.h. */
14183+
14184+
/* Override any GCC internal prototype to avoid an error.
14185+
Use char because int might match the return type of a GCC
14186+
builtin and then its argument prototype would still apply. */
14187+
#ifdef __cplusplus
14188+
extern "C"
14189+
#endif
14190+
char login_tty ();
14191+
int
14192+
main ()
14193+
{
14194+
return login_tty ();
14195+
;
14196+
return 0;
14197+
}
14198+
_ACEOF
14199+
if ac_fn_c_try_link "$LINENO"; then :
14200+
ac_cv_lib_bsd_login_tty=yes
14201+
else
14202+
ac_cv_lib_bsd_login_tty=no
14203+
fi
14204+
rm -f core conftest.err conftest.$ac_objext \
14205+
conftest$ac_exeext conftest.$ac_ext
14206+
LIBS=$ac_check_lib_save_LIBS
14207+
fi
14208+
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_login_tty" >&5
14209+
$as_echo "$ac_cv_lib_bsd_login_tty" >&6; }
14210+
if test "x$ac_cv_lib_bsd_login_tty" = xyes; then :
14211+
$as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h
14212+
LIBS="$LIBS -lbsd"
14213+
fi
14214+
14215+
14216+
fi
14217+
14218+
1412214219
fi
1412314220
done
1412414221

configure.ac

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2158,7 +2158,7 @@ sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/ioctl.h \
21582158
sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \
21592159
sys/param.h sys/random.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \
21602160
sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \
2161-
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \
2161+
sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h utmp.h \
21622162
libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \
21632163
linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \
21642164
sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \
@@ -4081,14 +4081,20 @@ PY_CHECK_FUNC([setgroups], [
40814081
#endif
40824082
])
40834083

4084-
# check for openpty and forkpty
4084+
# check for openpty, login_tty, and forkpty
40854085

40864086
AC_CHECK_FUNCS(openpty,,
40874087
AC_CHECK_LIB(util,openpty,
40884088
[AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lutil"],
40894089
AC_CHECK_LIB(bsd,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lbsd"])
40904090
)
40914091
)
4092+
AC_CHECK_FUNCS(login_tty,,
4093+
AC_CHECK_LIB(util,login_tty,
4094+
[AC_DEFINE(HAVE_LOGIN_TTY) LIBS="$LIBS -lutil"],
4095+
AC_CHECK_LIB(bsd,login_tty, [AC_DEFINE(HAVE_LOGIN_TTY) LIBS="$LIBS -lbsd"])
4096+
)
4097+
)
40924098
AC_CHECK_FUNCS(forkpty,,
40934099
AC_CHECK_LIB(util,forkpty,
40944100
[AC_DEFINE(HAVE_FORKPTY) LIBS="$LIBS -lutil"],

0 commit comments

Comments
 (0)