From ddc3219f3a08d55a225e86fcfd4396fcdc6e51d2 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Thu, 17 Dec 2020 03:23:48 -0600 Subject: [PATCH 1/4] Soumendra Ganguly: add os.login_tty() for *nix. Signed-off-by: Soumendra Ganguly --- Doc/library/os.rst | 11 ++ .../2020-12-11-04-56-12.bpo-41818.bVX3sO.rst | 1 + Modules/clinic/posixmodule.c.h | 41 ++++++- Modules/posixmodule.c | 101 ++++++++++++++++-- configure | 101 +++++++++++++++++- 5 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2020-12-11-04-56-12.bpo-41818.bVX3sO.rst diff --git a/Doc/library/os.rst b/Doc/library/os.rst index a4c5fbb481521e..3c4b0d529312bc 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -990,6 +990,17 @@ as internal buffering of data. .. versionadded:: 3.3 +.. function:: login_tty(fd) + + Prepare the tty of which fd is a file descriptor for a new login session. + Make the calling process a session leader; make the tty the controlling tty, + the stdin, the stdout, and the stderr of the calling process; close fd. + + .. availability:: Unix. + + .. versionadded:: 3.10 + + .. function:: lseek(fd, pos, how) Set the current position of file descriptor *fd* to position *pos*, modified diff --git a/Misc/NEWS.d/next/Library/2020-12-11-04-56-12.bpo-41818.bVX3sO.rst b/Misc/NEWS.d/next/Library/2020-12-11-04-56-12.bpo-41818.bVX3sO.rst new file mode 100644 index 00000000000000..8fec11fbe4fb5e --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-12-11-04-56-12.bpo-41818.bVX3sO.rst @@ -0,0 +1 @@ +Soumendra Ganguly: New function os.login_tty() for Unix. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 4a72ea0dd56f43..5015da70b53ae0 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -3029,6 +3029,41 @@ os_openpty(PyObject *module, PyObject *Py_UNUSED(ignored)) #endif /* (defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX)) */ +#if (defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY)) + +PyDoc_STRVAR(os_login_tty__doc__, +"login_tty($module, fd, /)\n" +"--\n" +"\n" +"Prepare the tty of which fd is a file descriptor for a new login session.\n" +"\n" +"Make the calling process a session leader; make the tty the\n" +"controlling tty, the stdin, the stdout, and the stderr of the\n" +"calling process; close fd."); + +#define OS_LOGIN_TTY_METHODDEF \ + {"login_tty", (PyCFunction)os_login_tty, METH_O, os_login_tty__doc__}, + +static PyObject * +os_login_tty_impl(PyObject *module, int fd); + +static PyObject * +os_login_tty(PyObject *module, PyObject *arg) +{ + PyObject *return_value = NULL; + int fd; + + if (!_PyLong_FileDescriptor_Converter(arg, &fd)) { + goto exit; + } + return_value = os_login_tty_impl(module, fd); + +exit: + return return_value; +} + +#endif /* (defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY)) */ + #if defined(HAVE_FORKPTY) PyDoc_STRVAR(os_forkpty__doc__, @@ -8764,6 +8799,10 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #define OS_OPENPTY_METHODDEF #endif /* !defined(OS_OPENPTY_METHODDEF) */ +#ifndef OS_LOGIN_TTY_METHODDEF + #define OS_LOGIN_TTY_METHODDEF +#endif /* !defined(OS_LOGIN_TTY_METHODDEF) */ + #ifndef OS_FORKPTY_METHODDEF #define OS_FORKPTY_METHODDEF #endif /* !defined(OS_FORKPTY_METHODDEF) */ @@ -9163,4 +9202,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=f3ec08afcd6cd8f8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f9f9bf32d1318d82 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d9eb62f20e65bd..3e0530f77683be 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7118,22 +7118,21 @@ os_sched_getaffinity_impl(PyObject *module, pid_t pid) # define DEV_PTY_FILE "/dev/ptmx" #endif -#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX) -#ifdef HAVE_PTY_H +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) +#if defined(HAVE_PTY_H) #include -#else -#ifdef HAVE_LIBUTIL_H +#if defined(HAVE_UTMP_H) +#include +#endif /* HAVE_UTMP_H */ +#elif defined(HAVE_LIBUTIL_H) #include -#else -#ifdef HAVE_UTIL_H +#elif defined(HAVE_UTIL_H) #include -#endif /* HAVE_UTIL_H */ -#endif /* HAVE_LIBUTIL_H */ #endif /* HAVE_PTY_H */ #ifdef HAVE_STROPTS_H #include #endif -#endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX) */ +#endif /* if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) */ #if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) @@ -7235,6 +7234,84 @@ os_openpty_impl(PyObject *module) } #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ +#if defined(HAVE_SETSID) +#if defined(TIOCSCTTY) || defined(HAVE_TTYNAME) +#define HAVE_FALLBACK_LOGIN_TTY 1 +#endif /* defined(TIOCSCTTY) || defined(HAVE_TTYNAME) */ +#endif /* HAVE_SETSID */ + +#if defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) +/*[clinic input] +os.login_tty + + fd: fildes + / + +Prepare the tty of which fd is a file descriptor for a new login session. + +Make the calling process a session leader; make the tty the +controlling tty, the stdin, the stdout, and the stderr of the +calling process; close fd. +[clinic start generated code]*/ + +static PyObject * +os_login_tty_impl(PyObject *module, int fd) +/*[clinic end generated code: output=495a79911b4cc1bc input=5f298565099903a2]*/ +{ +#if defined(HAVE_LOGIN_TTY) + if (login_tty(fd) == -1) { + return posix_error(); + } +#else /* defined(HAVE_FALLBACK_LOGIN_TTY) */ + /* Establish a new session. */ + if (setsid() == -1) { + return posix_error(); + } + + /* The tty becomes the controlling terminal. */ +#if defined(TIOCSCTTY) + if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) { + return posix_error(); + } +#else /* defined(HAVE_TTYNAME) */ + /* Fallback method (archaic); from Advanced Programming in the UNIX(R) + * Environment, Third edition, 2013, Section 9.6 - Controlling Terminal: + * "Systems derived from UNIX System V allocate the controlling + * terminal for a session when the session leader opens the first + * terminal device that is not already associated with a session, as + * long as the call to open does not specify the O_NOCTTY flag." */ + char *tmppath = ttyname(fd); + if (tmppath == NULL) { + return posix_error(); + } + +#define CLOSE_IF_NOT_FD(otherfd) \ + if (fd != otherfd) { \ + close(otherfd); \ + } \ + + CLOSE_IF_NOT_FD(0); + CLOSE_IF_NOT_FD(1); + CLOSE_IF_NOT_FD(2); + + int tmpfd = open(tmppath, O_RDWR); + if (tmpfd == -1) { + return posix_error(); + } + close(tmpfd); +#endif /* defined(TIOCSCTTY) */ + + /* The tty becomes stdin/stdout/stderr */ + if (dup2(fd, 0) == -1 || dup2(fd, 1) == -1 || dup2(fd, 2) == -1) { + return posix_error(); + } + if (fd > 2) { + close(fd); + } +#endif /* defined(HAVE_LOGIN_TTY) */ + Py_RETURN_NONE; +} +#endif /* defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) */ #ifdef HAVE_FORKPTY /*[clinic input] @@ -7271,8 +7348,9 @@ os_forkpty_impl(PyObject *module) /* parent: release the import lock. */ PyOS_AfterFork_Parent(); } - if (pid == -1) + if (pid == -1) { return posix_error(); + } return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd); } #endif /* HAVE_FORKPTY */ @@ -7613,7 +7691,7 @@ os_initgroups_impl(PyObject *module, PyObject *oname, gid_t gid) const char *username = PyBytes_AS_STRING(oname); if (initgroups(username, gid) == -1) - return PyErr_SetFromErrno(PyExc_OSError); + return posix_error(); Py_RETURN_NONE; } @@ -14652,6 +14730,7 @@ static PyMethodDef posix_methods[] = { OS_SCHED_GETAFFINITY_METHODDEF OS_OPENPTY_METHODDEF OS_FORKPTY_METHODDEF + OS_LOGIN_TTY_METHODDEF OS_GETEGID_METHODDEF OS_GETEUID_METHODDEF OS_GETGID_METHODDEF diff --git a/configure b/configure index 9ee750b70f4a19..55eb94dc6df192 100755 --- a/configure +++ b/configure @@ -8041,7 +8041,7 @@ sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/ioctl.h \ sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \ sys/param.h sys/random.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \ -sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ +sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h utmp.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \ sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \ @@ -12735,7 +12735,7 @@ $as_echo "no" >&6; } fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# check for openpty and forkpty +# check for openpty, login_tty, and forkpty for ac_func in openpty do : @@ -12831,6 +12831,103 @@ fi fi +fi +done + +for ac_func in login_tty +do : + ac_fn_c_check_func "$LINENO" "login_tty" "ac_cv_func_login_tty" +if test "x$ac_cv_func_login_tty" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOGIN_TTY 1 +_ACEOF + +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for login_tty in -lutil" >&5 +$as_echo_n "checking for login_tty in -lutil... " >&6; } +if ${ac_cv_lib_util_login_tty+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lutil $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char login_tty (); +int +main () +{ +return login_tty (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_util_login_tty=yes +else + ac_cv_lib_util_login_tty=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_util_login_tty" >&5 +$as_echo "$ac_cv_lib_util_login_tty" >&6; } +if test "x$ac_cv_lib_util_login_tty" = xyes; then : + $as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h + LIBS="$LIBS -lutil" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for login_tty in -lbsd" >&5 +$as_echo_n "checking for login_tty in -lbsd... " >&6; } +if ${ac_cv_lib_bsd_login_tty+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lbsd $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char login_tty (); +int +main () +{ +return login_tty (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_bsd_login_tty=yes +else + ac_cv_lib_bsd_login_tty=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_login_tty" >&5 +$as_echo "$ac_cv_lib_bsd_login_tty" >&6; } +if test "x$ac_cv_lib_bsd_login_tty" = xyes; then : + $as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h + LIBS="$LIBS -lbsd" +fi + + +fi + + fi done From b6267a66d24bf68186f48805bd75f076c32c564b Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Thu, 26 Aug 2021 20:39:49 -0700 Subject: [PATCH 2/4] Update os.rst versionadded to 3.11 --- Doc/library/os.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/os.rst b/Doc/library/os.rst index 3c4b0d529312bc..1a1f764254a1d2 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -998,7 +998,7 @@ as internal buffering of data. .. availability:: Unix. - .. versionadded:: 3.10 + .. versionadded:: 3.11 .. function:: lseek(fd, pos, how) From e372f559803fbf1588e1379c318ed50166d10e85 Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Sat, 28 Aug 2021 01:39:40 -0500 Subject: [PATCH 3/4] Add check for login_tty() to configure.ac Signed-off-by: Soumendra Ganguly --- configure | 14 +++++++++++++- configure.ac | 10 ++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 55eb94dc6df192..77c1f3ffa579f5 100755 --- a/configure +++ b/configure @@ -787,6 +787,7 @@ infodir docdir oldincludedir includedir +runstatedir localstatedir sharedstatedir sysconfdir @@ -905,6 +906,7 @@ datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' +runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' @@ -1157,6 +1159,15 @@ do | -silent | --silent | --silen | --sile | --sil) silent=yes ;; + -runstatedir | --runstatedir | --runstatedi | --runstated \ + | --runstate | --runstat | --runsta | --runst | --runs \ + | --run | --ru | --r) + ac_prev=runstatedir ;; + -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ + | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ + | --run=* | --ru=* | --r=*) + runstatedir=$ac_optarg ;; + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ @@ -1294,7 +1305,7 @@ fi for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir + libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. @@ -1447,6 +1458,7 @@ Fine tuning of the installation directories: --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] diff --git a/configure.ac b/configure.ac index 7f7dfa588a8144..8b5e277d2ead31 100644 --- a/configure.ac +++ b/configure.ac @@ -2201,7 +2201,7 @@ sys/audioio.h sys/xattr.h sys/bsdtty.h sys/event.h sys/file.h sys/ioctl.h \ sys/kern_control.h sys/loadavg.h sys/lock.h sys/mkdev.h sys/modem.h \ sys/param.h sys/random.h sys/select.h sys/sendfile.h sys/socket.h sys/statvfs.h \ sys/stat.h sys/syscall.h sys/sys_domain.h sys/termio.h sys/time.h \ -sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h \ +sys/times.h sys/types.h sys/uio.h sys/un.h sys/utsname.h sys/wait.h pty.h utmp.h \ libutil.h sys/resource.h netpacket/packet.h sysexits.h bluetooth.h \ linux/tipc.h linux/random.h spawn.h util.h alloca.h endian.h \ sys/endian.h sys/sysmacros.h linux/memfd.h linux/wait.h sys/memfd.h \ @@ -3988,7 +3988,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ [AC_MSG_RESULT(no) ]) -# check for openpty and forkpty +# check for openpty, login_tty, and forkpty AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(util,openpty, @@ -3996,6 +3996,12 @@ AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(bsd,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lbsd"]) ) ) +AC_CHECK_FUNCS(login_tty,, + AC_CHECK_LIB(util,login_tty, + [AC_DEFINE(HAVE_LOGIN_TTY) LIBS="$LIBS -lutil"], + AC_CHECK_LIB(bsd,login_tty, [AC_DEFINE(HAVE_LOGIN_TTY) LIBS="$LIBS -lbsd"]) + ) +) AC_CHECK_FUNCS(forkpty,, AC_CHECK_LIB(util,forkpty, [AC_DEFINE(HAVE_FORKPTY) LIBS="$LIBS -lutil"], From ec3b44bd6f9c34ed93ed9ba231075493badabe7e Mon Sep 17 00:00:00 2001 From: Soumendra Ganguly Date: Fri, 19 Nov 2021 21:25:13 -0600 Subject: [PATCH 4/4] Fix merge conflict in Modules/clinic/posixmodule.c.h Signed-off-by: Soumendra Ganguly --- Modules/clinic/posixmodule.c.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index 5015da70b53ae0..f78d78059e8939 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -9202,4 +9202,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject *const *args, Py_ssize_t na #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=f9f9bf32d1318d82 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=65a85d7d3f2c487e input=a9049054013a1b77]*/