1 /* $OpenBSD: cmd-load-buffer.c,v 1.43 2016/10/10 21:51:39 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 cmd_q *); 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 = 0, 46 .exec = cmd_load_buffer_exec 47 }; 48 49 static enum cmd_retval 50 cmd_load_buffer_exec(struct cmd *self, struct cmd_q *cmdq) 51 { 52 struct args *args = self->args; 53 struct client *c = cmdq->client; 54 struct session *s; 55 FILE *f; 56 const char *path, *bufname, *cwd; 57 char *pdata, *new_pdata, *cause, *file, resolved[PATH_MAX]; 58 size_t psize; 59 int ch, error; 60 61 bufname = NULL; 62 if (args_has(args, 'b')) 63 bufname = args_get(args, 'b'); 64 65 path = args->argv[0]; 66 if (strcmp(path, "-") == 0) { 67 error = server_set_stdin_callback(c, cmd_load_buffer_callback, 68 (void *)bufname, &cause); 69 if (error != 0) { 70 cmdq_error(cmdq, "%s: %s", path, cause); 71 free(cause); 72 return (CMD_RETURN_ERROR); 73 } 74 return (CMD_RETURN_WAIT); 75 } 76 77 if (c != NULL && c->session == NULL && c->cwd != NULL) 78 cwd = c->cwd; 79 else if ((s = c->session) != NULL && s->cwd != NULL) 80 cwd = s->cwd; 81 else 82 cwd = "."; 83 84 if (*path == '/') 85 file = xstrdup(path); 86 else 87 xasprintf(&file, "%s/%s", cwd, path); 88 if (realpath(file, resolved) == NULL && 89 strlcpy(resolved, file, sizeof resolved) >= sizeof resolved) { 90 cmdq_error(cmdq, "%s: %s", file, strerror(ENAMETOOLONG)); 91 return (CMD_RETURN_ERROR); 92 } 93 f = fopen(resolved, "rb"); 94 free(file); 95 if (f == NULL) { 96 cmdq_error(cmdq, "%s: %s", resolved, 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", resolved); 113 goto error; 114 } 115 if (pdata != NULL) 116 pdata[psize] = '\0'; 117 118 fclose(f); 119 120 if (paste_set(pdata, psize, bufname, &cause) != 0) { 121 cmdq_error(cmdq, "%s", cause); 122 free(pdata); 123 free(cause); 124 return (CMD_RETURN_ERROR); 125 } 126 127 return (CMD_RETURN_NORMAL); 128 129 error: 130 free(pdata); 131 if (f != NULL) 132 fclose(f); 133 return (CMD_RETURN_ERROR); 134 } 135 136 static void 137 cmd_load_buffer_callback(struct client *c, int closed, void *data) 138 { 139 const char *bufname = data; 140 char *pdata, *cause, *saved; 141 size_t psize; 142 143 if (!closed) 144 return; 145 c->stdin_callback = NULL; 146 147 server_client_unref(c); 148 if (c->flags & CLIENT_DEAD) 149 return; 150 151 psize = EVBUFFER_LENGTH(c->stdin_data); 152 if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) 153 goto out; 154 155 memcpy(pdata, EVBUFFER_DATA(c->stdin_data), psize); 156 pdata[psize] = '\0'; 157 evbuffer_drain(c->stdin_data, psize); 158 159 if (paste_set(pdata, psize, bufname, &cause) != 0) { 160 /* No context so can't use server_client_msg_error. */ 161 if (~c->flags & CLIENT_UTF8) { 162 saved = cause; 163 cause = utf8_sanitize(saved); 164 free(saved); 165 } 166 evbuffer_add_printf(c->stderr_data, "%s", cause); 167 server_client_push_stderr(c); 168 free(pdata); 169 free(cause); 170 } 171 172 out: 173 cmdq_continue(c->cmdq); 174 } 175