grantpt.c.patch   [plain text]


--- 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;
 		}
 	}