| /* |
| * 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 <string.h> |
| |
| #include "log.h" |
| #include "strfmt.h" |
| #include "hostcmd.h" |
| |
| #if defined(USE_PKG_HOSTCMD_NONE) |
| #include "hostcmd_none.h" |
| #elif defined(USE_PKG_HOSTCMD_UNIX) |
| #include "hostcmd_unix.h" |
| #elif defined(USE_PKG_HOSTCMD_WINDOWS) |
| #include "hostcmd_windows.h" |
| #else /* host command package */ |
| #warning host command package not selected |
| #include "hostcmd_none.h" |
| #endif /* host command package */ |
| |
| #include "hostcmd_internal.h" |
| |
| int |
| finishHostCommandStream (HostCommandStream *hcs, int fileDescriptor) { |
| const char *mode = hcs->isInput? "w": "r"; |
| |
| if ((**hcs->streamVariable = fdopen(fileDescriptor, mode))) { |
| return 1; |
| } else { |
| logSystemError("fdopen"); |
| } |
| |
| return 0; |
| } |
| |
| int |
| processHostCommandStreams ( |
| HostCommandStream *hcs, |
| HostCommandStreamProcessor *processStream, |
| void *data |
| ) { |
| while (hcs->streamVariable) { |
| if (*hcs->streamVariable) { |
| if (!processStream(hcs, data)) { |
| return 0; |
| } |
| } |
| |
| hcs += 1; |
| } |
| |
| return 1; |
| } |
| |
| void |
| initializeHostCommandOptions (HostCommandOptions *options) { |
| memset(options, 0, sizeof(*options)); |
| options->asynchronous = 0; |
| |
| options->standardInput = NULL; |
| options->standardOutput = NULL; |
| options->standardError = NULL; |
| } |
| |
| static int |
| constructHostCommandStream (HostCommandStream *hcs, void *data) { |
| **hcs->streamVariable = NULL; |
| return constructHostCommandPackageData(&hcs->package); |
| } |
| |
| static int |
| destructHostCommandStream (HostCommandStream *hcs, void *data) { |
| destructHostCommandPackageData(&hcs->package); |
| |
| if (**hcs->streamVariable) { |
| fclose(**hcs->streamVariable); |
| **hcs->streamVariable = NULL; |
| } |
| |
| return 1; |
| } |
| |
| int |
| runHostCommand ( |
| const char *const *command, |
| const HostCommandOptions *options |
| ) { |
| int result = 0XFF; |
| HostCommandOptions defaults; |
| |
| if (!options) { |
| initializeHostCommandOptions(&defaults); |
| options = &defaults; |
| } |
| |
| { |
| char buffer[0X100]; |
| STR_BEGIN(buffer, sizeof(buffer)); |
| |
| { |
| const char *const *argument = command; |
| while (*argument) STR_PRINTF(" %s", *argument++); |
| } |
| |
| STR_END; |
| logMessage(LOG_DEBUG, "starting host command:%s", buffer); |
| } |
| |
| { |
| HostCommandStream streams[] = { |
| { .streamVariable = &options->standardInput, |
| .fileDescriptor = 0, |
| .isInput = 1 |
| }, |
| |
| { .streamVariable = &options->standardOutput, |
| .fileDescriptor = 1, |
| .isInput = 0 |
| }, |
| |
| { .streamVariable = &options->standardError, |
| .fileDescriptor = 2, |
| .isInput = 0 |
| }, |
| |
| { .streamVariable = NULL } |
| }; |
| |
| if (processHostCommandStreams(streams, constructHostCommandStream, NULL)) { |
| int ok = 0; |
| |
| if (processHostCommandStreams(streams, prepareHostCommandStream, NULL)) { |
| if (runCommand(&result, command, streams, options->asynchronous)) { |
| ok = 1; |
| } |
| } |
| |
| if (!ok) processHostCommandStreams(streams, destructHostCommandStream, NULL); |
| } |
| } |
| |
| return result; |
| } |
| |
| int |
| executeHostCommand (const char *const *command) { |
| return runHostCommand(command, NULL); |
| } |