1 /* $OpenBSD: cmd-load-buffer.c,v 1.28 2014/04/24 09:14:43 nicm Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 15 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 16 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 21 #include <errno.h> 22 #include <fcntl.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 #include "tmux.h" 29 30 /* 31 * Loads a paste buffer from a file. 32 */ 33 34 enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmd_q *); 35 void cmd_load_buffer_callback(struct client *, int, void *); 36 37 const struct cmd_entry cmd_load_buffer_entry = { 38 "load-buffer", "loadb", 39 "b:", 1, 1, 40 CMD_BUFFER_USAGE " path", 41 0, 42 NULL, 43 cmd_load_buffer_exec 44 }; 45 46 enum cmd_retval 47 cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) 48 { 49 struct args *args = self->args; 50 struct client *c = cmdq->client; 51 struct session *s; 52 FILE *f; 53 const char *path; 54 char *pdata, *new_pdata, *cause; 55 size_t psize; 56 u_int limit; 57 int ch, error, buffer, *buffer_ptr, cwd, fd; 58 59 if (!args_has(args, 'b')) 60 buffer = -1; 61 else { 62 buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause); 63 if (cause != NULL) { 64 cmdq_error(cmdq, "buffer %s", cause); 65 free(cause); 66 return (CMD_RETURN_ERROR); 67 } 68 } 69 70 path = args->argv[0]; 71 if (strcmp(path, "-") == 0) { 72 buffer_ptr = xmalloc(sizeof *buffer_ptr); 73 *buffer_ptr = buffer; 74 75 error = server_set_stdin_callback(c, cmd_load_buffer_callback, 76 buffer_ptr, &cause); 77 if (error != 0) { 78 cmdq_error(cmdq, "%s: %s", path, cause); 79 free(cause); 80 return (CMD_RETURN_ERROR); 81 } 82 return (CMD_RETURN_WAIT); 83 } 84 85 if (c != NULL && c->session == NULL) 86 cwd = c->cwd; 87 else if ((s = cmd_current_session(cmdq, 0)) != NULL) 88 cwd = s->cwd; 89 else 90 cwd = AT_FDCWD; 91 92 if ((fd = openat(cwd, path, O_RDONLY)) == -1 || 93 (f = fdopen(fd, "rb")) == NULL) { 94 if (fd != -1) 95 close(fd); 96 cmdq_error(cmdq, "%s: %s", path, strerror(errno)); 97 return (CMD_RETURN_ERROR); 98 } 99 100 pdata = NULL; 101 psize = 0; 102 while ((ch = getc(f)) != EOF) { 103 /* Do not let the server die due to memory exhaustion. */ 104 if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { 105 cmdq_error(cmdq, "realloc error: %s", strerror(errno)); 106 goto error; 107 } 108 pdata = new_pdata; 109 pdata[psize++] = ch; 110 } 111 if (ferror(f)) { 112 cmdq_error(cmdq, "%s: read error", path); 113 goto error; 114 } 115 if (pdata != NULL) 116 pdata[psize] = '\0'; 117 118 fclose(f); 119 120 limit = options_get_number(&global_options, "buffer-limit"); 121 if (buffer == -1) { 122 paste_add(pdata, psize, limit); 123 return (CMD_RETURN_NORMAL); 124 } 125 if (paste_replace(buffer, pdata, psize) != 0) { 126 cmdq_error(cmdq, "no buffer %d", buffer); 127 free(pdata); 128 return (CMD_RETURN_ERROR); 129 } 130 131 return (CMD_RETURN_NORMAL); 132 133 error: 134 free(pdata); 135 if (f != NULL) 136 fclose(f); 137 return (CMD_RETURN_ERROR); 138 } 139 140 void 141 cmd_load_buffer_callback(struct client *c, int closed, void *data) 142 { 143 int *buffer = data; 144 char *pdata; 145 size_t psize; 146 u_int limit; 147 148 if (!closed) 149 return; 150 c->stdin_callback = NULL; 151 152 c->references--; 153 if (c->flags & CLIENT_DEAD) 154 return; 155 156 psize = EVBUFFER_LENGTH(c->stdin_data); 157 if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) { 158 free(data); 159 goto out; 160 } 161 memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); 162 pdata[psize] = '\0'; 163 evbuffer_drain(c->stdin_data, psize); 164 165 limit = options_get_number(&global_options, "buffer-limit"); 166 if (*buffer == -1) 167 paste_add(pdata, psize, limit); 168 else if (paste_replace(*buffer, pdata, psize) != 0) { 169 /* No context so can't use server_client_msg_error. */ 170 evbuffer_add_printf(c->stderr_data, "no buffer %d\n", *buffer); 171 server_push_stderr(c); 172 free(pdata); 173 } 174 175 free(data); 176 177 out: 178 cmdq_continue(c->cmdq); 179 } 180