summaryrefslogtreecommitdiff
path: root/libc/stdlib
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2001-05-08 19:58:20 +0000
committerEric Andersen <andersen@codepoet.org>2001-05-08 19:58:20 +0000
commita3e03be058a9b9a2caf36c5b18f66c0fc3df3bf0 (patch)
tree2ad333bd1e56590e981eba3c54f6057cbf5758bb /libc/stdlib
parent6c0899094d50e0d35d699594bfcd9cae4164abe2 (diff)
Add in libutil, based on Cory Visi's variant of Michael Shmulevich's libutil
port. I have reworked the code quite a bit so that the stuff that is supposed to be in libc is in libc, and I added a bunch of missing stuff so the libutil interface matches that of glibc's libutil. The only caveat is that libutil/login.c is currently a stub. -Erik
Diffstat (limited to 'libc/stdlib')
-rw-r--r--libc/stdlib/Makefile3
-rw-r--r--libc/stdlib/bsd_getpt.c78
-rw-r--r--libc/stdlib/getpt.c89
-rw-r--r--libc/stdlib/grantpt.c66
-rw-r--r--libc/stdlib/ptsname.c171
-rw-r--r--libc/stdlib/pty-private.h42
-rw-r--r--libc/stdlib/unix_grantpt.c197
-rw-r--r--libc/stdlib/unlockpt.c49
8 files changed, 694 insertions, 1 deletions
diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile
index 123841959..46276668b 100644
--- a/libc/stdlib/Makefile
+++ b/libc/stdlib/Makefile
@@ -38,7 +38,8 @@ MOBJ2=atexit.o exit.o
CSRC = abort.c getenv.c mktemp.c qsort.c realpath.c abs.c bsearch.c \
- mkstemp.c putenv.c rand.c random.c setenv.c system.c div.c ldiv.c
+ mkstemp.c putenv.c rand.c random.c setenv.c system.c div.c ldiv.c \
+ getpt.c ptsname.c grantpt.c unlockpt.c
ifeq ($(HAS_FLOATS),true)
CSRC += strtod.c
endif
diff --git a/libc/stdlib/bsd_getpt.c b/libc/stdlib/bsd_getpt.c
new file mode 100644
index 000000000..0f981ab95
--- /dev/null
+++ b/libc/stdlib/bsd_getpt.c
@@ -0,0 +1,78 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+
+/* Prefix for master pseudo terminal nodes. */
+#define _PATH_PTY "/dev/pty"
+
+
+/* Letters indicating a series of pseudo terminals. */
+#ifndef PTYNAME1
+#define PTYNAME1 "pqrsPQRS"
+#endif
+const char _ptyname1[] = PTYNAME1;
+
+/* Letters indicating the position within a series. */
+#ifndef PTYNAME2
+#define PTYNAME2 "0123456789abcdefghijklmnopqrstuv";
+#endif
+const char _ptyname2[] = PTYNAME2;
+
+
+/* Open a master pseudo terminal and return its file descriptor. */
+int
+__getpt (void)
+{
+ char buf[sizeof (_PATH_PTY) + 2];
+ const char *p, *q;
+ char *s;
+
+ memcpy (buf, _PATH_PTY, sizeof (_PATH_PTY) - 1);
+ s = buf + strlen (buf);
+
+ /* s[0] and s[1] will be filled in the loop. */
+ s[2] = '\0';
+
+ for (p = _ptyname1; *p != '\0'; ++p)
+ {
+ s[0] = *p;
+
+ for (q = _ptyname2; *q != '\0'; ++q)
+ {
+ int fd;
+
+ s[1] = *q;
+
+ fd = open (buf, O_RDWR);
+ if (fd != -1)
+ return fd;
+
+ if (errno == ENOENT)
+ return -1;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
diff --git a/libc/stdlib/getpt.c b/libc/stdlib/getpt.c
new file mode 100644
index 000000000..74f009a95
--- /dev/null
+++ b/libc/stdlib/getpt.c
@@ -0,0 +1,89 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <paths.h>
+#include <sys/statfs.h>
+
+/* Constant that identifies the `devpts' filesystem. */
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+/* Constant that identifies the `devfs' filesystem. */
+#define DEVFS_SUPER_MAGIC 0x1373
+
+/* Path to the master pseudo terminal cloning device. */
+#define _PATH_DEVPTMX _PATH_DEV "ptmx"
+/* Directory containing the UNIX98 pseudo terminals. */
+#define _PATH_DEVPTS _PATH_DEV "pts"
+
+/* Prototype for function that opens BSD-style master pseudo-terminals. */
+int __bsd_getpt (void);
+
+/* Open a master pseudo terminal and return its file descriptor. */
+int
+getpt (void)
+{
+ static int have_no_dev_ptmx;
+ int fd;
+
+ if (!have_no_dev_ptmx)
+ {
+ fd = open (_PATH_DEVPTMX, O_RDWR);
+ if (fd != -1)
+ {
+ struct statfs fsbuf;
+ static int devpts_mounted;
+
+ /* Check that the /dev/pts filesystem is mounted
+ or if /dev is a devfs filesystem (this implies /dev/pts). */
+ if (devpts_mounted
+ || (statfs (_PATH_DEVPTS, &fsbuf) == 0
+ && fsbuf.f_type == DEVPTS_SUPER_MAGIC)
+ || (statfs (_PATH_DEV, &fsbuf) == 0
+ && fsbuf.f_type == DEVFS_SUPER_MAGIC))
+ {
+ /* Everything is ok. */
+ devpts_mounted = 1;
+ return fd;
+ }
+
+ /* If /dev/pts is not mounted then the UNIX98 pseudo terminals
+ are not usable. */
+ close (fd);
+ have_no_dev_ptmx = 1;
+ }
+ else
+ {
+ if (errno == ENOENT || errno == ENODEV)
+ have_no_dev_ptmx = 1;
+ else
+ return -1;
+ }
+ }
+
+ return __bsd_getpt ();
+}
+
+#define PTYNAME1 "pqrstuvwxyzabcde";
+#define PTYNAME2 "0123456789abcdef";
+
+#define __getpt __bsd_getpt
+#include <bsd_getpt.c>
diff --git a/libc/stdlib/grantpt.c b/libc/stdlib/grantpt.c
new file mode 100644
index 000000000..63f423b8f
--- /dev/null
+++ b/libc/stdlib/grantpt.c
@@ -0,0 +1,66 @@
+/* Copyright (C) 1998, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/statfs.h>
+
+/* Constant that identifies the `devpts' filesystem. */
+#define DEVPTS_SUPER_MAGIC 0x1cd1
+/* Constant that identifies the `devfs' filesystem. */
+#define DEVFS_SUPER_MAGIC 0x1373
+
+/* Prototype for function that changes ownership and access permission
+ for slave pseudo terminals that do not live on a `devpts'
+ filesystem. */
+int __unix_grantpt (int fd);
+
+/* Prototype for private function that gets the name of the slave
+ pseudo terminal in a safe way. */
+static int pts_name (int fd, char **pts, size_t buf_len);
+
+/* Change the ownership and access permission of the slave pseudo
+ terminal associated with the master pseudo terminal specified
+ by FD. */
+int
+grantpt (int fd)
+{
+ struct statfs fsbuf;
+#ifdef PATH_MAX
+ char _buf[PATH_MAX];
+#else
+ char _buf[512];
+#endif
+ char *buf = _buf;
+
+ if (pts_name (fd, &buf, sizeof (_buf)))
+ return -1;
+
+ if (statfs (buf, &fsbuf) < 0)
+ return -1;
+
+ /* If the slave pseudo terminal lives on a `devpts' filesystem, the
+ ownership and access permission are already set. */
+ if (fsbuf.f_type == DEVPTS_SUPER_MAGIC || fsbuf.f_type == DEVFS_SUPER_MAGIC)
+ return 0;
+
+ return __unix_grantpt (fd);
+}
+
+#define grantpt __unix_grantpt
+#include <unix_grantpt.c>
diff --git a/libc/stdlib/ptsname.c b/libc/stdlib/ptsname.c
new file mode 100644
index 000000000..2fbc6be49
--- /dev/null
+++ b/libc/stdlib/ptsname.c
@@ -0,0 +1,171 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <termios.h>
+#include <unistd.h>
+
+/* Check if DEV corresponds to a master pseudo terminal device. */
+#define MASTER_P(Dev) \
+ (major ((Dev)) == 2 \
+ || (major ((Dev)) == 4 && minor ((Dev)) >= 128 && minor ((Dev)) < 192) \
+ || (major ((Dev)) >= 128 && major ((Dev)) < 136))
+
+/* Check if DEV corresponds to a master pseudo terminal device. */
+#define SLAVE_P(Dev) \
+ (major ((Dev)) == 3 \
+ || (major ((Dev)) == 4 && minor ((Dev)) >= 192 && minor ((Dev)) < 256) \
+ || (major ((Dev)) >= 136 && major ((Dev)) < 144))
+
+/* Note that major number 4 corresponds to the old BSD style pseudo
+ terminal devices. As of Linux 2.1.115 these are no longer
+ supported. They have been replaced by major numbers 2 (masters)
+ and 3 (slaves). */
+
+/* Directory where we can find the slave pty nodes. */
+#define _PATH_DEVPTS "/dev/pts/"
+
+/* The are declared in getpt.c. */
+extern const char _ptyname1[];
+extern const char _ptyname2[];
+
+/* Static buffer for `ptsname'. */
+static char buffer[sizeof (_PATH_DEVPTS) + 20];
+
+/*
+extern char *
+_itoa_word (unsigned long value, char *buflim,
+ unsigned int base, int upper_case);
+*/
+
+
+/* Store at most BUFLEN characters of the pathname of the slave pseudo
+ terminal associated with the master FD is open on in BUF.
+ Return 0 on success, otherwise an error number. */
+int ptsname_r (int fd, char *buf, size_t buflen)
+{
+ int save_errno = errno;
+ struct stat st;
+ int ptyno;
+
+ if (buf == NULL)
+ {
+ errno = EINVAL;
+ return EINVAL;
+ }
+
+ if (!isatty (fd))
+ {
+ errno = ENOTTY;
+ return ENOTTY;
+ }
+#if 0
+#ifdef TIOCGPTN
+ if (ioctl (fd, TIOCGPTN, &ptyno) == 0)
+ {
+ /* Buffer we use to print the number in. For a maximum size for
+ `int' of 8 bytes we never need more than 20 digits. */
+ char numbuf[21];
+ const char *devpts = _PATH_DEVPTS;
+ const size_t devptslen = strlen (devpts);
+ char *p;
+
+ numbuf[20] = '\0';
+ p = _itoa_word (ptyno, &numbuf[20], 10, 0);
+
+ if (buflen < devptslen + strlen (p) + 1)
+ {
+ errno = ERANGE;
+ return ERANGE;
+ }
+
+ strcpy (buf, devpts);
+ strcat (buf, p);
+ }
+ else if (errno == EINVAL)
+#endif
+#endif
+ {
+ char *p;
+
+ if (buflen < strlen (_PATH_TTY) + 3)
+ {
+ errno = ERANGE;
+ return ERANGE;
+ }
+
+ if (fstat (fd, &st) < 0)
+ return errno;
+
+ /* Check if FD really is a master pseudo terminal. */
+ if (! MASTER_P (st.st_rdev))
+ {
+ errno = ENOTTY;
+ return ENOTTY;
+ }
+
+ ptyno = minor (st.st_rdev);
+ /* This is for the old BSD pseudo terminals. As of Linux
+ 2.1.115 these are no longer supported. */
+ if (major (st.st_rdev) == 4)
+ ptyno -= 128;
+
+ if (ptyno / 16 >= strlen (_ptyname1))
+ {
+ errno = ENOTTY;
+ return ENOTTY;
+ }
+
+ strcpy (buf, _PATH_TTY);
+ p = buf + strlen (buf);
+ p[0] = _ptyname1[ptyno / 16];
+ p[1] = _ptyname2[ptyno % 16];
+ p[2] = '\0';
+ }
+
+ if (_xstat (_STAT_VER, buf, &st) < 0)
+ return errno;
+
+ /* Check if the name we're about to return really corresponds to a
+ slave pseudo terminal. */
+ if (! S_ISCHR (st.st_mode) || ! SLAVE_P (st.st_rdev))
+ {
+ /* This really is a configuration problem. */
+ errno = ENOTTY;
+ return ENOTTY;
+ }
+
+ errno = save_errno;
+ return 0;
+}
+
+/* Return the pathname of the pseudo terminal slave assoicated with
+ the master FD is open on, or NULL on errors.
+ The returned storage is good until the next call to this function. */
+char *
+ptsname (int fd)
+{
+ return ptsname_r (fd, buffer, sizeof (buffer)) != 0 ? NULL : buffer;
+}
diff --git a/libc/stdlib/pty-private.h b/libc/stdlib/pty-private.h
new file mode 100644
index 000000000..621dbfd6f
--- /dev/null
+++ b/libc/stdlib/pty-private.h
@@ -0,0 +1,42 @@
+/* Internal defenitions and declarations for pseudo terminal functions.
+ Copyright (C) 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#ifndef _PTY_PRIVATE_H
+#define _PTY_PRIVATE_H 1
+
+/* The group slave pseudo terminals belong to. */
+#define TTY_GROUP "tty"
+
+/* The file descriptor connected to the master pseudo terminal. */
+#define PTY_FILENO 3
+
+/* Path to the helper program that implements `grantpt' in user space. */
+#define _PATH_PT_CHOWN "/sbin/pt_chown"
+
+/* Exit codes for the helper program. */
+enum /* failure modes */
+{
+ FAIL_EBADF = 1,
+ FAIL_EINVAL,
+ FAIL_EACCES,
+ FAIL_EXEC
+};
+
+#endif /* pty-private.h */
diff --git a/libc/stdlib/unix_grantpt.c b/libc/stdlib/unix_grantpt.c
new file mode 100644
index 000000000..eb6ce0b35
--- /dev/null
+++ b/libc/stdlib/unix_grantpt.c
@@ -0,0 +1,197 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <grp.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "pty-private.h"
+
+extern int ptsname_r (int fd, char *buf, size_t buflen);
+
+/* Return the result of ptsname_r in the buffer pointed to by PTS,
+ which should be of length BUF_LEN. If it is too long to fit in
+ this buffer, a sufficiently long buffer is allocated using malloc,
+ and returned in PTS. 0 is returned upon success, -1 otherwise. */
+static int
+pts_name (int fd, char **pts, size_t buf_len)
+{
+ int rv;
+ char *buf = *pts;
+
+ for (;;)
+ {
+ char *new_buf;
+
+ if (buf_len)
+ {
+ rv = ptsname_r (fd, buf, buf_len);
+
+ if (rv != 0 || memchr (buf, '\0', buf_len))
+ /* We either got an error, or we succeeded and the
+ returned name fit in the buffer. */
+ break;
+
+ /* Try again with a longer buffer. */
+ buf_len += buf_len; /* Double it */
+ }
+ else
+ /* No initial buffer; start out by mallocing one. */
+ buf_len = 128; /* First time guess. */
+
+ if (buf != *pts)
+ /* We've already malloced another buffer at least once. */
+ new_buf = realloc (buf, buf_len);
+ else
+ new_buf = malloc (buf_len);
+ if (! new_buf)
+ {
+ rv = -1;
+ errno = ENOMEM;
+ break;
+ }
+ buf = new_buf;
+ }
+
+ if (rv == 0)
+ *pts = buf; /* Return buffer to the user. */
+ else if (buf != *pts)
+ free (buf); /* Free what we malloced when returning an error. */
+
+ return rv;
+}
+
+/* Change the ownership and access permission of the slave pseudo
+ terminal associated with the master pseudo terminal specified
+ by FD. */
+int
+grantpt (int fd)
+{
+ int retval = -1;
+#ifdef PATH_MAX
+ char _buf[PATH_MAX];
+#else
+ char _buf[512];
+#endif
+ char *buf = _buf;
+ struct stat st;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+
+ if (pts_name (fd, &buf, sizeof (_buf)))
+ return -1;
+
+ if (_xstat (_STAT_VER, buf, &st) < 0)
+ goto cleanup;
+
+ /* Make sure that we own the device. */
+ uid = getuid ();
+ if (st.st_uid != uid)
+ {
+ if (chown (buf, uid, st.st_gid) < 0)
+ goto helper;
+ }
+
+ gid = getgid ();
+
+ /* Make sure the group of the device is that special group. */
+ if (st.st_gid != gid)
+ {
+ if (chown (buf, uid, gid) < 0)
+ goto helper;
+ }
+
+ /* Make sure the permission mode is set to readable and writable by
+ the owner, and writable by the group. */
+ if ((st.st_mode & ACCESSPERMS) != (S_IRUSR|S_IWUSR|S_IWGRP))
+ {
+ if (chmod (buf, S_IRUSR|S_IWUSR|S_IWGRP) < 0)
+ goto helper;
+ }
+
+ retval = 0;
+ goto cleanup;
+
+ /* We have to use the helper program. */
+ helper:
+
+ pid = fork ();
+ if (pid == -1)
+ goto cleanup;
+ else if (pid == 0)
+ {
+ /* Disable core dumps. */
+ struct rlimit rl = { 0, 0 };
+ setrlimit (RLIMIT_CORE, &rl);
+
+ /* We pase the master pseudo terminal as file descriptor PTY_FILENO. */
+ if (fd != PTY_FILENO)
+ if (dup2 (fd, PTY_FILENO) < 0)
+ exit (FAIL_EBADF);
+
+ execle (_PATH_PT_CHOWN, _PATH_PT_CHOWN, NULL, NULL);
+ exit (FAIL_EXEC);
+ }
+ else
+ {
+ int w;
+
+ if (waitpid (pid, &w, 0) == -1)
+ goto cleanup;
+ if (!WIFEXITED (w))
+ errno = ENOEXEC;
+ else
+ switch (WEXITSTATUS(w))
+ {
+ case 0:
+ retval = 0;
+ break;
+ case FAIL_EBADF:
+ errno = EBADF;
+ break;
+ case FAIL_EINVAL:
+ errno = EINVAL;
+ break;
+ case FAIL_EACCES:
+ errno = EACCES;
+ break;
+ case FAIL_EXEC:
+ errno = ENOEXEC;
+ break;
+
+ default:
+ assert(! "getpt: internal error: invalid exit code from pt_chown");
+ }
+ }
+
+ cleanup:
+ if (buf != _buf)
+ free (buf);
+
+ return retval;
+}
diff --git a/libc/stdlib/unlockpt.c b/libc/stdlib/unlockpt.c
new file mode 100644
index 000000000..5dfea15d7
--- /dev/null
+++ b/libc/stdlib/unlockpt.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 1998 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the GNU C Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+
+/* Unlock the slave pseudo terminal associated with the master pseudo
+ terminal specified by FD. */
+int
+unlockpt (int fd)
+{
+#ifdef TIOCSPTLCK
+ int save_errno = errno;
+ int unlock = 0;
+
+ if (ioctl (fd, TIOCSPTLCK, &unlock))
+ {
+ if (errno == EINVAL)
+ {
+ errno = save_errno;
+ return 0;
+ }
+ else
+ return -1;
+ }
+#endif
+ /* If we have no TIOCSPTLCK ioctl, all slave pseudo terminals are
+ unlocked by default. */
+ return 0;
+}