]>
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>
34 # include <linux/serial.h>
42 # include <linux/major.h>
45 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
47 # define typeof __typeof__
50 # define restrict __restrict__
54 #define alignof(type) ((sizeof(type)+(sizeof(void*)-1)) & ~(sizeof(void*)-1))
56 struct console
*consoles
;
59 * Read and allocate one line from file,
60 * the caller has to free the result
64 __attribute__((__nonnull__
))
66 char *oneline(const char *file
)
69 char *ret
= (char*)0, *nl
;
72 if ((fp
= fopen(file
, "re")) == (FILE*)0)
74 if (getline(&ret
, &len
, fp
) < 0)
78 if ((nl
= strchr(ret
, '\n')))
88 * Read and determine active attribute for tty below
89 * /sys/class/tty, the caller has to free the result.
92 __attribute__((__malloc__
))
93 char *actattr(const char *tty
)
98 if (!tty
|| *tty
== '\0')
101 if (asprintf(&path
, "/sys/class/tty/%s/active", tty
) < 0)
104 if ((ret
= oneline(path
)) == (char*)0)
113 * Read and determine device attribute for tty below
117 dev_t
devattr(const char *tty
)
119 unsigned int maj
, min
;
123 if (!tty
|| *tty
== '\0')
126 if (asprintf(&path
, "/sys/class/tty/%s/dev", tty
) < 0)
129 if ((value
= oneline(path
)) == (char*)0)
132 if (sscanf(value
, "%u:%u", &maj
, &min
) == 2)
133 dev
= makedev(maj
, min
);
140 #endif /* __linux__ */
143 * Search below /dev for the characer device in
144 * the local `dev_t comparedev' variable.
146 static dev_t comparedev
;
149 __attribute__((__nonnull__
,__malloc__
,__hot__
))
151 char* scandev(DIR *dir
)
153 char *name
= (char*)0;
159 while ((dent
= readdir(dir
))) {
162 if (fstatat(fd
, dent
->d_name
, &st
, 0) < 0)
164 if (!S_ISCHR(st
.st_mode
))
166 if (comparedev
!= st
.st_rdev
)
168 if ((size_t)snprintf(path
, sizeof(path
), "/dev/%s", dent
->d_name
) >= sizeof(path
))
170 name
= realpath(path
, NULL
);
177 * Default control characters for an unknown terminal line.
180 struct chardata initcp
= {
188 * Allocate an aligned `struct console' memory area,
189 * initialize its default values, and append it to
190 * the global linked list.
193 static int concount
; /* Counter for console IDs */
197 __attribute__((__nonnull__
,__hot__
))
199 void consalloc(char * name
)
201 struct console
*restrict tail
;
203 if (posix_memalign((void*)&tail
, sizeof(void*), alignof(typeof(struct console
))) != 0)
204 perror("memory allocation");
206 tail
->next
= (struct console
*)0;
209 tail
->file
= (FILE*)0;
212 tail
->id
= concount
++;
214 memset(&tail
->tio
, 0, sizeof(tail
->tio
));
215 memcpy(&tail
->cp
, &initcp
, sizeof(struct chardata
));
220 consoles
->next
= tail
;
224 * Try to detect the real device(s) used for the system console
225 * /dev/console if but only if /dev/console is used. On Linux
226 * this can be more than one device, e.g. a serial line as well
227 * as a virtual console as well as a simple printer.
229 void detect_consoles(const char *device
, int fallback
)
233 char *attrib
, *cmdline
;
236 if (!device
|| *device
== '\0')
238 else fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
248 if (fstat(fd
, &st
) < 0) {
252 comparedev
= st
.st_rdev
;
255 * Check if the device detection for Linux system console should be used.
257 if (comparedev
== makedev(TTYAUX_MAJOR
, 0)) { /* /dev/tty */
262 if (comparedev
== makedev(TTYAUX_MAJOR
, 1)) { /* /dev/console */
266 if (comparedev
== makedev(TTYAUX_MAJOR
, 2)) { /* /dev/ptmx */
271 if (comparedev
== makedev(TTY_MAJOR
, 0)) { /* /dev/tty0 */
273 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
277 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
281 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
285 comparedev
= (dev_t
)devnum
;
288 dir
= opendir("/dev");
302 * Detection of devices used for Linux system consolei using
303 * the /proc/consoles API with kernel 2.6.38 and higher.
305 if ((fc
= fopen("/proc/consoles", "re"))) {
309 dir
= opendir("/dev");
314 while ((fscanf(fc
, "%*s %*s (%[^)]) %d:%d", &fbuf
[0], &maj
, &min
) == 3)) {
317 if (!strchr(fbuf
, 'E'))
319 comparedev
= makedev(maj
, min
);
331 * Detection of devices used for Linux system console using
332 * the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
334 if ((attrib
= actattr("console"))) {
335 char *words
= attrib
, *token
;
338 dir
= opendir("/dev");
343 while ((token
= strsep(&words
, " \t\r\n"))) {
348 comparedev
= devattr(token
);
349 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
350 char *tmp
= actattr(token
);
353 comparedev
= devattr(tmp
);
370 * Detection of devices used for Linux system console using
371 * kernel parameter on the kernels command line.
373 if ((cmdline
= oneline("/proc/cmdline"))) {
374 char *words
= cmdline
, *token
;
377 dir
= opendir("/dev");
382 while ((token
= strsep(&words
, " \t\r\n"))) {
394 if (strncmp(token
, "console=", 8) != 0)
398 if (strcmp(token
, "brl") == 0)
400 if ((colon
= strchr(token
, ',')))
403 if (asprintf(&name
, "/dev/%s", token
) < 0)
406 if ((fd
= open(name
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
)) < 0) {
412 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
416 comparedev
= (dev_t
)devnum
;
418 if (fstat(fd
, &st
) < 0) {
422 comparedev
= st
.st_rdev
;
423 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
424 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
428 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
441 * Detection of the device used for Linux system console using
442 * the ioctl TIOCGDEV if available (e.g. official 2.6.38).
449 if (!device
|| *device
== '\0')
451 else fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
456 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
460 comparedev
= (dev_t
)devnum
;
463 if (device
&& *device
!= '\0')
465 else name
= ttyname(fallback
);
470 consalloc(strdup(name
));
472 if (!device
|| *device
== '\0')
473 consoles
->fd
= fallback
;
481 #endif /* __linux __ */
486 if (device
&& *device
!= '\0')
488 else name
= ttyname(fallback
);
493 consalloc(strdup(name
));
495 consoles
->fd
= fallback
;