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