GUACAMOLE-313: Add guaclog utility with stubbed interpretation of key events.

This commit is contained in:
Michael Jumper 2017-11-26 15:44:03 -08:00
parent db85163e20
commit ebc731aaf3
16 changed files with 1047 additions and 0 deletions

View File

@ -27,6 +27,7 @@ DIST_SUBDIRS = \
src/terminal \
src/guacd \
src/guacenc \
src/guaclog \
src/pulse \
src/protocols/rdp \
src/protocols/ssh \
@ -75,6 +76,10 @@ if ENABLE_GUACENC
SUBDIRS += src/guacenc
endif
if ENABLE_GUACLOG
SUBDIRS += src/guaclog
endif
EXTRA_DIST = \
.dockerignore \
CONTRIBUTING \

View File

@ -1191,6 +1191,18 @@ AM_CONDITIONAL([ENABLE_GUACENC], [test "x${enable_guacenc}" = "xyes" \
-a "x${have_libavutil}" = "xyes" \
-a "x${have_libswscale}" = "xyes"])
#
# guaclog
#
AC_ARG_ENABLE([guaclog],
[AS_HELP_STRING([--disable-guaclog],
[do not build the Guacamole input logging tool])],
[],
[enable_guaclog=yes])
AM_CONDITIONAL([ENABLE_GUACLOG], [test "x${enable_guaclog}" = "xyes"])
#
# Output Makefiles
#
@ -1207,6 +1219,8 @@ AC_CONFIG_FILES([Makefile
src/guacd/man/guacd.conf.5
src/guacenc/Makefile
src/guacenc/man/guacenc.1
src/guaclog/Makefile
src/guaclog/man/guaclog.1
src/pulse/Makefile
src/protocols/rdp/Makefile
src/protocols/ssh/Makefile
@ -1229,6 +1243,7 @@ AM_COND_IF([ENABLE_VNC], [build_vnc=yes], [build_vnc=no])
AM_COND_IF([ENABLE_GUACD], [build_guacd=yes], [build_guacd=no])
AM_COND_IF([ENABLE_GUACENC], [build_guacenc=yes], [build_guacenc=no])
AM_COND_IF([ENABLE_GUACLOG], [build_guaclog=yes], [build_guaclog=no])
#
# Init scripts
@ -1272,6 +1287,7 @@ $PACKAGE_NAME version $PACKAGE_VERSION
guacd ...... ${build_guacd}
guacenc .... ${build_guacenc}
guaclog .... ${build_guaclog}
Init scripts: ${build_init}

5
src/guaclog/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Compiled guaclog
guaclog
guaclog.exe

51
src/guaclog/Makefile.am Normal file
View File

@ -0,0 +1,51 @@
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
AUTOMAKE_OPTIONS = foreign
bin_PROGRAMS = guaclog
man_MANS = \
man/guaclog.1
noinst_HEADERS = \
guaclog.h \
instructions.h \
interpret.h \
log.h \
state.h
guaclog_SOURCES = \
guaclog.c \
instructions.c \
instruction-key.c \
interpret.c \
log.c \
state.c
guaclog_CFLAGS = \
-Werror -Wall \
@LIBGUAC_INCLUDE@
guaclog_LDADD = \
@LIBGUAC_LTLIB@
EXTRA_DIST = \
man/guaclog.1.in

119
src/guaclog/guaclog.c Normal file
View File

@ -0,0 +1,119 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "guaclog.h"
#include "interpret.h"
#include "log.h"
#include <getopt.h>
#include <stdbool.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
int i;
/* Load defaults */
bool force = false;
/* Parse arguments */
int opt;
while ((opt = getopt(argc, argv, "s:r:f")) != -1) {
/* -f: Force */
if (opt == 'f')
force = true;
/* Invalid option */
else {
goto invalid_options;
}
}
/* Log start */
guaclog_log(GUAC_LOG_INFO, "Guacamole input log interpreter (guaclog) "
"version " VERSION);
/* Track number of overall failures */
int total_files = argc - optind;
int failures = 0;
/* Abort if no files given */
if (total_files <= 0) {
guaclog_log(GUAC_LOG_INFO, "No input files specified. Nothing to do.");
return 0;
}
guaclog_log(GUAC_LOG_INFO, "%i input file(s) provided.", total_files);
/* Interpret all input files */
for (i = optind; i < argc; i++) {
/* Get current filename */
const char* path = argv[i];
/* Generate output filename */
char out_path[4096];
int len = snprintf(out_path, sizeof(out_path), "%s.txt", path);
/* Do not write if filename exceeds maximum length */
if (len >= sizeof(out_path)) {
guaclog_log(GUAC_LOG_ERROR, "Cannot write output file for \"%s\": "
"Name too long", path);
continue;
}
/* Attempt interpreting, log granular success/failure at debug level */
if (guaclog_interpret(path, out_path, force)) {
failures++;
guaclog_log(GUAC_LOG_DEBUG,
"%s was NOT successfully interpreted.", path);
}
else
guaclog_log(GUAC_LOG_DEBUG, "%s was successfully "
"interpreted.", path);
}
/* Warn if at least one file failed */
if (failures != 0)
guaclog_log(GUAC_LOG_WARNING, "Interpreting failed for %i of %i "
"file(s).", failures, total_files);
/* Notify of success */
else
guaclog_log(GUAC_LOG_INFO, "All files interpreted successfully.");
/* Interpreting complete */
return 0;
/* Display usage and exit with error if options are invalid */
invalid_options:
fprintf(stderr, "USAGE: %s"
" [-f]"
" [FILE]...\n", argv[0]);
return 1;
}

31
src/guaclog/guaclog.h Normal file
View File

@ -0,0 +1,31 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUACLOG_H
#define GUACLOG_H
#include "config.h"
/**
* The default log level below which no messages should be logged.
*/
#define GUACLOG_DEFAULT_LOG_LEVEL GUAC_LOG_INFO
#endif

View File

@ -0,0 +1,43 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "log.h"
#include "state.h"
#include <stdbool.h>
#include <stdlib.h>
int guaclog_handle_key(guaclog_state* state, int argc, char** argv) {
/* Verify argument count */
if (argc < 2) {
guaclog_log(GUAC_LOG_WARNING, "\"key\" instruction incomplete");
return 1;
}
/* Parse arguments */
int keysym = atoi(argv[0]);
bool pressed = (atoi(argv[1]) != 0);
/* Update interpreter state accordingly */
return guaclog_state_update_key(state, keysym, pressed);
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "state.h"
#include "instructions.h"
#include "log.h"
#include <string.h>
guaclog_instruction_handler_mapping guaclog_instruction_handler_map[] = {
{"key", guaclog_handle_key},
{NULL, NULL}
};
int guaclog_handle_instruction(guaclog_state* state, const char* opcode,
int argc, char** argv) {
/* Search through mapping for instruction handler having given opcode */
guaclog_instruction_handler_mapping* current = guaclog_instruction_handler_map;
while (current->opcode != NULL) {
/* Invoke handler if opcode matches (if defined) */
if (strcmp(current->opcode, opcode) == 0) {
/* Invoke defined handler */
guaclog_instruction_handler* handler = current->handler;
if (handler != NULL)
return handler(state, argc, argv);
/* Log defined but unimplemented instructions */
guaclog_log(GUAC_LOG_DEBUG, "\"%s\" not implemented", opcode);
return 0;
}
/* Next candidate handler */
current++;
} /* end opcode search */
/* Ignore any unknown instructions */
return 0;
}

108
src/guaclog/instructions.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUACLOG_INSTRUCTIONS_H
#define GUACLOG_INSTRUCTIONS_H
#include "config.h"
#include "state.h"
/**
* A callback function which, when invoked, handles a particular Guacamole
* instruction. The opcode of the instruction is implied (as it is expected
* that there will be a 1:1 mapping of opcode to callback function), while the
* arguments for that instruction are included in the parameters given to the
* callback.
*
* @param state
* The current state of the Guacamole input log interpreter.
*
* @param argc
* The number of arguments (excluding opcode) passed to the instruction
* being handled by the callback.
*
* @param argv
* All arguments (excluding opcode) associated with the instruction being
* handled by the callback.
*
* @return
* Zero if the instruction was handled successfully, non-zero if an error
* occurs.
*/
typedef int guaclog_instruction_handler(guaclog_state* state,
int argc, char** argv);
/**
* Mapping of instruction opcode to corresponding handler function.
*/
typedef struct guaclog_instruction_handler_mapping {
/**
* The opcode of the instruction that the associated handler function
* should be invoked for.
*/
const char* opcode;
/**
* The handler function to invoke whenever an instruction having the
* associated opcode is parsed.
*/
guaclog_instruction_handler* handler;
} guaclog_instruction_handler_mapping;
/**
* Array of all opcode/handler mappings for all supported opcodes, terminated
* by an entry with a NULL opcode. All opcodes not listed here can be safely
* ignored.
*/
extern guaclog_instruction_handler_mapping guaclog_instruction_handler_map[];
/**
* Handles the instruction having the given opcode and arguments, updating
* the state of the interpreter accordingly.
*
* @param state
* The current state of the Guacamole input log interpreter.
*
* @param opcode
* The opcode of the instruction being handled.
*
* @param argc
* The number of arguments (excluding opcode) passed to the instruction
* being handled by the callback.
*
* @param argv
* All arguments (excluding opcode) associated with the instruction being
* handled by the callback.
*
* @return
* Zero if the instruction was handled successfully, non-zero if an error
* occurs.
*/
int guaclog_handle_instruction(guaclog_state* state,
const char* opcode, int argc, char** argv);
/**
* Handler for the Guacamole "key" instruction.
*/
guaclog_instruction_handler guaclog_handle_key;
#endif

152
src/guaclog/interpret.c Normal file
View File

@ -0,0 +1,152 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "instructions.h"
#include "log.h"
#include "state.h"
#include <guacamole/client.h>
#include <guacamole/error.h>
#include <guacamole/parser.h>
#include <guacamole/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
/**
* Reads and handles all Guacamole instructions from the given guac_socket
* until end-of-stream is reached.
*
* @param state
* The current state of the Guacamole input log interpreter.
*
* @param path
* The name of the file being parsed (for logging purposes). This file
* must already be open and available through the given socket.
*
* @param socket
* The guac_socket through which instructions should be read.
*
* @return
* Zero on success, non-zero if parsing of Guacamole protocol data through
* the given socket fails.
*/
static int guaclog_read_instructions(guaclog_state* state,
const char* path, guac_socket* socket) {
/* Obtain Guacamole protocol parser */
guac_parser* parser = guac_parser_alloc();
if (parser == NULL)
return 1;
/* Continuously read and handle all instructions */
while (!guac_parser_read(parser, socket, -1)) {
guaclog_handle_instruction(state, parser->opcode,
parser->argc, parser->argv);
}
/* Fail on read/parse error */
if (guac_error != GUAC_STATUS_CLOSED) {
guaclog_log(GUAC_LOG_ERROR, "%s: %s",
path, guac_status_string(guac_error));
guac_parser_free(parser);
return 1;
}
/* Parse complete */
guac_parser_free(parser);
return 0;
}
int guaclog_interpret(const char* path, const char* out_path, bool force) {
/* Open input file */
int fd = open(path, O_RDONLY);
if (fd < 0) {
guaclog_log(GUAC_LOG_ERROR, "%s: %s", path, strerror(errno));
return 1;
}
/* Lock entire input file for reading by the current process */
struct flock file_lock = {
.l_type = F_RDLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 0,
.l_pid = getpid()
};
/* Abort if file cannot be locked for reading */
if (!force && fcntl(fd, F_SETLK, &file_lock) == -1) {
/* Warn if lock cannot be acquired */
if (errno == EACCES || errno == EAGAIN)
guaclog_log(GUAC_LOG_WARNING, "Refusing to interpret log of "
"in-progress session \"%s\" (specify the -f option to "
"override this behavior).", path);
/* Log an error if locking fails in an unexpected way */
else
guaclog_log(GUAC_LOG_ERROR, "Cannot lock \"%s\" for reading: %s",
path, strerror(errno));
close(fd);
return 1;
}
/* Allocate input state for interpreting process */
guaclog_state* state = guaclog_state_alloc(out_path);
if (state == NULL) {
close(fd);
return 1;
}
/* Obtain guac_socket wrapping file descriptor */
guac_socket* socket = guac_socket_open(fd);
if (socket == NULL) {
guaclog_log(GUAC_LOG_ERROR, "%s: %s", path,
guac_status_string(guac_error));
close(fd);
guaclog_state_free(state);
return 1;
}
guaclog_log(GUAC_LOG_INFO, "Writing input events from \"%s\" "
"to \"%s\" ...", path, out_path);
/* Attempt to read all instructions in the file */
if (guaclog_read_instructions(state, path, socket)) {
guac_socket_free(socket);
guaclog_state_free(state);
return 1;
}
/* Close input and finish interpreting process */
guac_socket_free(socket);
return guaclog_state_free(state);
}

51
src/guaclog/interpret.h Normal file
View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUACLOG_INTERPRET_H
#define GUACLOG_INTERPRET_H
#include "config.h"
#include <stdbool.h>
/**
* Interprets all input events within the given Guacamole protocol dump,
* producing a human-readable log of those input events. A read lock will be
* acquired on the input file to ensure that in-progress logs are not
* interpreted. This behavior can be overridden by specifying true for the
* force parameter.
*
* @param path
* The path to the file containing the raw Guacamole protocol dump.
*
* @param out_path
* The full path to the file in which interpreted log should be written.
*
* @param force
* Interpret even if the input file appears to be an in-progress log (has
* an associated lock).
*
* @return
* Zero on success, non-zero if an error prevented successful
* interpretation of the log.
*/
int guaclog_interpret(const char* path, const char* out_path, bool force);
#endif

85
src/guaclog/log.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "guaclog.h"
#include "log.h"
#include <guacamole/client.h>
#include <guacamole/error.h>
#include <stdarg.h>
#include <stdio.h>
int guaclog_log_level = GUACLOG_DEFAULT_LOG_LEVEL;
void vguaclog_log(guac_client_log_level level, const char* format,
va_list args) {
const char* priority_name;
char message[2048];
/* Don't bother if the log level is too high */
if (level > guaclog_log_level)
return;
/* Copy log message into buffer */
vsnprintf(message, sizeof(message), format, args);
/* Convert log level to human-readable name */
switch (level) {
/* Error log level */
case GUAC_LOG_ERROR:
priority_name = "ERROR";
break;
/* Warning log level */
case GUAC_LOG_WARNING:
priority_name = "WARNING";
break;
/* Informational log level */
case GUAC_LOG_INFO:
priority_name = "INFO";
break;
/* Debug log level */
case GUAC_LOG_DEBUG:
priority_name = "DEBUG";
break;
/* Any unknown/undefined log level */
default:
priority_name = "UNKNOWN";
break;
}
/* Log to STDERR */
fprintf(stderr, GUACLOG_LOG_NAME ": %s: %s\n", priority_name, message);
}
void guaclog_log(guac_client_log_level level, const char* format, ...) {
va_list args;
va_start(args, format);
vguaclog_log(level, format, args);
va_end(args);
}

73
src/guaclog/log.h Normal file
View File

@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUACLOG_LOG_H
#define GUACLOG_LOG_H
#include "config.h"
#include <guacamole/client.h>
#include <stdarg.h>
/**
* The maximum level at which to log messages. All other messages will be
* dropped.
*/
extern int guaclog_log_level;
/**
* The string to prepend to all log messages.
*/
#define GUACLOG_LOG_NAME "guaclog"
/**
* Writes a message to guaclog's logs. This function takes a format and
* va_list, similar to vprintf.
*
* @param level
* The level at which to log this message.
*
* @param format
* A printf-style format string to log.
*
* @param args
* The va_list containing the arguments to be used when filling the format
* string for printing.
*/
void vguaclog_log(guac_client_log_level level, const char* format,
va_list args);
/**
* Writes a message to guaclog's logs. This function accepts parameters
* identically to printf.
*
* @param level
* The level at which to log this message.
*
* @param format
* A printf-style format string to log.
*
* @param ...
* Arguments to use when filling the format string for printing.
*/
void guaclog_log(guac_client_log_level level, const char* format, ...);
#endif

View File

@ -0,0 +1,60 @@
.\"
.\" Licensed to the Apache Software Foundation (ASF) under one
.\" or more contributor license agreements. See the NOTICE file
.\" distributed with this work for additional information
.\" regarding copyright ownership. The ASF licenses this file
.\" to you under the Apache License, Version 2.0 (the
.\" "License"); you may not use this file except in compliance
.\" with the License. You may obtain a copy of the License at
.\"
.\" http://www.apache.org/licenses/LICENSE-2.0
.\"
.\" Unless required by applicable law or agreed to in writing,
.\" software distributed under the License is distributed on an
.\" "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
.\" KIND, either express or implied. See the License for the
.\" specific language governing permissions and limitations
.\" under the License.
.\"
.TH guaclog 1 "26 Jan 2018" "version @PACKAGE_VERSION@" "Apache Guacamole"
.
.SH NAME
guaclog \- Guacamole input log interpreter
.
.SH SYNOPSIS
.B guaclog
[\fB-f\fR]
[\fIFILE\fR]...
.
.SH DESCRIPTION
.B guaclog
is an interpreter which accepts Guacamole protocol dumps, such as those saved
when input logging is enabled on a Guacamole connection, writing human-readable
text logs as output.
.B guaclog
is essentially an implementation of a Guacamole client which accepts
its input from files instead of a network connection, however unlike
.B guacenc
it only handles instructions related to user input.
.P
Each \fIFILE\fR specified will be translated into a new human-readable text
file named \fIFILE\fR.txt. Existing files will not be overwritten; the
interpreting process for any input file will be aborted if it would result in
overwriting an existing file.
.P
Guacamole acquires a write lock on input logs as they are being written. By
default,
.B guaclog
will check whether the each input file is locked and will refuse to read and
interpret an input file if it appears to be an in-progress log. This behavior
can be overridden by specifying the \fB-f\fR option. Interpreting an
in-progress log will still work; the resulting human-readable text file will
simply cover the user's session only up to the current point in time.
.
.SH OPTIONS
.TP
\fB-f\fR
Overrides the default behavior of
.B guaclog
such that input files will be interpreted even if they appear to be logs of
in-progress Guacamole sessions.

97
src/guaclog/state.c Normal file
View File

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "config.h"
#include "log.h"
#include "state.h"
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
guaclog_state* guaclog_state_alloc(const char* path) {
/* Open output file */
int fd = open(path, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
if (fd == -1) {
guaclog_log(GUAC_LOG_ERROR, "Failed to open output file \"%s\": %s",
path, strerror(errno));
goto fail_output_fd;
}
/* Create stream for output file */
FILE* output = fdopen(fd, "wb");
if (output == NULL) {
guaclog_log(GUAC_LOG_ERROR, "Failed to allocate stream for output "
"file \"%s\": %s", path, strerror(errno));
goto fail_output_file;
}
/* Allocate state */
guaclog_state* state = (guaclog_state*) calloc(1, sizeof(guaclog_state));
if (state == NULL) {
goto fail_state;
}
/* Associate state with output file */
state->output = output;
return state;
/* Free all allocated data in case of failure */
fail_state:
fclose(output);
fail_output_file:
close(fd);
fail_output_fd:
return NULL;
}
int guaclog_state_free(guaclog_state* state) {
/* Ignore NULL state */
if (state == NULL)
return 0;
/* Close output file */
fclose(state->output);
free(state);
return 0;
}
int guaclog_state_update_key(guaclog_state* state, int keysym, bool pressed) {
/* STUB */
fprintf(state->output, "STUB: keysym=0x%X, pressed=%s\n",
keysym, pressed ? "true" : "false");
return 0;
}

89
src/guaclog/state.h Normal file
View File

@ -0,0 +1,89 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#ifndef GUACLOG_STATE_H
#define GUACLOG_STATE_H
#include "config.h"
#include <stdbool.h>
#include <stdio.h>
/**
* The current state of the Guacamole input log interpreter.
*/
typedef struct guaclog_state {
/**
* Output file stream.
*/
FILE* output;
} guaclog_state;
/**
* Allocates a new state structure for the Guacamole input log interpreter.
* This structure serves as the representation of interpreter state as
* input-related instructions are read and handled.
*
* @param path
* The full path to the file in which interpreted, human-readable should be
* written.
*
* @return
* The newly-allocated Guacamole input log interpreter state, or NULL if
* the state could not be allocated.
*/
guaclog_state* guaclog_state_alloc(const char* path);
/**
* Frees all memory associated with the given Guacamole input log interpreter
* state, and finishes any remaining interpreting process. If the given state
* is NULL, this function has no effect.
*
* @param state
* The Guacamole input log interpreter state to free, which may be NULL.
*
* @return
* Zero if the interpreting process completed successfully, non-zero
* otherwise.
*/
int guaclog_state_free(guaclog_state* state);
/**
* Updates the given Guacamole input log interpreter state, marking the given
* key as pressed or released.
*
* @param state
* The Guacamole input log interpreter state being updated.
*
* @param keysym
* The X11 keysym of the key being pressed or released.
*
* @param pressed
* true if the key is being pressed, false if the key is being released.
*
* @return
* Zero if the interpreter state was updated successfully, non-zero
* otherwise.
*/
int guaclog_state_update_key(guaclog_state* state, int keysym, bool pressed);
#endif