]>
git.wh0rd.org - sysvinit.git/blob - src/consoles.c
2 * consoles.c Routines to detect the system consoles
4 * Copyright (c) 2011 SuSE LINUX Products GmbH, All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21 * Author: Werner Fink <werner@suse.de>
28 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 #include <sys/ttydefaults.h>
35 # include <linux/serial.h>
43 # include <linux/major.h>
46 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
48 # define typeof __typeof__
51 # define restrict __restrict__
55 #define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
57 struct console
*consoles
;
60 * Read and allocate one line from file,
61 * the caller has to free the result
65 __attribute__((__nonnull__
))
67 char *oneline(const char *file
)
70 char *ret
= (char*)0, *nl
;
73 if ((fp
= fopen(file
, "re")) == (FILE*)0)
75 if (getline(&ret
, &len
, fp
) < 0)
79 if ((nl
= strchr(ret
, '\n')))
89 * Read and determine active attribute for tty below
90 * /sys/class/tty, the caller has to free the result.
93 __attribute__((__malloc__
))
94 char *actattr(const char *tty
)
99 if (!tty
|| *tty
== '\0')
102 if (asprintf(&path
, "/sys/class/tty/%s/active", tty
) < 0)
105 if ((ret
= oneline(path
)) == (char*)0)
114 * Read and determine device attribute for tty below
118 dev_t
devattr(const char *tty
)
120 unsigned int maj
, min
;
124 if (!tty
|| *tty
== '\0')
127 if (asprintf(&path
, "/sys/class/tty/%s/dev", tty
) < 0)
130 if ((value
= oneline(path
)) == (char*)0)
133 if (sscanf(value
, "%u:%u", &maj
, &min
) == 2)
134 dev
= makedev(maj
, min
);
141 #endif /* __linux__ */
144 * Search below /dev for the characer device in
145 * the local `dev_t comparedev' variable.
147 static dev_t comparedev
;
150 __attribute__((__nonnull__
,__malloc__
,__hot__
))
152 char* scandev(DIR *dir
)
154 char *name
= (char*)0;
160 while ((dent
= readdir(dir
))) {
163 if (fstatat(fd
, dent
->d_name
, &st
, 0) < 0)
165 if (!S_ISCHR(st
.st_mode
))
167 if (comparedev
!= st
.st_rdev
)
169 if ((size_t)snprintf(path
, sizeof(path
), "/dev/%s", dent
->d_name
) >= sizeof(path
))
171 name
= realpath(path
, NULL
);
178 * Default control characters for an unknown terminal line.
181 struct chardata initcp
= {
189 * Allocate an aligned `struct console' memory area,
190 * initialize its default values, and append it to
191 * the global linked list.
194 static int concount
; /* Counter for console IDs */
198 __attribute__((__nonnull__
,__hot__
))
200 void consalloc(char * name
)
202 struct console
*restrict tail
;
204 if (posix_memalign((void*)&tail
, sizeof(void*), alignof(typeof(struct console
))) != 0)
205 perror("memory allocation");
207 tail
->next
= (struct console
*)0;
210 tail
->file
= (FILE*)0;
213 tail
->id
= concount
++;
215 memset(&tail
->tio
, 0, sizeof(tail
->tio
));
216 memcpy(&tail
->cp
, &initcp
, sizeof(struct chardata
));
221 consoles
->next
= tail
;
225 * Try to detect the real device(s) used for the system console
226 * /dev/console if but only if /dev/console is used. On Linux
227 * this can be more than one device, e.g. a serial line as well
228 * as a virtual console as well as a simple printer.
230 * Returns 1 if stdout and stderr should be reconnected and 0
233 int detect_consoles(const char *device
, int fallback
)
237 char *attrib
, *cmdline
;
240 if (!device
|| *device
== '\0')
243 fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
255 if (fstat(fd
, &st
) < 0) {
259 comparedev
= st
.st_rdev
;
261 if (ret
&& (fstat(fallback
, &st
) < 0 || comparedev
!= st
.st_rdev
))
265 * Check if the device detection for Linux system console should be used.
267 if (comparedev
== makedev(TTYAUX_MAJOR
, 0)) { /* /dev/tty */
272 if (comparedev
== makedev(TTYAUX_MAJOR
, 1)) { /* /dev/console */
276 if (comparedev
== makedev(TTYAUX_MAJOR
, 2)) { /* /dev/ptmx */
281 if (comparedev
== makedev(TTY_MAJOR
, 0)) { /* /dev/tty0 */
283 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
287 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
291 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
295 comparedev
= (dev_t
)devnum
;
298 dir
= opendir("/dev");
312 * Detection of devices used for Linux system consolei using
313 * the /proc/consoles API with kernel 2.6.38 and higher.
315 if ((fc
= fopen("/proc/consoles", "re"))) {
319 dir
= opendir("/dev");
324 while ((fscanf(fc
, "%*s %*s (%[^)]) %d:%d", &fbuf
[0], &maj
, &min
) == 3)) {
327 if (!strchr(fbuf
, 'E'))
329 comparedev
= makedev(maj
, min
);
341 * Detection of devices used for Linux system console using
342 * the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
344 if ((attrib
= actattr("console"))) {
345 char *words
= attrib
, *token
;
348 dir
= opendir("/dev");
353 while ((token
= strsep(&words
, " \t\r\n"))) {
358 comparedev
= devattr(token
);
359 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
360 char *tmp
= actattr(token
);
363 comparedev
= devattr(tmp
);
380 * Detection of devices used for Linux system console using
381 * kernel parameter on the kernels command line.
383 if ((cmdline
= oneline("/proc/cmdline"))) {
384 char *words
= cmdline
, *token
;
387 dir
= opendir("/dev");
392 while ((token
= strsep(&words
, " \t\r\n"))) {
404 if (strncmp(token
, "console=", 8) != 0)
408 if (strcmp(token
, "brl") == 0)
410 if ((colon
= strchr(token
, ',')))
413 if (asprintf(&name
, "/dev/%s", token
) < 0)
416 if ((fd
= open(name
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
)) < 0) {
422 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
426 comparedev
= (dev_t
)devnum
;
428 if (fstat(fd
, &st
) < 0) {
432 comparedev
= st
.st_rdev
;
433 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
434 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
438 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
451 * Detection of the device used for Linux system console using
452 * the ioctl TIOCGDEV if available (e.g. official 2.6.38).
459 if (!device
|| *device
== '\0')
461 else fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
466 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
470 comparedev
= (dev_t
)devnum
;
473 if (device
&& *device
!= '\0')
475 else name
= ttyname(fallback
);
480 consalloc(strdup(name
));
482 if (!device
|| *device
== '\0')
483 consoles
->fd
= fallback
;
491 #endif /* __linux __ */
496 if (device
&& *device
!= '\0')
498 else name
= ttyname(fallback
);
503 consalloc(strdup(name
));
505 consoles
->fd
= fallback
;