--- grantpt.c.orig 2006-04-21 22:41:31.000000000 -0700 +++ grantpt.c 2006-04-21 22:43:03.000000000 -0700 @@ -54,18 +54,16 @@ #include <unistd.h> #include "un-namespace.h" -#define PTM_MAJOR 6 /* pseudo tty master major */ -#define PTS_MAJOR 5 /* pseudo tty slave major */ #define PTM_PREFIX "pty" /* pseudo tty master naming convention */ #define PTS_PREFIX "tty" /* pseudo tty slave naming convention */ /* * The following are range values for pseudo TTY devices. Pseudo TTYs have a - * name of /dev/[pt]ty[p-sP-S][0-9a-v], yielding 256 combinations per major. + * name of /dev/[pt]ty[p-w][0-9a-f], yielding 128 combinations per major. */ -#define PT_MAX 256 -#define PT_DEV1 "pqrsPQRS" -#define PT_DEV2 "0123456789abcdefghijklmnopqrstuv" +#define PT_MAX 128 +#define PT_DEV1 "pqrstuvw" +#define PT_DEV2 "0123456789abcdef" /* * grantpt(3) support utility. @@ -73,11 +71,32 @@ #define _PATH_PTCHOWN "/usr/libexec/pt_chown" /* + * On Mac OS X, the major device number may not be the same between reboots. + * So we need to determine the major device number the first time. + */ +#define _PATH_A_PTY (_PATH_DEV PTM_PREFIX "p0") + +static int _ptm_major = -1; + +static int +_init_major(void) +{ + struct stat st; + + if (_ptm_major >= 0) + return _ptm_major; + if (stat(_PATH_A_PTY, &st) < 0) + return -1; /* should never happen */ + _ptm_major = major(st.st_rdev); + return _ptm_major; +} +/* * ISPTM(x) returns 0 for struct stat x if x is not a pty master. * The bounds checking may be unnecessary but it does eliminate doubt. */ -#define ISPTM(x) (S_ISCHR((x).st_mode) && \ - major((x).st_rdev) == PTM_MAJOR && \ +#define ISPTM(x) (_init_major() >= 0 && \ + S_ISCHR((x).st_mode) && \ + major((x).st_rdev) == _ptm_major && \ minor((x).st_rdev) >= 0 && \ minor((x).st_rdev) < PT_MAX) @@ -100,50 +119,53 @@ serrno = errno; if ((slave = ptsname(fildes)) != NULL) { - /* - * Block SIGCHLD. - */ - (void)sigemptyset(&nblock); - (void)sigaddset(&nblock, SIGCHLD); - (void)_sigprocmask(SIG_BLOCK, &nblock, &oblock); - - switch (pid = fork()) { - case -1: - break; - case 0: /* child */ + /* 4430299: if we are root, we don't need to fork/exec */ + if (geteuid() != 0) { /* - * pt_chown expects the master pseudo TTY to be its - * standard input. + * Block SIGCHLD. */ - (void)_dup2(fildes, STDIN_FILENO); - (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); - execl(_PATH_PTCHOWN, _PATH_PTCHOWN, (char *)NULL); - _exit(EX_UNAVAILABLE); - /* NOTREACHED */ - default: /* parent */ + (void)sigemptyset(&nblock); + (void)sigaddset(&nblock, SIGCHLD); + (void)_sigprocmask(SIG_BLOCK, &nblock, &oblock); + + switch (pid = fork()) { + case -1: + break; + case 0: /* child */ + /* + * pt_chown expects the master pseudo TTY to be its + * standard input. + */ + (void)_dup2(fildes, STDIN_FILENO); + (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); + execl(_PATH_PTCHOWN, _PATH_PTCHOWN, (char *)NULL); + _exit(EX_UNAVAILABLE); + /* NOTREACHED */ + default: /* parent */ + /* + * Just wait for the process. Error checking is + * done below. + */ + while ((spid = _waitpid(pid, &status, 0)) == -1 && + (errno == EINTR)) + ; + if (spid != -1 && WIFEXITED(status) && + WEXITSTATUS(status) == EX_OK) + retval = 0; + else + errno = EACCES; + break; + } + /* - * Just wait for the process. Error checking is - * done below. + * Restore process's signal mask. */ - while ((spid = _waitpid(pid, &status, 0)) == -1 && - (errno == EINTR)) - ; - if (spid != -1 && WIFEXITED(status) && - WEXITSTATUS(status) == EX_OK) - retval = 0; - else - errno = EACCES; - break; + (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); } - /* - * Restore process's signal mask. - */ - (void)_sigprocmask(SIG_SETMASK, &oblock, NULL); - if (retval) { /* - * pt_chown failed. Try to manually change the + * pt_chown failed (or we're root). Try to manually change the * permissions for the slave. */ gid = (grp = getgrnam("tty")) ? grp->gr_gid : -1; @@ -227,8 +249,8 @@ errno = EINVAL; else { (void)sprintf(slave, _PATH_DEV PTS_PREFIX "%c%c", - PT_DEV1[minor(sbuf.st_rdev) / 32], - PT_DEV2[minor(sbuf.st_rdev) % 32]); + PT_DEV1[minor(sbuf.st_rdev) / 16], + PT_DEV2[minor(sbuf.st_rdev) % 16]); retval = slave; } }