]>
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,
89 * 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)
112 /* Read and determine device attribute for tty */
114 dev_t
devattr(const char *tty
)
116 unsigned int maj
, min
;
120 if (!tty
|| *tty
== '\0')
123 if (asprintf(&path
, "/sys/class/tty/%s/dev", tty
) < 0)
126 if ((value
= oneline(path
)) == (char*)0)
129 if (sscanf(value
, "%u:%u", &maj
, &min
) == 2)
130 dev
= makedev(maj
, min
);
137 #endif /* __linux__ */
139 static dev_t comparedev
;
142 __attribute__((__nonnull__
,__malloc__
,__hot__
))
144 char* scandev(DIR *dir
)
146 char *name
= (char*)0;
152 while ((dent
= readdir(dir
))) {
155 if (fstatat(fd
, dent
->d_name
, &st
, 0) < 0)
157 if (!S_ISCHR(st
.st_mode
))
159 if (comparedev
!= st
.st_rdev
)
161 if ((size_t)snprintf(path
, sizeof(path
), "/dev/%s", dent
->d_name
) >= sizeof(path
))
163 name
= realpath(path
, NULL
);
170 struct chardata initcp
= {
177 static int concount
; /* Counter for console IDs */
181 __attribute__((__nonnull__
,__hot__
))
183 void consalloc(char * name
)
185 struct console
*restrict tail
;
187 if (posix_memalign((void*)&tail
, sizeof(void*), alignof(typeof(struct console
))) != 0)
188 perror("memory allocation");
190 tail
->next
= (struct console
*)0;
193 tail
->file
= (FILE*)0;
196 tail
->id
= concount
++;
198 memset(&tail
->tio
, 0, sizeof(tail
->tio
));
199 memcpy(&tail
->cp
, &initcp
, sizeof(struct chardata
));
204 consoles
->next
= tail
;
207 void detect_consoles(const char *device
, int fallback
)
211 char *attrib
, *cmdline
;
214 if (!device
|| *device
== '\0')
216 else fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
226 if (fstat(fd
, &st
) < 0) {
230 comparedev
= st
.st_rdev
;
233 * Check if the device detection for Linux system console should be used.
235 if (comparedev
== makedev(TTYAUX_MAJOR
, 0)) { /* /dev/tty */
240 if (comparedev
== makedev(TTYAUX_MAJOR
, 1)) { /* /dev/console */
244 if (comparedev
== makedev(TTYAUX_MAJOR
, 2)) { /* /dev/ptmx */
249 if (comparedev
== makedev(TTY_MAJOR
, 0)) { /* /dev/tty0 */
251 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
255 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
259 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
263 comparedev
= (dev_t
)devnum
;
266 dir
= opendir("/dev");
280 * Detection of devices used for Linux system consolei using
281 * the /proc/consoles API with kernel 2.6.38 and higher.
283 if ((fc
= fopen("/proc/consoles", "re"))) {
287 dir
= opendir("/dev");
292 while ((fscanf(fc
, "%*s %*s (%[^)]) %d:%d", &fbuf
[0], &maj
, &min
) == 3)) {
295 if (!strchr(fbuf
, 'E'))
297 comparedev
= makedev(maj
, min
);
309 * Detection of devices used for Linux system console using
310 * the sysfs /sys/class/tty/ API with kernel 2.6.37 and higher.
312 if ((attrib
= actattr("console"))) {
313 char *words
= attrib
, *token
;
316 dir
= opendir("/dev");
321 while ((token
= strsep(&words
, " \t\r\n"))) {
326 comparedev
= devattr(token
);
327 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
328 char *tmp
= actattr(token
);
331 comparedev
= devattr(tmp
);
348 * Detection of devices used for Linux system console using
349 * kernel parameter on the kernels command line.
351 if ((cmdline
= oneline("/proc/cmdline"))) {
352 char *words
= cmdline
, *token
;
355 dir
= opendir("/dev");
360 while ((token
= strsep(&words
, " \t\r\n"))) {
372 if (strncmp(token
, "console=", 8) != 0)
376 if (strcmp(token
, "brl") == 0)
378 if ((colon
= strchr(token
, ',')))
381 if (asprintf(&name
, "/dev/%s", token
) < 0)
384 if ((fd
= open(name
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
)) < 0) {
390 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
394 comparedev
= (dev_t
)devnum
;
396 if (fstat(fd
, &st
) < 0) {
400 comparedev
= st
.st_rdev
;
401 if (comparedev
== makedev(TTY_MAJOR
, 0)) {
402 if (ioctl(fd
, VT_GETSTATE
, &vt
) < 0) {
406 comparedev
= makedev(TTY_MAJOR
, (int)vt
.v_active
);
419 * Detection of the device used for Linux system console using
420 * the ioctl TIOCGDEV if available (e.g. official 2.6.38).
427 if (!device
|| *device
== '\0')
429 else fd
= open(device
, O_RDWR
|O_NONBLOCK
|O_NOCTTY
|O_CLOEXEC
);
434 if (ioctl (fd
, TIOCGDEV
, &devnum
) < 0) {
438 comparedev
= (dev_t
)devnum
;
441 if (device
&& *device
!= '\0')
443 else name
= ttyname(fallback
);
448 consalloc(strdup(name
));
450 if (!device
|| *device
== '\0')
451 consoles
->fd
= fallback
;
459 #endif /* __linux __ */
464 if (device
&& *device
!= '\0')
466 else name
= ttyname(fallback
);
471 consalloc(strdup(name
));
473 consoles
->fd
= fallback
;