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