GUACAMOLE-313: Add guaclog utility with stubbed interpretation of key events.
This commit is contained in:
parent
db85163e20
commit
ebc731aaf3
@ -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 \
|
||||
|
16
configure.ac
16
configure.ac
@ -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
5
src/guaclog/.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
# Compiled guaclog
|
||||
guaclog
|
||||
guaclog.exe
|
||||
|
51
src/guaclog/Makefile.am
Normal file
51
src/guaclog/Makefile.am
Normal 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
119
src/guaclog/guaclog.c
Normal 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
31
src/guaclog/guaclog.h
Normal 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
|
||||
|
43
src/guaclog/instruction-key.c
Normal file
43
src/guaclog/instruction-key.c
Normal 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);
|
||||
|
||||
}
|
||||
|
62
src/guaclog/instructions.c
Normal file
62
src/guaclog/instructions.c
Normal 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
108
src/guaclog/instructions.h
Normal 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
152
src/guaclog/interpret.c
Normal 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
51
src/guaclog/interpret.h
Normal 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
85
src/guaclog/log.c
Normal 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
73
src/guaclog/log.h
Normal 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
|
||||
|
60
src/guaclog/man/guaclog.1.in
Normal file
60
src/guaclog/man/guaclog.1.in
Normal 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
97
src/guaclog/state.c
Normal 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
89
src/guaclog/state.h
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user