1 /* $OpenBSD: cmd-load-buffer.c,v 1.51 2018/01/15 15:27:03 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 static enum cmd_retval cmd_load_buffer_exec(struct cmd *, struct cmdq_item *); 35 36 static void cmd_load_buffer_callback(struct client *, int, void *); 37 38 const struct cmd_entry cmd_load_buffer_entry = { 39 .name = "load-buffer", 40 .alias = "loadb", 41 42 .args = { "b:", 1, 1 }, 43 .usage = CMD_BUFFER_USAGE " path", 44 45 .flags = CMD_AFTERHOOK, 46 .exec = cmd_load_buffer_exec 47 }; 48 49 struct cmd_load_buffer_data { 50 struct cmdq_item *item; 51 char *bufname; 52 }; 53 54 static enum cmd_retval 55 cmd_load_buffer_exec(struct cmd *self, struct cmdq_item *item) 56 { 57 struct args *args = self->args; 58 struct cmd_load_buffer_data *cdata; 59 struct client *c = item->client; 60 FILE *f; 61 const char *path, *bufname; 62 char *pdata = NULL, *new_pdata, *cause; 63 char *file; 64 size_t psize; 65 int ch, error; 66 67 bufname = NULL; 68 if (args_has(args, 'b')) 69 bufname = args_get(args, 'b'); 70 71 path = args->argv[0]; 72 if (strcmp(path, "-") == 0) { 73 cdata = xcalloc(1, sizeof *cdata); 74 cdata->item = item; 75 76 if (bufname != NULL) 77 cdata->bufname = xstrdup(bufname); 78 79 error = server_set_stdin_callback(c, cmd_load_buffer_callback, 80 cdata, &cause); 81 if (error != 0) { 82 cmdq_error(item, "%s: %s", path, cause); 83 free(cause); 84 return (CMD_RETURN_ERROR); 85 } 86 return (CMD_RETURN_WAIT); 87 } 88 89 file = server_client_get_path(c, path); 90 f = fopen(file, "rb"); 91 if (f == NULL) { 92 cmdq_error(item, "%s: %s", file, strerror(errno)); 93 goto error; 94 } 95 96 pdata = NULL; 97 psize = 0; 98 while ((ch = getc(f)) != EOF) { 99 /* Do not let the server die due to memory exhaustion. */ 100 if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { 101 cmdq_error(item, "realloc error: %s", strerror(errno)); 102 goto error; 103 } 104 pdata = new_pdata; 105 pdata[psize++] = ch; 106 } 107 if (ferror(f)) { 108 cmdq_error(item, "%s: read error", file); 109 goto error; 110 } 111 if (pdata != NULL) 112 pdata[psize] = '\0'; 113 114 fclose(f); 115 free(file); 116 117 if (paste_set(pdata, psize, bufname, &cause) != 0) { 118 cmdq_error(item, "%s", cause); 119 free(pdata); 120 free(cause); 121 return (CMD_RETURN_ERROR); 122 } 123 124 return (CMD_RETURN_NORMAL); 125 126 error: 127 free(pdata); 128 if (f != NULL) 129 fclose(f); 130 free(file); 131 return (CMD_RETURN_ERROR); 132 } 133 134 static void 135 cmd_load_buffer_callback(struct client *c, int closed, void *data) 136 { 137 struct cmd_load_buffer_data *cdata = data; 138 char *pdata, *cause, *saved; 139 size_t psize; 140 141 if (!closed) 142 return; 143 c->stdin_callback = NULL; 144 145 server_client_unref(c); 146 if (c->flags & CLIENT_DEAD) 147 goto out; 148 149 psize = EVBUFFER_LENGTH(c->stdin_data); 150 if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) 151 goto out; 152 153 memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); 154 pdata[psize] = '\0'; 155 evbuffer_drain(c->stdin_data, psize); 156 157 if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) { 158 /* No context so can't use server_client_msg_error. */ 159 if (~c->flags & CLIENT_UTF8) { 160 saved = cause; 161 cause = utf8_sanitize(saved); 162 free(saved); 163 } 164 evbuffer_add_printf(c->stderr_data, "%s", cause); 165 server_client_push_stderr(c); 166 free(pdata); 167 free(cause); 168 } 169 out: 170 cdata->item->flags &= ~CMDQ_WAITING; 171 172 free(cdata->bufname); 173 free(cdata); 174 } 175