1 /* $OpenBSD$ */ 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 return (CMD_RETURN_ERROR); 91 } 92 return (CMD_RETURN_WAIT); 93 } 94 95 file = server_client_get_path(c, path); 96 free(path); 97 98 f = fopen(file, "rb"); 99 if (f == NULL) { 100 cmdq_error(item, "%s: %s", file, strerror(errno)); 101 goto error; 102 } 103 104 pdata = NULL; 105 psize = 0; 106 while ((ch = getc(f)) != EOF) { 107 /* Do not let the server die due to memory exhaustion. */ 108 if ((new_pdata = realloc(pdata, psize + 2)) == NULL) { 109 cmdq_error(item, "realloc error: %s", strerror(errno)); 110 goto error; 111 } 112 pdata = new_pdata; 113 pdata[psize++] = ch; 114 } 115 if (ferror(f)) { 116 cmdq_error(item, "%s: read error", file); 117 goto error; 118 } 119 if (pdata != NULL) 120 pdata[psize] = '\0'; 121 122 fclose(f); 123 free(file); 124 125 if (paste_set(pdata, psize, bufname, &cause) != 0) { 126 cmdq_error(item, "%s", cause); 127 free(pdata); 128 free(cause); 129 return (CMD_RETURN_ERROR); 130 } 131 132 return (CMD_RETURN_NORMAL); 133 134 error: 135 free(pdata); 136 if (f != NULL) 137 fclose(f); 138 free(file); 139 return (CMD_RETURN_ERROR); 140 } 141 142 static void 143 cmd_load_buffer_callback(struct client *c, int closed, void *data) 144 { 145 struct cmd_load_buffer_data *cdata = data; 146 char *pdata, *cause, *saved; 147 size_t psize; 148 149 if (!closed) 150 return; 151 c->stdin_callback = NULL; 152 153 server_client_unref(c); 154 if (c->flags & CLIENT_DEAD) 155 goto out; 156 157 psize = EVBUFFER_LENGTH(c->stdin_data); 158 if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) 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 if (paste_set(pdata, psize, cdata->bufname, &cause) != 0) { 166 /* No context so can't use server_client_msg_error. */ 167 if (~c->flags & CLIENT_UTF8) { 168 saved = cause; 169 cause = utf8_sanitize(saved); 170 free(saved); 171 } 172 evbuffer_add_printf(c->stderr_data, "%s", cause); 173 server_client_push_stderr(c); 174 free(pdata); 175 free(cause); 176 } 177 out: 178 cdata->item->flags &= ~CMDQ_WAITING; 179 180 free(cdata->bufname); 181 free(cdata); 182 } 183