When looking for a device match, do a breadth-first search instead
of depth-first. We already special case /dev/pts/ so chances are good that if it is not a pseudo-tty it is in the base of /dev/. Also avoid a stat(2) when possible if struct dirent has d_type.
This commit is contained in:
@@ -154,7 +154,7 @@ sudo_ttyname_dev(dev_t tdev)
|
|||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/*
|
/*
|
||||||
* Devices to search before doing a depth-first scan.
|
* Devices to search before doing a breadth-first scan.
|
||||||
* XXX - use /etc/ttysrch too (for Solaris).
|
* XXX - use /etc/ttysrch too (for Solaris).
|
||||||
* XXX - add tty* w/ wildcards?
|
* XXX - add tty* w/ wildcards?
|
||||||
*/
|
*/
|
||||||
@@ -177,14 +177,14 @@ static char *ignore_devs[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a depth-first scan of dir looking for the specified device.
|
* Do a breadth-first scan of dir looking for the specified device.
|
||||||
*/
|
*/
|
||||||
static
|
static
|
||||||
char *sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin)
|
char *sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin)
|
||||||
{
|
{
|
||||||
DIR *d;
|
DIR *d;
|
||||||
char pathbuf[PATH_MAX], *devname = NULL;
|
char pathbuf[PATH_MAX], **subdirs = NULL, *devname = NULL;
|
||||||
size_t sdlen, d_len, len;
|
size_t sdlen, d_len, len, num_subdirs = 0, max_subdirs = 0;
|
||||||
struct dirent *dp;
|
struct dirent *dp;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
int i;
|
int i;
|
||||||
@@ -237,21 +237,41 @@ char *sudo_ttyname_scan(const char *dir, dev_t rdev, bool builtin)
|
|||||||
if (search_devs[i] != NULL)
|
if (search_devs[i] != NULL)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (stat(pathbuf, &sb) == 0) {
|
# if defined(HAVE_STRUCT_DIRENT_D_TYPE) && defined(DTTOIF)
|
||||||
if (S_ISDIR(sb.st_mode)) {
|
/* Use d_type to avoid a stat() if possible. */
|
||||||
if (!builtin)
|
/* Convert d_type to stat-style type bits but follow links. */
|
||||||
devname = sudo_ttyname_scan(pathbuf, rdev, builtin);
|
if (dp->d_type != DT_LNK && dp->d_type != DT_CHR)
|
||||||
continue;
|
sb.st_mode = DTTOIF(dp->d_type);
|
||||||
}
|
else
|
||||||
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
|
# endif
|
||||||
devname = estrdup(pathbuf);
|
if (stat(pathbuf, &sb) == -1)
|
||||||
break;
|
continue;
|
||||||
|
if (S_ISDIR(sb.st_mode)) {
|
||||||
|
if (!builtin) {
|
||||||
|
/* Add to list of subdirs to search. */
|
||||||
|
if (num_subdirs + 1 > max_subdirs) {
|
||||||
|
max_subdirs += 64;
|
||||||
|
subdirs = erealloc3(subdirs, max_subdirs, sizeof(char *));
|
||||||
|
}
|
||||||
|
subdirs[num_subdirs++] = estrdup(pathbuf);
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (S_ISCHR(sb.st_mode) && sb.st_rdev == rdev) {
|
||||||
|
devname = estrdup(pathbuf);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
closedir(d);
|
closedir(d);
|
||||||
|
|
||||||
|
/* Search subdirs if we didn't find it in the root level. */
|
||||||
|
for (i = 0; devname == NULL && i < num_subdirs; i++)
|
||||||
|
devname = sudo_ttyname_scan(subdirs[i], rdev, false);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
for (i = 0; i < num_subdirs; i++)
|
||||||
|
efree(subdirs[i]);
|
||||||
|
efree(subdirs);
|
||||||
debug_return_str(devname);
|
debug_return_str(devname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +319,7 @@ sudo_ttyname_dev(dev_t rdev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not found? Do a depth-first traversal of /dev/.
|
* Not found? Do a breadth-first traversal of /dev/.
|
||||||
*/
|
*/
|
||||||
if (tty == NULL)
|
if (tty == NULL)
|
||||||
tty = sudo_ttyname_scan(_PATH_DEV, rdev, false);
|
tty = sudo_ttyname_scan(_PATH_DEV, rdev, false);
|
||||||
|
Reference in New Issue
Block a user