[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
ttyname fails for setid programs under linux/devfs
From: |
ben |
Subject: |
ttyname fails for setid programs under linux/devfs |
Date: |
Fri, 24 Oct 2003 04:12:23 +0100 |
User-agent: |
Mutt/1.5.4i |
Hi,
I run Linux and use devfs, without the 'compatibility names', and I
recently discovered that write(1) invariably fails with the message
'can't find your tty's name!'. Further investigation revealed that
ttyname(3) currently tries the following two strategies:
1. Read the links in /proc/self/fd. This fails for write(1) because
write is sgid tty, and the links in /proc/self/fd are readable only
by root for setid processes.
2. Walk /dev and /dev/pts. This fails because my tty (/dev/vc/3) is
not in either of these directories.
Two other minor flaws in the current implementation are that it
returns "/dev/tty" rather than the actual device for a fd open on
/dev/tty; and that if (say) a device file is created in /tmp and
opened, it will return the path that was opened rather than the
canonical name of the tty in /dev.
Therefore the patch below modifies ttyname_r to try these strategies:
1. If the fd we are given is open on /dev/tty, try to readlink
/proc/self/tty (this will be a symlink to the ctty in kernel 2.8,
according to comments in the source of procps); if that fails, try
to extract the device number of our ctty out of /proc/self/stat;
only if that fails return "/dev/tty".
2. Read the file /proc/tty/drivers, which maps device numbers to /dev
file names.
3. Attempt to guess the name from its device number, using a routine I
took out of procps.
4. Read the links in /proc/self/fd. This, unlike the other methods,
will return the opened name rather than the canonical name; but I
reasoned it was better than walking /dev...?
5. Walk an extended list of dirs in dev, including devfs dirs like
/dev/vc and /dev/tts.
, and makes ttyname call ttyname_r (I couldn't see why it didn't
anyway... am I missing something?).
If you wish to make use of this, I hereby state that I donate all
rights in my code to the FSF, etc.... There is one function which is
not mine, out of procps: this is clearly marked so you can remove it
if you wish.
The diff is taken against glibc-2.3.2, but the files concerned haven't
changed since then in the current CVS version.
Ben
---BEGIN DIFF---
diff -Naur glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname.c
glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname.c
--- glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname.c 2002-11-02
02:16:02.000000000 +0000
+++ glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname.c 2003-10-23
05:42:39.000000000 +0100
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991,92,93,1996-2001,2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,1995-2001, 2003 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
@@ -16,173 +16,30 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
-#include <errno.h>
-#include <limits.h>
-#include <stddef.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <stdio-common/_itoa.h>
-
-#if 0
-/* Is this used anywhere? It is not exported. */
-char *__ttyname;
-#endif
-
-static char *getttyname (const char *dev, dev_t mydev,
- ino64_t myino, int save, int *dostat)
- internal_function;
-
-
-libc_freeres_ptr (static char *getttyname_name);
-
-static char *
-internal_function
-getttyname (const char *dev, dev_t mydev, ino64_t myino, int save, int *dostat)
-{
- static size_t namelen;
- struct stat64 st;
- DIR *dirstream;
- struct dirent64 *d;
- size_t devlen = strlen (dev) + 1;
-
- dirstream = __opendir (dev);
- if (dirstream == NULL)
- {
- *dostat = -1;
- return NULL;
- }
-
- while ((d = __readdir64 (dirstream)) != NULL)
- if ((d->d_fileno == myino || *dostat)
- && strcmp (d->d_name, "stdin")
- && strcmp (d->d_name, "stdout")
- && strcmp (d->d_name, "stderr"))
- {
- size_t dlen = _D_ALLOC_NAMLEN (d);
- if (devlen + dlen > namelen)
- {
- free (getttyname_name);
- namelen = 2 * (devlen + dlen); /* Big enough. */
- getttyname_name = malloc (namelen);
- if (! getttyname_name)
- {
- *dostat = -1;
- /* Perhaps it helps to free the directory stream buffer. */
- (void) __closedir (dirstream);
- return NULL;
- }
- *((char *) __mempcpy (getttyname_name, dev, devlen - 1)) = '/';
- }
- memcpy (&getttyname_name[devlen], d->d_name, dlen);
- if (__xstat64 (_STAT_VER, getttyname_name, &st) == 0
-#ifdef _STATBUF_ST_RDEV
- && S_ISCHR (st.st_mode) && st.st_rdev == mydev
-#else
- && d->d_fileno == myino && st.st_dev == mydev
-#endif
- )
- {
- (void) __closedir (dirstream);
-#if 0
- __ttyname = getttyname_name;
-#endif
- __set_errno (save);
- return getttyname_name;
- }
- }
-
- (void) __closedir (dirstream);
- __set_errno (save);
- return NULL;
-}
+/* Ben Morrow <address@hidden> 2003-10-22 */
+#include <stddef.h>
+#include <limits.h>
+#include <errno.h>
-/* Static buffer in `ttyname'. */
-libc_freeres_ptr (static char *ttyname_buf);
+static char __ttyname_buf[TTY_NAME_MAX];
+int __ttyname_r(int fd, char *buf, size_t buflen);
-/* Return the pathname of the terminal FD is open on, or NULL on errors.
- The returned storage is good only until the next call to this function. */
char *
-ttyname (int fd)
+__ttyname(int fd)
{
- static size_t buflen;
- char procname[30];
- struct stat64 st, st1;
- int dostat = 0;
- char *name;
- int save = errno;
- int len;
-
- if (!__isatty (fd))
- return NULL;
+ int rv;
- /* We try using the /proc filesystem. */
- *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
+ rv = __ttyname_r(fd, __ttyname_buf, sizeof(__ttyname_buf));
- if (buflen == 0)
+ if (rv)
{
- buflen = 4095;
- ttyname_buf = (char *) malloc (buflen + 1);
- if (ttyname_buf == NULL)
- {
- buflen = 0;
- return NULL;
- }
- }
-
- len = __readlink (procname, ttyname_buf, buflen);
- if (len != -1
- /* This is for Linux 2.0. */
- && ttyname_buf[0] != '[')
- {
- if ((size_t) len >= buflen)
- return NULL;
- /* readlink need not terminate the string. */
- ttyname_buf[len] = '\0';
- return ttyname_buf;
- }
-
- if (__fxstat64 (_STAT_VER, fd, &st) < 0)
- return NULL;
-
- if (__xstat64 (_STAT_VER, "/dev/pts", &st1) == 0 && S_ISDIR (st1.st_mode))
- {
-#ifdef _STATBUF_ST_RDEV
- name = getttyname ("/dev/pts", st.st_rdev, st.st_ino, save, &dostat);
-#else
- name = getttyname ("/dev/pts", st.st_dev, st.st_ino, save, &dostat);
-#endif
- }
- else
- {
- __set_errno (save);
- name = NULL;
- }
-
- if (!name && dostat != -1)
- {
-#ifdef _STATBUF_ST_RDEV
- name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
-#else
- name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
-#endif
- }
-
- if (!name && dostat != -1)
- {
- dostat = 1;
-#ifdef _STATBUF_ST_RDEV
- name = getttyname ("/dev", st.st_rdev, st.st_ino, save, &dostat);
-#else
- name = getttyname ("/dev", st.st_dev, st.st_ino, save, &dostat);
-#endif
+ __set_errno(rv);
+ return NULL;
}
- return name;
+ return __ttyname_buf;
}
+
+weak_alias(__ttyname, ttyname);
diff -Naur glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname_r.c
glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname_r.c
--- glibc-2.3.2-orig/sysdeps/unix/sysv/linux/ttyname_r.c 2003-02-25
02:05:29.000000000 +0000
+++ glibc-2.3.2/sysdeps/unix/sysv/linux/ttyname_r.c 2003-10-24
03:56:16.000000000 +0100
@@ -16,6 +16,8 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+/* Ben Morrow <address@hidden> 2003-10-22 */
+
#include <errno.h>
#include <limits.h>
#include <stddef.h>
@@ -25,174 +27,339 @@
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
+#include <stdio.h>
+#include <sys/sysmacros.h>
-#include <stdio-common/_itoa.h>
-
-static int getttyname_r (char *buf, size_t buflen,
- dev_t mydev, ino64_t myino, int save,
- int *dostat) internal_function;
-
-static int
-internal_function
-getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
- int save, int *dostat)
-{
- struct stat64 st;
- DIR *dirstream;
- struct dirent64 *d;
- size_t devlen = strlen (buf);
-
- dirstream = __opendir (buf);
- if (dirstream == NULL)
- {
- *dostat = -1;
- return errno;
- }
+#define DEV_TTY_NUM (256 * 5)
+#define DEV_WALKS { "/dev/vc", "/dev/pts", "/dev/tts", "/dev/usb/tts", \
+ "/dev/pty", "/dev", NULL }
+/* we want to search the smallest dirs first. /dev is very full on non-devfs
systems. */
+#define CPP_STR_(x) #x
+#define CPP_STR(x) CPP_STR_(x)
+#define TTYDRV_FMT "%*s %" CPP_STR(TTY_NAME_MAX) "s %d %*s %*s"
+/* for reading /proc/tty/drivers */
+#define STAT_FMT "%*d %*s %*s %*d %*d %*d %d"
+/* for reading /proc/self/stat for our ctty */
+
+/* Finding a name given info about a device:
+ * put ttyname into buf; return 0 for success, error code for failure or
+ * -1 to try next method. Do not change errno; it is saved and restored
+ * around the call, though, so don't worry. Do check that the path you
+ * return is in fact the tty required, using IS_MYTTY below.
+ */
+/* read /proc/tty/drivers */
+static int tty_drivers(char *buf, size_t buflen, dev_t dev, ino64_t ino)
internal_function;
+/* attempt to guess from the device number */
+static int dev_guess(char *buf, size_t buflen, dev_t dev, ino64_t ino)
internal_function;
+/* search through the dirs in DEV_WALKS */
+static int walk_dev(char *buf, size_t buflen, dev_t dev, ino64_t ino)
internal_function;
- while ((d = __readdir64 (dirstream)) != NULL)
- if ((d->d_fileno == myino || *dostat)
- && strcmp (d->d_name, "stdin")
- && strcmp (d->d_name, "stdout")
- && strcmp (d->d_name, "stderr"))
- {
- char *cp;
- size_t needed = _D_EXACT_NAMLEN (d) + 1;
-
- if (needed > buflen)
- {
- *dostat = -1;
- (void) __closedir (dirstream);
- __set_errno (ERANGE);
- return ERANGE;
- }
+/* read a symlink */
+static int read_link(char *buf, size_t buflen, const char *name, dev_t dev,
ino64_t ino) internal_function;
- cp = __stpncpy (buf + devlen, d->d_name, needed);
- cp[0] = '\0';
+/* Get real dev if we are given /dev/tty. 0 for error. */
+static dev_t self_stat(void) internal_function;
- if (__xstat64 (_STAT_VER, buf, &st) == 0
#ifdef _STATBUF_ST_RDEV
- && S_ISCHR (st.st_mode) && st.st_rdev == mydev
+# define ST_RDEV st_rdev
+# define IS_MYTTY(st, dev, ino) (S_ISCHR((st).st_mode) && (st).st_rdev == dev)
#else
- && d->d_fileno == myino && st.st_dev == mydev
+# define ST_RDEV st_dev
+# define IS_MYTTY(st, dev, ino) ((st).st_ino == ino && (st).st_dev == dev)
#endif
- )
- {
- (void) __closedir (dirstream);
- __set_errno (save);
- return 0;
- }
- }
- (void) __closedir (dirstream);
- __set_errno (save);
- /* It is not clear what to return in this case. `isatty' says FD
- refers to a TTY but no entry in /dev has this inode. */
- return ENOTTY;
+static int internal_function
+tty_drivers(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+ FILE *ttydrv;
+ char fmt[TTY_NAME_MAX];
+ int maj, ret = 0;
+ struct stat64 ttyst;
+
+ ttydrv = fopen("/proc/tty/drivers", "r");
+ if (!ttydrv)
+ {
+ return -1;
+ }
+
+ while (fscanf(ttydrv, TTYDRV_FMT, fmt, &maj) != EOF)
+ {
+ if (maj == major(dev))
+ {
+ restat:
+ ret = snprintf(buf, buflen, fmt, minor(dev));
+ if (ret < 0 || ret > buflen)
+ {
+ ret = ERANGE;
+ break;
+ }
+
+ ret = -1;
+
+ if (!__xstat64(_STAT_VER, buf, &ttyst) && IS_MYTTY(ttyst, dev, ino))
+ {
+ ret = 0;
+ break;
+ }
+ else
+ {
+ if (!strstr(fmt, "%d") && !strchr(fmt + 5, '/'))
+ {
+ if (!strcmp(fmt, "/dev/pts"))
+ strcat(fmt, "/%d");
+ else
+ strcat(fmt, "%d");
+ goto restat;
+ }
+ }
+ }
+ }
+
+ fclose(ttydrv);
+ return ret;
}
-/* Store at most BUFLEN character of the pathname of the terminal FD is
- open on in BUF. Return 0 on success, otherwise an error number. */
-int
-__ttyname_r (int fd, char *buf, size_t buflen)
+static int internal_function
+read_link(char *buf, size_t buflen, const char *name, dev_t dev, ino64_t ino)
{
- char procname[30];
- struct stat64 st, st1;
- int dostat = 0;
- int save = errno;
int ret;
+ struct stat64 st;
- /* Test for the absolute minimal size. This makes life easier inside
- the loop. */
- if (!buf)
- {
- __set_errno (EINVAL);
- return EINVAL;
- }
+ ret = __readlink (name, buf, buflen - 1);
- if (buflen < sizeof ("/dev/pts/"))
+ if (ret == -1 && (errno == ENAMETOOLONG || errno == ERANGE))
{
- __set_errno (ERANGE);
return ERANGE;
}
- /* We try using the /proc filesystem. */
- *_fitoa_word (fd, __stpcpy (procname, "/proc/self/fd/"), 10, 0) = '\0';
-
- ret = __readlink (procname, buf, buflen - 1);
- if (ret == -1 && errno == ENOENT)
+ if (ret != -1 && buf[0] != '[' && (!ino || /* /proc/self/tty is definitive */
+ (!__xstat64(_STAT_VER, buf, &st) &&
+ IS_MYTTY(st, dev, ino))))
{
- __set_errno (EBADF);
- return EBADF;
+ buf[ret] = 0;
+ return 0;
}
- if (!__isatty (fd))
- {
- __set_errno (ENOTTY);
- return ENOTTY;
- }
+ return -1;
+}
- if (ret == -1 && errno == ENAMETOOLONG)
- {
- __set_errno (ERANGE);
- return ERANGE;
- }
+/*
+ * This function is a slightly modified version of
+ * proc/devname.c:guess_name from procps-3.1.9
+ * by Albert Cahalan.
+ * That file is distributed under the LGPL.
+ *
+ * This function fails for devfs names; however, we try this after
+ * we try /proc/tty/drivers so we will only fail for (devfs &&
+ * no old names && /proc not mounted) which is pretty unlikely.
+ */
+static int internal_function
+dev_guess(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+ int maj, min, tmpmin, rvi;
+ char t0, t1;
+ struct stat64 sbuf;
+
+ maj = major(dev);
+ min = minor(dev);
+ tmpmin = min;
+
+ switch(maj){
+ case 4:
+ if(min<64){
+ rvi = snprintf(buf, buflen, "/dev/tty%d", min);
+ break;
+ }
+ if(min<128){ /* to 255 on newer systems */
+ rvi = snprintf(buf, buflen, "/dev/ttyS%d", min-64);
+ break;
+ }
+ tmpmin = min & 0x3f; /* FALL THROUGH */
+ case 3: /* /dev/[pt]ty[p-za-o][0-9a-z] is 936 */
+ t0 = "pqrstuvwxyzabcde"[tmpmin>>4];
+ t1 = "0123456789abcdef"[tmpmin&0x0f];
+ rvi = snprintf(buf, buflen, "/dev/tty%c%c", t0, t1);
+ break;
+ case 17: rvi = snprintf(buf, buflen, "/dev/ttyH%d", min); break;
+ case 19: rvi = snprintf(buf, buflen, "/dev/ttyC%d", min); break;
+ case 22: rvi = snprintf(buf, buflen, "/dev/ttyD%d", min); break; /*
devices.txt */
+ case 23: rvi = snprintf(buf, buflen, "/dev/ttyD%d", min); break; /*
driver code */
+ case 24: rvi = snprintf(buf, buflen, "/dev/ttyE%d", min); break;
+ case 32: rvi = snprintf(buf, buflen, "/dev/ttyX%d", min); break;
+ case 43: rvi = snprintf(buf, buflen, "/dev/ttyI%d", min); break;
+ case 46: rvi = snprintf(buf, buflen, "/dev/ttyR%d", min); break;
+ case 48: rvi = snprintf(buf, buflen, "/dev/ttyL%d", min); break;
+ case 57: rvi = snprintf(buf, buflen, "/dev/ttyP%d", min); break;
+ case 71: rvi = snprintf(buf, buflen, "/dev/ttyF%d", min); break;
+ case 75: rvi = snprintf(buf, buflen, "/dev/ttyW%d", min); break;
+ case 78: rvi = snprintf(buf, buflen, "/dev/ttyM%d", min); break; /*
conflict */
+ case 105: rvi = snprintf(buf, buflen, "/dev/ttyV%d", min); break;
+ case 112: rvi = snprintf(buf, buflen, "/dev/ttyM%d", min); break; /*
conflict */
+ /* 136 ... 143 are /dev/pts/0, /dev/pts/1, /dev/pts/2 ... */
+ case 136 ... 143: rvi = snprintf(buf, buflen, "/dev/pts/%d",
min+(maj-136)*256); break;
+ case 148: rvi = snprintf(buf, buflen, "/dev/ttyT%d", min); break;
+ case 154: rvi = snprintf(buf, buflen, "/dev/ttySR%d", min); break;
+ case 156: rvi = snprintf(buf, buflen, "/dev/ttySR%d", min+256); break;
+ case 164: rvi = snprintf(buf, buflen, "/dev/ttyCH%d", min); break;
+ case 166: rvi = snprintf(buf, buflen, "/dev/ttyACM%d", min); break; /*
bummer, 9-char */
+ case 172: rvi = snprintf(buf, buflen, "/dev/ttyMX%d", min); break;
+ case 174: rvi = snprintf(buf, buflen, "/dev/ttySI%d", min); break;
+ case 188: rvi = snprintf(buf, buflen, "/dev/ttyUSB%d", min); break; /*
bummer, 9-char */
+ default: return -1;
+ }
- if (ret != -1 && buf[0] != '[')
- {
- buf[ret] = '\0';
- return 0;
- }
+ if (rvi < 0 || rvi > buflen)
+ return ERANGE;
- if (__fxstat64 (_STAT_VER, fd, &st) < 0)
- return errno;
+ if (!__xstat64(_STAT_VER, buf, &sbuf) && IS_MYTTY(sbuf, dev, ino))
+ return 0;
- /* Prepare the result buffer. */
- memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/"));
- buflen -= sizeof ("/dev/pts/") - 1;
+ return -1;
+}
- if (__xstat64 (_STAT_VER, buf, &st1) == 0 && S_ISDIR (st1.st_mode))
- {
-#ifdef _STATBUF_ST_RDEV
- ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
- &dostat);
-#else
- ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
- &dostat);
-#endif
- }
- else
+static int internal_function
+walk_dev(char *buf, size_t buflen, dev_t dev, ino64_t ino)
+{
+ struct stat64 st;
+ DIR *dirstream;
+ struct dirent64 *d;
+ const char *walks[] = DEV_WALKS, **i;
+ int ret;
+
+ for(i = walks; *i; i++)
{
- __set_errno (save);
- ret = ENOENT;
+ dirstream = __opendir (*i);
+ if (dirstream == NULL)
+ continue;
+
+/* this fails if we are under chroot and our tty was opened before the chroot:
+ * the correct dev file will now have a different ino.
+ */
+ while ((d = __readdir64 (dirstream)) != NULL)
+ if ((!ino || d->d_fileno == ino) /* if we are looking for a real
+ * device for /dev/tty we have to
+ * stat every entry in /dev:
+ * too bad :(.
+ */
+ && strcmp (d->d_name, "stdin")
+ && strcmp (d->d_name, "stdout")
+ && strcmp (d->d_name, "stderr"))
+ {
+ ret = snprintf(buf, buflen, "%s/%s", *i, d->d_name);
+ if (ret < 0 || ret >= buflen)
+ {
+ ret = ERANGE;
+ goto out;
+ }
+
+ ret = -1;
+
+ if (!__xstat64 (_STAT_VER, buf, &st) && IS_MYTTY(st, dev, ino))
+ {
+ ret = 0;
+ goto out;
+ }
+ }
+
+ (void) __closedir(dirstream);
}
- if (ret && dostat != -1)
+ return -1;
+
+out:
+ (void) __closedir (dirstream);
+ return ret;
+}
+
+static dev_t internal_function
+self_stat(void)
+{
+ FILE *fp;
+ int tty = 0;
+
+ fp = fopen("/proc/self/stat", "r");
+ if (!fp)
+ return 0;
+
+ if (fscanf(fp, STAT_FMT, &tty) == EOF)
+ tty = 0;
+
+ fclose(fp);
+ return tty;
+}
+
+int
+__ttyname_r (int fd, char *buf, size_t buflen)
+{
+ char linkname[sizeof("/proc/self/fd/12345678")];
+ struct stat64 st;
+ dev_t dev;
+ ino64_t ino;
+ int ret, errno_save;
+
+ errno_save = errno;
+
+ ret = EINVAL;
+ if (!buf) goto out;
+
+ ret = ENOTTY;
+ if (!__isatty(fd)) goto out;
+
+ ret = __fxstat64(_STAT_VER, fd, &st);
+ if (ret)
{
- buf[sizeof ("/dev/") - 1] = '\0';
- buflen += sizeof ("pts/") - 1;
-#ifdef _STATBUF_ST_RDEV
- ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
- &dostat);
-#else
- ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
- &dostat);
-#endif
+ ret = errno;
+ goto out;
}
- if (ret && dostat != -1)
+ dev = st.ST_RDEV;
+ ino = st.st_ino;
+
+ if (dev == DEV_TTY_NUM)
{
- buf[sizeof ("/dev/") - 1] = '\0';
- dostat = 1;
+ ino = 0;
+ ret = read_link(buf, buflen, "/proc/self/tty", dev, ino);
+ if (ret >= 0) goto out;
+
#ifdef _STATBUF_ST_RDEV
- ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino,
- save, &dostat);
+ dev = self_stat();
#else
- ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino,
- save, &dostat);
+ dev = 0;
+ /* /proc/self/stat won't give us the ino */
#endif
+ if (!dev)
+ {
+ ret = 0;
+ /* yes, it's pretty useless, but it's the best we can do */
+ if (buflen < sizeof("/dev/tty"))
+ ret = ERANGE;
+ else
+ strncpy(buf, "/dev/tty", buflen);
+
+ goto out;
+ }
+ }
+
+
+ ret = tty_drivers(buf, buflen, dev, ino);
+ if(ret >= 0) goto out;
+
+ ret = dev_guess(buf, buflen, dev, ino);
+ if (ret >= 0) goto out;
+
+ if (ino)
+ {
+ sprintf(linkname, "/proc/self/fd/%d", fd);
+ ret = read_link(buf, buflen, linkname, dev, ino);
+ if (ret >=0 ) goto out;
}
+ ret = walk_dev(buf, buflen, dev, ino);
+ if (ret < 0) ret = ENOENT;
+
+out:
+ __set_errno(errno_save);
return ret;
}
-weak_alias (__ttyname_r, ttyname_r)
+weak_alias (__ttyname_r, ttyname_r);
---END DIFF---
--
Musica Dei donum optimi, trahit homines, trahit deos. |
Musica truces molit animos, tristesque mentes erigit. | address@hidden
Musica vel ipsas arbores et horridas movet feras. |
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- ttyname fails for setid programs under linux/devfs,
ben <=