| /* |
| * BRLTTY - A background process providing access to the console screen (when in |
| * text mode) for a blind person using a refreshable braille display. |
| * |
| * Copyright (C) 1995-2023 by The BRLTTY Developers. |
| * |
| * BRLTTY comes with ABSOLUTELY NO WARRANTY. |
| * |
| * This is free software, placed under the terms of the |
| * GNU Lesser General Public License, as published by the Free Software |
| * Foundation; either version 2.1 of the License, or (at your option) any |
| * later version. Please see the file LICENSE-LGPL for details. |
| * |
| * Web Page: http://brltty.app/ |
| * |
| * This software is maintained by Dave Mielke <dave@mielke.cc>. |
| */ |
| |
| #include "prologue.h" |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <strings.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| |
| #include "log.h" |
| #include "strfmt.h" |
| #include "device.h" |
| #include "file.h" |
| #include "parse.h" |
| |
| FILE * |
| getConsole (void) { |
| #if defined(GRUB_RUNTIME) |
| return stdout; |
| #else /* get console */ |
| static FILE *console = NULL; |
| |
| if (!console) { |
| if ((console = fopen("/dev/console", "wb"))) { |
| logMessage(LOG_DEBUG, "console opened: fd=%d", fileno(console)); |
| registerProgramStream("console-stream", &console); |
| } else { |
| logSystemError("console open"); |
| } |
| } |
| |
| return console; |
| #endif /* get console */ |
| } |
| |
| int |
| writeToConsole (const unsigned char *bytes, size_t count) { |
| FILE *console = getConsole(); |
| if (!console) return 0; |
| |
| while (count) { |
| size_t result = fwrite(bytes, 1, count, console); |
| if (!ferror(console)) fflush(console); |
| |
| if (ferror(console)) { |
| logSystemError("console write"); |
| return 0; |
| } |
| |
| bytes += result; |
| count -= result; |
| } |
| |
| return 1; |
| } |
| |
| int |
| ringConsoleBell (void) { |
| static unsigned char bellSequence[] = {0X07}; |
| return writeToConsole(bellSequence, sizeof(bellSequence)); |
| } |
| |
| const char * |
| getDeviceDirectory (void) { |
| static const char *deviceDirectory = NULL; |
| |
| if (!deviceDirectory) { |
| const char *directory = DEVICE_DIRECTORY; |
| const size_t directoryLength = strlen(directory); |
| |
| static const char *const variables[] = {"DTDEVROOT", "UTDEVROOT", NULL}; |
| const char *const *variable = variables; |
| |
| while (*variable) { |
| const char *root = getenv(*variable); |
| |
| if (root && *root) { |
| const size_t rootLength = strlen(root); |
| char path[rootLength + directoryLength + 1]; |
| snprintf(path, sizeof(path), "%s%s", root, directory); |
| |
| if (testDirectoryPath(path)) { |
| if ((deviceDirectory = strdup(path))) goto found; |
| logMallocError(); |
| } else if (errno != ENOENT) { |
| logMessage(LOG_ERR, "device directory error: %s (%s): %s", |
| path, *variable, strerror(errno)); |
| } |
| } |
| |
| variable += 1; |
| } |
| |
| deviceDirectory = directory; |
| found: |
| logMessage(LOG_DEBUG, "device directory: %s", deviceDirectory); |
| } |
| |
| return deviceDirectory; |
| } |
| |
| char * |
| getDevicePath (const char *device) { |
| const char *directory = getDeviceDirectory(); |
| |
| #ifdef ALLOW_DOS_DEVICE_NAMES |
| if (isDosDevice(device, NULL)) { |
| //directory = NULL; |
| } |
| #endif /* ALLOW_DOS_DEVICE_NAMES */ |
| |
| return makePath(directory, device); |
| } |
| |
| const char * |
| resolveDeviceName (const char *const *names, int strict, const char *description) { |
| const char *first = *names; |
| const char *device = NULL; |
| const char *name; |
| |
| while ((name = *names++)) { |
| char *path = getDevicePath(name); |
| if (!path) break; |
| logMessage(LOG_DEBUG, "checking %s device: %s", description, path); |
| |
| if (testPath(path)) { |
| device = name; |
| free(path); |
| break; |
| } |
| |
| logMessage(LOG_DEBUG, "%s device access error: %s: %s", |
| description, path, strerror(errno)); |
| |
| if (errno != ENOENT) { |
| if (!device) { |
| device = name; |
| } |
| } |
| |
| free(path); |
| } |
| |
| if (!device) { |
| if (!first) { |
| logMessage(LOG_ERR, "%s device names not defined", description); |
| } else if (strict) { |
| logMessage(LOG_ERR, "%s device not found", description); |
| } else { |
| device = first; |
| } |
| } |
| |
| if (device) logMessage(LOG_INFO, "%s device: %s", description, device); |
| return device; |
| } |
| |
| char ** |
| getDeviceParameters (const char *const *names, const char *identifier) { |
| char parameters[strlen(names[0]) + 1 + strlen(identifier) + 1]; |
| STR_BEGIN(parameters, sizeof(parameters)) |
| |
| { |
| static const char characters[] = { |
| DEVICE_PARAMETER_SEPARATOR, |
| PARAMETER_ASSIGNMENT_CHARACTER, |
| 0 |
| }; |
| const char *character = strpbrk(identifier, characters); |
| |
| if (!(character && (*character == PARAMETER_ASSIGNMENT_CHARACTER))) { |
| STR_PRINTF("%s%c", names[0], PARAMETER_ASSIGNMENT_CHARACTER); |
| } |
| } |
| |
| { |
| char *character = STR_NEXT; |
| STR_PRINTF("%s", identifier); |
| |
| while (character < STR_NEXT) { |
| if (*character == DEVICE_PARAMETER_SEPARATOR) *character = PARAMETER_SEPARATOR_CHARACTER; |
| character += 1; |
| } |
| } |
| |
| STR_END; |
| return getParameters(names, NULL, parameters); |
| } |
| |
| #ifdef ALLOW_DOS_DEVICE_NAMES |
| int |
| isDosDevice (const char *identifier, const char *prefix) { |
| size_t count = strcspn(identifier, ":"); |
| size_t length; |
| |
| if (!count) return 0; |
| |
| if (prefix) { |
| if (!(length = strlen(prefix))) return 0; |
| if (length > count) return 0; |
| if (strncasecmp(identifier, prefix, length) != 0) return 0; |
| } else { |
| length = strspn(identifier, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); |
| if (!length) return 0; |
| } |
| |
| identifier += length; |
| count -= length; |
| |
| if (strspn(identifier, "0123456789") != count) return 0; |
| return 1; |
| } |
| #endif /* ALLOW_DOS_DEVICE_NAMES */ |