1 /* $OpenBSD: cmd-load-buffer.c,v 1.54 2018/08/27 11:03:34 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 = cmd_find_client(item, NULL, 1); 60 struct session *s = item->target.s; 61 struct winlink *wl = item->target.wl; 62 struct window_pane *wp = item->target.wp; 63 FILE *f; 64 const char *bufname; 65 char *pdata = NULL, *new_pdata, *cause; 66 char *path, *file; 67 size_t psize; 68 int ch, error; 69 70 bufname = NULL; 71 if (args_has(args, 'b')) 72 bufname = args_get(args, 'b'); 73 74 path = format_single(item, args->argv[0], c, s, wl, wp); 75 if (strcmp(path, "-") == 0) { 76 free(path); 77 c = item->client; 78 79 cdata = xcalloc(1, sizeof *cdata); 80 cdata->item = item; 81 82 if (bufname != NULL) 83 cdata->bufname = xstrdup(bufname); 84 85 error = server_set_stdin_callback(c, cmd_load_buffer_callback, 86 cdata, &cause); 87 if (error != 0) { 88 cmdq_error(item, "-: %s", cause); 89 free(cause); 90 free(cdata); 91 return (CMD_RETURN_ERROR); 92 } 93 return (CMD_RETURN_WAIT); 94 } 95 96 file = server_client_get_path(c, path); 97 free(path); 98 99 f = fopen(file, "rb"); 100 if (f == NULL) { 101 cmdq_error(item, "%s: %s", file, strerror(errno)); 102 goto error; 103 } 104 105 pdata = NULL; 106 psize = 0; 107 while ((ch = getc(f)) != EOF) { 108 /* Do not let the server die due to memory exhaustion. */ 109 if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { 110 cmdq_error(item, "realloc error: %s", strerror(errno)); 111 goto error; 112 } 113 pdata = new_pdata; 114 pdata[psize++] = ch; 115 } 116 if (ferror(f)) { 117 cmdq_error(item, "%s: read error", file); 118 goto error; 119 } 120 if (pdata != NULL) 121 pdata[psize] = '\0'; 122 123 fclose(f); 124 free(file); 125 126 if (paste_set(pdata, psize, bufname, &cause) != 0) { 127 cmdq_error(item, "%s", cause); 128 free(pdata); 129 free(cause); 130 return (CMD_RETURN_ERROR); 131 } 132 133 return (CMD_RETURN_NORMAL); 134 135 error: 136 free(pdata); 137 if (f != NULL) 138 fclose(f); 139 free(file); 140 return (CMD_RETURN_ERROR); 141 } 142 143 static void 144 cmd_load_buffer_callback(struct client *c, int closed, void *data) 145 { 146 struct cmd_load_buffer_data *cdata = data; 147 char *pdata, *cause, *saved; 148 size_t psize; 149 150 if (!closed) 151 return; 152 c->stdin_callback = NULL; 153 154 server_client_unref(c); 155 if (c->flags & CLIENT_DEAD) 156 goto out; 157 158 psize = EVBUFFER_LENGTH(c->stdin_data); 159 if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) 160 goto out; 161 162 memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); 163 pdata[psize] = '\0'; 164 evbuffer_drain(c->stdin_data, psize); 165 166 if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) { 167 /* No context so can't use server_client_msg_error. */ 168 if (~c->flags & CLIENT_UTF8) { 169 saved = cause; 170 cause = utf8_sanitize(saved); 171 free(saved); 172 } 173 evbuffer_add_printf(c->stderr_data, "%s", cause); 174 server_client_push_stderr(c); 175 free(pdata); 176 free(cause); 177 } 178 out: 179 cdata->item->flags &= ~CMDQ_WAITING; 180 181 free(cdata->bufname); 182 free(cdata); 183 } 184