diff --git a/Doc/library/os.rst b/Doc/library/os.rst index aa506734458..21c2073c9ed 100644 --- a/Doc/library/os.rst +++ b/Doc/library/os.rst @@ -1000,6 +1000,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.11 + + .. 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/2022-05-02-03-56-50.gh-issue-85984.RBivvc.rst b/Misc/NEWS.d/next/Library/2022-05-02-03-56-50.gh-issue-85984.RBivvc.rst new file mode 100644 index 00000000000..e54f29ad2cb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-05-02-03-56-50.gh-issue-85984.RBivvc.rst @@ -0,0 +1 @@ +New function os.login_tty() for Unix. diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h index fdcd5bdd4dc..d62b09ed740 100644 --- a/Modules/clinic/posixmodule.c.h +++ b/Modules/clinic/posixmodule.c.h @@ -3106,6 +3106,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__, @@ -8932,6 +8967,10 @@ exit: #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) */ @@ -9331,4 +9370,4 @@ exit: #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */ -/*[clinic end generated code: output=3b5a56add047ee1d input=a9049054013a1b77]*/ +/*[clinic end generated code: output=6150bcc25f5e4bc7 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index c55275c6c55..40158894411 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7274,22 +7274,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) +#if defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_LOGIN_TTY) || defined(HAVE_DEV_PTMX) #ifdef HAVE_PTY_H #include -#else -#ifdef HAVE_LIBUTIL_H +#ifdef 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 /* 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) @@ -7392,6 +7391,56 @@ os_openpty_impl(PyObject *module) #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ +#if defined(HAVE_SETSID) && defined(TIOCSCTTY) +#define HAVE_FALLBACK_LOGIN_TTY 1 +#endif /* defined(HAVE_SETSID) && defined(TIOCSCTTY) */ + +#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]*/ +{ +#ifdef 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 (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1) { + return posix_error(); + } + + /* 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 /* HAVE_LOGIN_TTY */ + Py_RETURN_NONE; +} +#endif /* defined(HAVE_LOGIN_TTY) || defined(HAVE_FALLBACK_LOGIN_TTY) */ + + #ifdef HAVE_FORKPTY /*[clinic input] os.forkpty @@ -7427,8 +7476,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 */ @@ -14797,6 +14847,7 @@ static PyMethodDef posix_methods[] = { OS_SCHED_SETAFFINITY_METHODDEF OS_SCHED_GETAFFINITY_METHODDEF OS_OPENPTY_METHODDEF + OS_LOGIN_TTY_METHODDEF OS_FORKPTY_METHODDEF OS_GETEGID_METHODDEF OS_GETEUID_METHODDEF diff --git a/configure b/configure index 0f5c2c80f60..b57c6f3a45a 100755 --- a/configure +++ b/configure @@ -8857,7 +8857,7 @@ for ac_header in \ sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \ sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.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 sys/xattr.h sysexits.h syslog.h \ - termios.h util.h utime.h \ + termios.h util.h utime.h utmp.h \ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` @@ -16750,7 +16750,7 @@ fi -# check for openpty and forkpty +# check for openpty, login_tty, and forkpty for ac_func in openpty do : @@ -16849,6 +16849,65 @@ fi fi done +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing login_tty" >&5 +$as_echo_n "checking for library containing login_tty... " >&6; } +if ${ac_cv_search_login_tty+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$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 +for ac_lib in '' util; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_login_tty=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if ${ac_cv_search_login_tty+:} false; then : + break +fi +done +if ${ac_cv_search_login_tty+:} false; then : + +else + ac_cv_search_login_tty=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_login_tty" >&5 +$as_echo "$ac_cv_search_login_tty" >&6; } +ac_res=$ac_cv_search_login_tty +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +$as_echo "#define HAVE_LOGIN_TTY 1" >>confdefs.h + + +fi + for ac_func in forkpty do : ac_fn_c_check_func "$LINENO" "forkpty" "ac_cv_func_forkpty" diff --git a/configure.ac b/configure.ac index 8c0711d8a9a..07b8885f1e4 100644 --- a/configure.ac +++ b/configure.ac @@ -2508,7 +2508,7 @@ AC_CHECK_HEADERS([ \ sys/random.h sys/resource.h sys/select.h sys/sendfile.h sys/socket.h sys/soundcard.h sys/stat.h \ sys/statvfs.h sys/sys_domain.h sys/syscall.h sys/sysmacros.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 sys/xattr.h sysexits.h syslog.h \ - termios.h util.h utime.h \ + termios.h util.h utime.h utmp.h \ ]) AC_HEADER_DIRENT AC_HEADER_MAJOR @@ -4670,7 +4670,7 @@ PY_CHECK_FUNC([setgroups], [ #endif ]) -# check for openpty and forkpty +# check for openpty, login_tty, and forkpty AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(util,openpty, @@ -4678,6 +4678,9 @@ AC_CHECK_FUNCS(openpty,, AC_CHECK_LIB(bsd,openpty, [AC_DEFINE(HAVE_OPENPTY) LIBS="$LIBS -lbsd"]) ) ) +AC_SEARCH_LIBS([login_tty], [util], + [AC_DEFINE([HAVE_LOGIN_TTY], [1], [Define to 1 if you have the `login_tty' function.])] +) AC_CHECK_FUNCS(forkpty,, AC_CHECK_LIB(util,forkpty, [AC_DEFINE(HAVE_FORKPTY) LIBS="$LIBS -lutil"], diff --git a/pyconfig.h.in b/pyconfig.h.in index 4ac054a28d8..383fd47dd43 100644 --- a/pyconfig.h.in +++ b/pyconfig.h.in @@ -721,6 +721,9 @@ /* Define to 1 if you have the `log2' function. */ #undef HAVE_LOG2 +/* Define to 1 if you have the `login_tty' function. */ +#undef HAVE_LOGIN_TTY + /* Define to 1 if the system has the type `long double'. */ #undef HAVE_LONG_DOUBLE @@ -1389,6 +1392,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_UTIME_H +/* Define to 1 if you have the header file. */ +#undef HAVE_UTMP_H + /* Define to 1 if you have the `uuid_create' function. */ #undef HAVE_UUID_CREATE