interpret.c (4589B)
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 */ 19 20#include "config.h" 21#include "instructions.h" 22#include "log.h" 23#include "state.h" 24 25#include <guacamole/client.h> 26#include <guacamole/error.h> 27#include <guacamole/parser.h> 28#include <guacamole/socket.h> 29 30#include <sys/stat.h> 31#include <sys/types.h> 32#include <errno.h> 33#include <fcntl.h> 34#include <stdbool.h> 35#include <string.h> 36#include <unistd.h> 37 38/** 39 * Reads and handles all Guacamole instructions from the given guac_socket 40 * until end-of-stream is reached. 41 * 42 * @param state 43 * The current state of the Guacamole input log interpreter. 44 * 45 * @param path 46 * The name of the file being parsed (for logging purposes). This file 47 * must already be open and available through the given socket. 48 * 49 * @param socket 50 * The guac_socket through which instructions should be read. 51 * 52 * @return 53 * Zero on success, non-zero if parsing of Guacamole protocol data through 54 * the given socket fails. 55 */ 56static int guaclog_read_instructions(guaclog_state* state, 57 const char* path, guac_socket* socket) { 58 59 /* Obtain Guacamole protocol parser */ 60 guac_parser* parser = guac_parser_alloc(); 61 if (parser == NULL) 62 return 1; 63 64 /* Continuously read and handle all instructions */ 65 while (!guac_parser_read(parser, socket, -1)) { 66 guaclog_handle_instruction(state, parser->opcode, 67 parser->argc, parser->argv); 68 } 69 70 /* Fail on read/parse error */ 71 if (guac_error != GUAC_STATUS_CLOSED) { 72 guaclog_log(GUAC_LOG_ERROR, "%s: %s", 73 path, guac_status_string(guac_error)); 74 guac_parser_free(parser); 75 return 1; 76 } 77 78 /* Parse complete */ 79 guac_parser_free(parser); 80 return 0; 81 82} 83 84int guaclog_interpret(const char* path, const char* out_path, bool force) { 85 86 /* Open input file */ 87 int fd = open(path, O_RDONLY); 88 if (fd < 0) { 89 guaclog_log(GUAC_LOG_ERROR, "%s: %s", path, strerror(errno)); 90 return 1; 91 } 92 93 /* Lock entire input file for reading by the current process */ 94 struct flock file_lock = { 95 .l_type = F_RDLCK, 96 .l_whence = SEEK_SET, 97 .l_start = 0, 98 .l_len = 0, 99 .l_pid = getpid() 100 }; 101 102 /* Abort if file cannot be locked for reading */ 103 if (!force && fcntl(fd, F_SETLK, &file_lock) == -1) { 104 105 /* Warn if lock cannot be acquired */ 106 if (errno == EACCES || errno == EAGAIN) 107 guaclog_log(GUAC_LOG_WARNING, "Refusing to interpret log of " 108 "in-progress session \"%s\" (specify the -f option to " 109 "override this behavior).", path); 110 111 /* Log an error if locking fails in an unexpected way */ 112 else 113 guaclog_log(GUAC_LOG_ERROR, "Cannot lock \"%s\" for reading: %s", 114 path, strerror(errno)); 115 116 close(fd); 117 return 1; 118 } 119 120 /* Allocate input state for interpreting process */ 121 guaclog_state* state = guaclog_state_alloc(out_path); 122 if (state == NULL) { 123 close(fd); 124 return 1; 125 } 126 127 /* Obtain guac_socket wrapping file descriptor */ 128 guac_socket* socket = guac_socket_open(fd); 129 if (socket == NULL) { 130 guaclog_log(GUAC_LOG_ERROR, "%s: %s", path, 131 guac_status_string(guac_error)); 132 close(fd); 133 guaclog_state_free(state); 134 return 1; 135 } 136 137 guaclog_log(GUAC_LOG_INFO, "Writing input events from \"%s\" " 138 "to \"%s\" ...", path, out_path); 139 140 /* Attempt to read all instructions in the file */ 141 if (guaclog_read_instructions(state, path, socket)) { 142 guac_socket_free(socket); 143 guaclog_state_free(state); 144 return 1; 145 } 146 147 /* Close input and finish interpreting process */ 148 guac_socket_free(socket); 149 return guaclog_state_free(state); 150 151} 152