xref: /openbsd-src/usr.bin/tmux/cmd-load-buffer.c (revision 35a092d62738012b07bf5af85703df23fc920d33)
1 /* $OpenBSD: cmd-load-buffer.c,v 1.19 2011/10/23 08:34:01 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 <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 
27 #include "tmux.h"
28 
29 /*
30  * Loads a paste buffer from a file.
31  */
32 
33 int	cmd_load_buffer_exec(struct cmd *, struct cmd_ctx *);
34 void	cmd_load_buffer_callback(struct client *, void *);
35 
36 const struct cmd_entry cmd_load_buffer_entry = {
37 	"load-buffer", "loadb",
38 	"b:", 1, 1,
39 	CMD_BUFFER_USAGE " path",
40 	0,
41 	NULL,
42 	NULL,
43 	cmd_load_buffer_exec
44 };
45 
46 int
47 cmd_load_buffer_exec(struct cmd *self, struct cmd_ctx *ctx)
48 {
49 	struct args	*args = self->args;
50 	struct client	*c = ctx->cmdclient;
51 	struct session  *s;
52 	FILE		*f;
53 	const char	*path, *newpath, *wd;
54 	char		*pdata, *new_pdata, *cause;
55 	size_t		 psize;
56 	u_int		 limit;
57 	int		 ch, buffer;
58 	int		*buffer_ptr;
59 
60 	if (!args_has(args, 'b'))
61 		buffer = -1;
62 	else {
63 		buffer = args_strtonum(args, 'b', 0, INT_MAX, &cause);
64 		if (cause != NULL) {
65 			ctx->error(ctx, "buffer %s", cause);
66 			xfree(cause);
67 			return (-1);
68 		}
69 	}
70 
71 	path = args->argv[0];
72 	if (strcmp(path, "-") == 0) {
73 		if (c == NULL) {
74 			ctx->error(ctx, "%s: can't read from stdin", path);
75 			return (-1);
76 		}
77 		if (c->flags & CLIENT_TERMINAL) {
78 			ctx->error(ctx, "%s: stdin is a tty", path);
79 			return (-1);
80 		}
81 		if (c->stdin_fd == -1) {
82 			ctx->error(ctx, "%s: can't read from stdin", path);
83 			return (-1);
84 		}
85 
86 		buffer_ptr = xmalloc(sizeof *buffer_ptr);
87 		*buffer_ptr = buffer;
88 
89 		c->stdin_data = buffer_ptr;
90 		c->stdin_callback = cmd_load_buffer_callback;
91 
92 		c->references++;
93 		bufferevent_enable(c->stdin_event, EV_READ);
94 		return (1);
95 	}
96 
97 	if (c != NULL)
98 		wd = c->cwd;
99 	else if ((s = cmd_current_session(ctx, 0)) != NULL) {
100 		wd = options_get_string(&s->options, "default-path");
101 		if (*wd == '\0')
102 			wd = s->cwd;
103 	} else
104 		wd = NULL;
105 	if (wd != NULL && *wd != '\0') {
106 		newpath = get_full_path(wd, path);
107 		if (newpath != NULL)
108 			path = newpath;
109 	}
110 	if ((f = fopen(path, "rb")) == NULL) {
111 		ctx->error(ctx, "%s: %s", path, strerror(errno));
112 		return (-1);
113 	}
114 
115 	pdata = NULL;
116 	psize = 0;
117 	while ((ch = getc(f)) != EOF) {
118 		/* Do not let the server die due to memory exhaustion. */
119 		if ((new_pdata = realloc(pdata, psize + 2)) == NULL) {
120 			ctx->error(ctx, "realloc error: %s", strerror(errno));
121 			goto error;
122 		}
123 		pdata = new_pdata;
124 		pdata[psize++] = ch;
125 	}
126 	if (ferror(f)) {
127 		ctx->error(ctx, "%s: read error", path);
128 		goto error;
129 	}
130 	if (pdata != NULL)
131 		pdata[psize] = '\0';
132 
133 	fclose(f);
134 
135 	limit = options_get_number(&global_options, "buffer-limit");
136 	if (buffer == -1) {
137 		paste_add(&global_buffers, pdata, psize, limit);
138 		return (0);
139 	}
140 	if (paste_replace(&global_buffers, buffer, pdata, psize) != 0) {
141 		ctx->error(ctx, "no buffer %d", buffer);
142 		xfree(pdata);
143 		return (-1);
144 	}
145 
146 	return (0);
147 
148 error:
149 	if (pdata != NULL)
150 		xfree(pdata);
151 	if (f != NULL)
152 		fclose(f);
153 	return (-1);
154 }
155 
156 void
157 cmd_load_buffer_callback(struct client *c, void *data)
158 {
159 	int	*buffer = data;
160 	char	*pdata;
161 	size_t	 psize;
162 	u_int	 limit;
163 
164 	/*
165 	 * Event callback has already checked client is not dead and reduced
166 	 * its reference count. But tell it to exit.
167 	 */
168 	c->flags |= CLIENT_EXIT;
169 
170 	psize = EVBUFFER_LENGTH(c->stdin_event->input);
171 	if (psize == 0 || (pdata = malloc(psize + 1)) == NULL) {
172 		xfree(data);
173 		return;
174 	}
175 	bufferevent_read(c->stdin_event, pdata, psize);
176 	pdata[psize] = '\0';
177 
178 	limit = options_get_number(&global_options, "buffer-limit");
179 	if (*buffer == -1)
180 		paste_add(&global_buffers, pdata, psize, limit);
181 	else if (paste_replace(&global_buffers, *buffer, pdata, psize) != 0) {
182 		/* No context so can't use server_client_msg_error. */
183 		evbuffer_add_printf(
184 		    c->stderr_event->output, "no buffer %d\n", *buffer);
185 		bufferevent_enable(c->stderr_event, EV_WRITE);
186 	}
187 
188 	xfree(data);
189 }
190