# include <linux/serial.h>
# include <linux/major.h>
#endif
-#include <fcntl.h>
#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <unistd.h>
#ifdef USE_SULOGIN_EMERGENCY_MOUNT
} while (0)
static inline void __attribute__ ((__format__ (__printf__, 1, 2)))
-dbgprint(const char *mesg, ...)
+dbgprint(const char * const mesg, ...)
{
va_list ap;
va_start(ap, mesg);
}
if (stat("/", &rt) != 0) {
- warn("can not get file status of root file system\n");
+ warn("cannot get file status of root file system\n");
return;
}
* the caller has to free the result
*/
static __attribute__((__nonnull__))
-char *oneline(const char *file)
+char *oneline(const char * const file)
{
FILE *fp;
char *ret = NULL;
- size_t len = 0;
+ size_t dummy = 0;
+ ssize_t len;
DBG(dbgprint("reading %s", file));
- if (!(fp = fopen(file, "re")))
+ if (!(fp = fopen(file, "r" UL_CLOEXECSTR)))
return NULL;
- if (getline(&ret, &len, fp) >= 0) {
+ len = getline(&ret, &dummy, fp);
+ if (len >= 0) {
char *nl;
if (len)
* /sys/class/tty, the caller has to free the result.
*/
static __attribute__((__malloc__))
-char *actattr(const char *tty)
+char *actattr(const char * const tty)
{
char *ret, *path;
* /sys/class/tty.
*/
static
-dev_t devattr(const char *tty)
+dev_t devattr(const char * const tty)
{
dev_t dev = 0;
char *path, *value;
#endif /* __linux__ */
/*
- * Search below /dev for the characer device in `dev_t comparedev' variable.
+ * Search below /dev for the character device in `dev_t comparedev' variable.
+ * Note that realpath(3) is used here to avoid not existent devices due the
+ * strdup(3) used in our canonicalize_path()!
*/
static
#ifdef __GNUC__
__attribute__((__nonnull__,__malloc__,__hot__))
#endif
-char* scandev(DIR *dir, dev_t comparedev)
+char* scandev(DIR *dir, const dev_t comparedev)
{
+ char path[PATH_MAX];
char *name = NULL;
- struct dirent *dent;
- int fd;
+ const struct dirent *dent;
+ int len, fd;
DBG(dbgprint("scanning /dev for %u:%u", major(comparedev), minor(comparedev)));
+ /*
+ * Try udev links on character devices first.
+ */
+ if ((len = snprintf(path, sizeof(path),
+ "/dev/char/%u:%u", major(comparedev), minor(comparedev))) > 0 &&
+ (size_t)len < sizeof(path)) {
+
+ name = realpath(path, NULL);
+ if (name)
+ goto out;
+ }
+
fd = dirfd(dir);
rewinddir(dir);
while ((dent = readdir(dir))) {
- char path[PATH_MAX];
struct stat st;
+
+#ifdef _DIRENT_HAVE_D_TYPE
+ if (dent->d_type != DT_UNKNOWN && dent->d_type != DT_CHR)
+ continue;
+#endif
if (fstatat(fd, dent->d_name, &st, 0) < 0)
continue;
if (!S_ISCHR(st.st_mode))
continue;
if (comparedev != st.st_rdev)
continue;
- if ((size_t)snprintf(path, sizeof(path), "/dev/%s", dent->d_name) >= sizeof(path))
+ if ((len = snprintf(path, sizeof(path), "/dev/%s", dent->d_name)) < 0 ||
+ (size_t)len >= sizeof(path))
continue;
-#ifdef USE_SULOGIN_EMERGENCY_MOUNT
- if (emergency_flags & MNT_DEVTMPFS)
- mknod(path, S_IFCHR|S_IRUSR|S_IWUSR, comparedev);
-#endif
- name = canonicalize_path(path);
- break;
+ name = realpath(path, NULL);
+ if (name)
+ goto out;
}
+#ifdef USE_SULOGIN_EMERGENCY_MOUNT
+ /*
+ * There was no /dev mounted hence and no device was found hence we create our own.
+ */
+ if (!name && (emergency_flags & MNT_DEVTMPFS)) {
+
+ if ((len = snprintf(path, sizeof(path),
+ "/dev/tmp-%u:%u", major(comparedev), minor(comparedev))) < 0 ||
+ (size_t)len >= sizeof(path))
+ goto out;
+
+ if (mknod(path, S_IFCHR|S_IRUSR|S_IWUSR, comparedev) < 0 && errno != EEXIST)
+ goto out;
+
+ name = realpath(path, NULL);
+ }
+#endif
+out:
return name;
}
*/
static
#ifdef __GNUC__
-__attribute__((__nonnull__,__hot__))
+__attribute__((__hot__))
#endif
-int append_console(struct list_head *consoles, const char *name)
+int append_console(struct list_head *consoles, const char * const name)
{
struct console *restrict tail;
- struct console *last = NULL;
+ const struct console *last = NULL;
DBG(dbgprint("appenging %s", name));
tail->flags = 0;
tail->fd = -1;
tail->id = last ? last->id + 1 : 0;
- tail->pid = 0;
+ tail->pid = -1;
memset(&tail->tio, 0, sizeof(tail->tio));
return 0;
char fbuf[16 + 1];
DIR *dir = NULL;
FILE *fc = NULL;
- int maj, min, rc = 1;
+ int maj, min, rc = 1, matches;
DBG(dbgprint("trying /proc"));
- fc = fopen("/proc/consoles", "re");
+ fc = fopen("/proc/consoles", "r" UL_CLOEXECSTR);
if (!fc) {
rc = 2;
goto done;
if (!dir)
goto done;
- while (fscanf(fc, "%*s %*s (%16[^)]) %d:%d", fbuf, &maj, &min) == 3) {
+ while ((matches = fscanf(fc, "%*s %*s (%16[^)]) %d:%d", fbuf, &maj, &min)) >= 1) {
char *name;
dev_t comparedev;
+ if (matches != 3)
+ continue;
if (!strchr(fbuf, 'E'))
continue;
comparedev = makedev(maj, min);
return rc;
}
+#ifdef TIOCGDEV
static int detect_consoles_from_tiocgdev(struct list_head *consoles,
- int fallback,
+ const int fallback,
const char *device)
{
-#ifdef TIOCGDEV
unsigned int devnum;
char *name;
int rc = 1, fd = -1;
close(fd);
DBG(dbgprint("[tiocgdev rc=%d]", rc));
return rc;
-#endif
- return 2;
}
+#endif /* TIOCGDEV */
#endif /* __linux__ */
/*
* Returns 1 if stdout and stderr should be reconnected and 0
* otherwise or less than zero on error.
*/
-int detect_consoles(const char *device, int fallback, struct list_head *consoles)
+int detect_consoles(const char *device, const int fallback, struct list_head *consoles)
{
int fd, reconnect = 0, rc;
dev_t comparedev = 0;
consoles_debug = getenv("CONSOLES_DEBUG") ? 1 : 0;
if (!device || !*device)
- fd = dup(fallback);
+ fd = fallback >= 0 ? dup(fallback) : - 1;
else {
fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY|O_CLOEXEC);
reconnect = 1;
struct stat st;
#ifdef TIOCGDEV
unsigned int devnum;
+#endif
+#ifdef __GNU__
+ /*
+ * The Hurd always gives st_rdev as 0, which causes this
+ * method to select the first terminal it finds.
+ */
+ close(fd);
+ goto fallback;
#endif
DBG(dbgprint("trying device/fallback file descriptor"));
#ifdef __linux__
console:
/*
- * Detection of devices used for Linux system consolei using
+ * Detection of devices used for Linux system console using
* the /proc/consoles API with kernel 2.6.38 and higher.
*/
rc = detect_consoles_from_proc(consoles);
* Detection of the device used for Linux system console using
* the ioctl TIOCGDEV if available (e.g. official 2.6.38).
*/
+#ifdef TIOCGDEV
rc = detect_consoles_from_tiocgdev(consoles, fallback, device);
if (rc == 0)
return reconnect; /* success */
if (rc < 0)
return rc; /* fatal error */
-
+#endif
if (!list_empty(consoles)) {
DBG(dbgprint("detection success [rc=%d]", reconnect));
return reconnect;
fallback:
if (fallback >= 0) {
const char *name;
+ char *n;
struct console *console;
if (device && *device != '\0')
if (!name)
name = "/dev/tty";
- rc = append_console(consoles, strdup(name));
+ n = strdup(name);
+ if (!n)
+ return -ENOMEM;
+ rc = append_console(consoles, n);
+ free(n);
if (rc < 0)
return rc;
if (list_empty(consoles))
{
char *name = NULL;
int fd, re;
- LIST_HEAD(consoles);
- struct list_head *p;
+ struct list_head *p, consoles;
if (argc == 2) {
name = argv[1];
if (!name)
errx(EXIT_FAILURE, "usage: %s [<tty>]\n", program_invocation_short_name);
+ INIT_LIST_HEAD(&consoles);
re = detect_consoles(name, fd, &consoles);
list_for_each(p, &consoles) {