diff --git a/Doc/library/os.rst b/Doc/library/os.rst index a4c5fbb4815..3c4b0d52931 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 00000000000..8fec11fbe4f --- /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 4a72ea0dd56..5015da70b53 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 @@ 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) */ @@ -9163,4 +9202,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=f3ec08afcd6cd8f8 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=f9f9bf32d1318d82 input=a9049054013a1b77]*/ diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d9eb62f20e6..3e0530f7768 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -7118,22 +7118,21 @@ error: # 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 @@ error: } #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 9ee750b70f4..55eb94dc6df 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