blob: 68083edae558aa5cb6281edf8d18cb1282bfe55b [file] [log] [blame] [edit]
/*
* 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 */