summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/pty.h40
-rw-r--r--include/utmp.h3
-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
-rw-r--r--libutil/Makefile61
-rw-r--r--libutil/forkpty.c52
-rw-r--r--libutil/login.c14
-rw-r--r--libutil/login_tty.c69
-rw-r--r--libutil/logout.c69
-rw-r--r--libutil/logwtmp.c73
-rw-r--r--libutil/openpty.c142
17 files changed, 1217 insertions, 1 deletions
diff --git a/include/pty.h b/include/pty.h
new file mode 100644
index 000000000..d8550840e
--- /dev/null
+++ b/include/pty.h
@@ -0,0 +1,40 @@
+/* Functions for pseudo TTY handling.
+ Copyright (C) 1996, 1997, 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. */
+
+#ifndef _PTY_H
+#define _PTY_H 1
+
+#include <features.h>
+
+#include <termios.h>
+#include <sys/ioctl.h>
+
+
+/* Create pseudo tty master slave pair with NAME and set terminal
+ attributes according to TERMP and WINP and return handles for both
+ ends in AMASTER and ASLAVE. */
+extern int openpty (int *__amaster, int *__aslave, char *__name,
+ struct termios *__termp, struct winsize *__winp);
+
+/* Create child process and establish the slave pseudo terminal as the
+ child's controlling terminal. */
+extern int forkpty (int *__amaster, char *__name,
+ struct termios *__termp, struct winsize *__winp);
+
+#endif /* pty.h */
diff --git a/include/utmp.h b/include/utmp.h
index c98caa5ce..e362181aa 100644
--- a/include/utmp.h
+++ b/include/utmp.h
@@ -44,6 +44,9 @@ extern struct utmp * getutid __P ((struct utmp *));
extern struct utmp * getutline __P ((struct utmp *));
extern struct utmp * pututline __P ((struct utmp *));
extern void endutent __P ((void));
+extern int login_tty (int __fd);
+extern void login (const struct utmp *entry);
+extern void logwtmp (const char *line, const char *name, const char *host);
#ifdef _LIBC
struct utmp * __getutent __P ((int));
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;
+}
diff --git a/libutil/Makefile b/libutil/Makefile
new file mode 100644
index 000000000..b5a458c30
--- /dev/null
+++ b/libutil/Makefile
@@ -0,0 +1,61 @@
+# Makefile for uClibc
+#
+# Copyright (C) 2000 by Lineo, inc.
+#
+# This program 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.
+#
+# This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+# Derived in part from the Linux-8086 C library, the GNU C Library, and several
+# other sundry sources. Files within this library are copyright by their
+# respective copyright holders.
+
+TOPDIR=../
+include $(TOPDIR)Rules.mak
+LIBC=$(TOPDIR)libc.a
+
+LIBUTIL=libutil.a
+LIBUTIL_SHARED=libutil.so
+TARGET_CC= ../extra/gcc-uClibc/$(TARGET_ARCH)-uclibc-gcc
+
+CSRC=forkpty.c login.c login_tty.c logout.c logwtmp.c openpty.c
+COBJS=$(patsubst %.c,%.o, $(CSRC))
+
+OBJS=$(COBJS)
+
+all: $(OBJS) $(LIBC)
+
+$(LIBC): ar-target
+
+ar-target: $(OBJS)
+ $(AR) $(ARFLAGS) $(LIBUTIL) $(OBJS)
+
+$(COBJS): %.o : %.c
+ $(TARGET_CC) $(CFLAGS) -c $< -o $@
+ $(STRIPTOOL) -x -R .note -R .comment $*.o
+
+shared: $(LIBUTIL)
+ $(TARGET_CC) $(LDFLAGS) -shared -o $(LIBUTIL_SHARED).$(MAJOR_VERSION) \
+ -Wl,-soname,$(LIBUTIL_SHARED).$(MAJOR_VERSION) $(COBJS) $(TOPDIR)$(SHARED_FULLNAME)
+
+install: all
+ install -d $(INSTALL_DIR)/lib
+ install -m 644 $(LIBUTIL) $(INSTALL_DIR)/lib/
+ @if [ -f $(LIBUTIL_SHARED).$(MAJOR_VERSION) ] ; then \
+ install -m 644 $(LIBUTIL_SHARED).$(MAJOR_VERSION) $(INSTALL_DIR)/lib/; \
+ (cd $(INSTALL_DIR)/lib/;ln -sf $(LIBUTIL_SHARED).$(MAJOR_VERSION) $(LIBUTIL_SHARED)); \
+ fi;
+
+clean:
+ rm -f *.[oa] *~ core $(LIBUTIL_SHARED).$(MAJOR_VERSION)
+
diff --git a/libutil/forkpty.c b/libutil/forkpty.c
new file mode 100644
index 000000000..af1d4becc
--- /dev/null
+++ b/libutil/forkpty.c
@@ -0,0 +1,52 @@
+/* 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 <sys/types.h>
+#include <termios.h>
+#include <unistd.h>
+#include <utmp.h>
+#include <pty.h>
+
+int forkpty (int *amaster, char *name,
+ struct termios *termp, struct winsize *winp)
+{
+ int master, slave, pid;
+
+ if (openpty (&master, &slave, name, termp, winp) == -1)
+ return -1;
+
+ switch (pid = fork ())
+ {
+ case -1:
+ return -1;
+ case 0:
+ /* Child. */
+ close (master);
+ if (login_tty (slave))
+ _exit (1);
+
+ return 0;
+ default:
+ /* Parent. */
+ *amaster = master;
+ close (slave);
+
+ return pid;
+ }
+}
diff --git a/libutil/login.c b/libutil/login.c
new file mode 100644
index 000000000..636ce9608
--- /dev/null
+++ b/libutil/login.c
@@ -0,0 +1,14 @@
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <utmp.h>
+
+/* Write the given entry into utmp and wtmp. */
+void login (const struct utmp *entry)
+{
+ return;
+}
+link_warning (login, "the `login' function is stubbed out and will not write utmp or wtmp.")
+
diff --git a/libutil/login_tty.c b/libutil/login_tty.c
new file mode 100644
index 000000000..d354407f2
--- /dev/null
+++ b/libutil/login_tty.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/* Make FD be the controlling terminal, stdin, stdout, and stderr;
+ then close FD. Returns 0 on success, nonzero on error. */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+
+int login_tty(int fd)
+{
+ (void) setsid();
+#ifdef TIOCSCTTY
+ if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
+ return (-1);
+#else
+ {
+ /* This might work. */
+ char *fdname = ttyname (fd);
+ int newfd;
+ if (fdname)
+ {
+ if (fd != 0)
+ (void) close (0);
+ if (fd != 1)
+ (void) close (1);
+ if (fd != 2)
+ (void) close (2);
+ newfd = open (fdname, O_RDWR);
+ (void) close (newfd);
+ }
+ }
+#endif
+ (void) dup2(fd, 0);
+ (void) dup2(fd, 1);
+ (void) dup2(fd, 2);
+ if (fd > 2)
+ (void) close(fd);
+ return (0);
+}
diff --git a/libutil/logout.c b/libutil/logout.c
new file mode 100644
index 000000000..082579b8f
--- /dev/null
+++ b/libutil/logout.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ 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 <string.h>
+#include <utmp.h>
+#include <sys/time.h>
+
+int
+logout (const char *line)
+{
+ struct utmp tmp;
+ struct utmp *ut;
+ int result = 0;
+
+ /* Tell that we want to use the UTMP file. */
+ utmpname (_PATH_UTMP);
+
+ /* Open UTMP file. */
+ setutent ();
+
+ /* Fill in search information. */
+#if _HAVE_UT_TYPE - 0
+ tmp.ut_type = USER_PROCESS;
+#endif
+ strncpy (tmp.ut_line, line, sizeof tmp.ut_line);
+
+ /* Read the record. */
+ if( (ut = getutline(&tmp)) )
+ {
+ /* Clear information about who & from where. */
+ bzero (ut->ut_name, sizeof ut->ut_name);
+#if _HAVE_UT_HOST - 0
+ bzero (ut->ut_host, sizeof ut->ut_host);
+#endif
+#if _HAVE_UT_TV - 0
+ gettimeofday (&ut->ut_tv, NULL);
+#else
+ time (&ut->ut_time);
+#endif
+#if _HAVE_UT_TYPE - 0
+ ut->ut_type = DEAD_PROCESS;
+#endif
+
+ if (pututline (ut) != NULL)
+ result = 1;
+ }
+
+ /* Close UTMP file. */
+ endutent ();
+
+ return result;
+}
diff --git a/libutil/logwtmp.c b/libutil/logwtmp.c
new file mode 100644
index 000000000..d8ee3da05
--- /dev/null
+++ b/libutil/logwtmp.c
@@ -0,0 +1,73 @@
+/* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+ 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 <string.h>
+#include <sys/time.h>
+#include <time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+
+
+void logwtmp (const char *line, const char *name, const char *host)
+{
+ struct utmp ut;
+ struct flock lock;
+ int ut_fd;
+
+
+ /* Set information in new entry. */
+ memset (&ut, 0, sizeof (ut));
+#if _HAVE_UT_PID - 0
+ ut.ut_pid = getpid ();
+#endif
+#if _HAVE_UT_TYPE - 0
+ ut.ut_type = name[0] ? USER_PROCESS : DEAD_PROCESS;
+#endif
+ strncpy (ut.ut_line, line, sizeof ut.ut_line);
+ strncpy (ut.ut_name, name, sizeof ut.ut_name);
+#if _HAVE_UT_HOST - 0
+ strncpy (ut.ut_host, host, sizeof ut.ut_host);
+#endif
+
+#if _HAVE_UT_TV - 0
+ __gettimeofday (&ut.ut_tv, NULL);
+#else
+ time (&ut.ut_time);
+#endif
+
+/* updwtmp (_PATH_WTMP, &ut); */
+/* from tinylogin */
+
+ if ((ut_fd = open(_PATH_WTMP, O_APPEND | O_WRONLY)) >= 0) {
+ /* Lock the utmp file before updating */
+ lock.l_type = F_WRLCK;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = 0;
+ lock.l_len = 0;
+ if (fcntl(ut_fd, F_SETLK, &lock) >= 0) {
+ write(ut_fd, (void *) &ut, sizeof(ut));
+ /* Now unlock the utmp file */
+ lock.l_type = F_UNLCK;
+ }
+ close(ut_fd);
+ }
+
+
+}
diff --git a/libutil/openpty.c b/libutil/openpty.c
new file mode 100644
index 000000000..1c2adbf6a
--- /dev/null
+++ b/libutil/openpty.c
@@ -0,0 +1,142 @@
+/* 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 <limits.h>
+#include <pty.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+extern int getpt (void);
+extern int grantpt (int fd);
+extern int ptsname_r (int fd, char *buf, size_t buflen);
+extern int unlockpt (int fd);
+
+/* 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;
+}
+
+/* Create pseudo tty master slave pair and set terminal attributes
+ according to TERMP and WINP. Return handles for both ends in
+ AMASTER and ASLAVE, and return the name of the slave end in NAME. */
+int
+openpty (int *amaster, int *aslave, char *name, struct termios *termp,
+ struct winsize *winp)
+{
+#ifdef PATH_MAX
+ char _buf[PATH_MAX];
+#else
+ char _buf[512];
+#endif
+ char *buf = _buf;
+ int master, slave;
+
+ master = getpt ();
+ if (master == -1)
+ return -1;
+
+ if (grantpt (master))
+ goto fail;
+
+ if (unlockpt (master))
+ goto fail;
+
+ if (pts_name (master, &buf, sizeof (_buf)))
+ goto fail;
+
+ slave = open (buf, O_RDWR | O_NOCTTY);
+ if (slave == -1)
+ {
+ if (buf != _buf)
+ free (buf);
+
+ goto fail;
+ }
+
+ /* XXX Should we ignore errors here? */
+ if(termp)
+ tcsetattr (slave, TCSAFLUSH, termp);
+ if (winp)
+ ioctl (slave, TIOCSWINSZ, winp);
+
+ *amaster = master;
+ *aslave = slave;
+ if (name != NULL)
+ strcpy (name, buf);
+
+ if (buf != _buf)
+ free (buf);
+ return 0;
+
+ fail:
+ close (master);
+ return -1;
+}