1 /* 2 * rpcd - UBUS RPC server 3 * 4 * Copyright (C) 2013-2014 Jo-Philipp Wich <jow@openwrt.org> 5 * 6 * Permission to use, copy, modify, and/or 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 USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <fcntl.h> 20 #include <errno.h> 21 #include <unistd.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <limits.h> 25 #include <dirent.h> 26 #include <sys/stat.h> 27 #include <sys/wait.h> 28 29 #include <rpcd/exec.h> 30 31 static int 32 rpc_errno_status(void) 33 { 34 switch (errno) 35 { 36 case EACCES: 37 return UBUS_STATUS_PERMISSION_DENIED; 38 39 case ENOTDIR: 40 return UBUS_STATUS_INVALID_ARGUMENT; 41 42 case ENOENT: 43 return UBUS_STATUS_NOT_FOUND; 44 45 case EINVAL: 46 return UBUS_STATUS_INVALID_ARGUMENT; 47 48 default: 49 return UBUS_STATUS_UNKNOWN_ERROR; 50 } 51 } 52 53 const char * 54 rpc_exec_lookup(const char *cmd) 55 { 56 struct stat s; 57 int plen = 0, clen = strlen(cmd) + 1; 58 char *search, *p; 59 static char path[PATH_MAX]; 60 61 if (!stat(cmd, &s) && S_ISREG(s.st_mode)) 62 return cmd; 63 64 search = getenv("PATH"); 65 66 if (!search) 67 search = "/bin:/usr/bin:/sbin:/usr/sbin"; 68 69 p = search; 70 71 do 72 { 73 if (*p != ':' && *p != '\0') 74 continue; 75 76 plen = p - search; 77 78 if ((plen + clen) >= sizeof(path)) 79 continue; 80 81 strncpy(path, search, plen); 82 sprintf(path + plen, "/%s", cmd); 83 84 if (!stat(path, &s) && S_ISREG(s.st_mode)) 85 return path; 86 87 search = p + 1; 88 } 89 while (*p++); 90 91 return NULL; 92 } 93 94 95 static void 96 rpc_ustream_to_blobmsg(struct blob_buf *blob, struct ustream *s, 97 const char *name) 98 { 99 int len; 100 char *rbuf, *wbuf; 101 102 if ((len = ustream_pending_data(s, false)) > 0) 103 { 104 wbuf = blobmsg_alloc_string_buffer(blob, name, len + 1); 105 106 if (!wbuf) 107 return; 108 109 ustream_for_each_read_buffer(s, rbuf, len) 110 { 111 memcpy(wbuf, rbuf, len); 112 wbuf += len; 113 } 114 115 *wbuf = 0; 116 blobmsg_add_string_buffer(blob); 117 } 118 } 119 120 static void 121 rpc_exec_reply(struct rpc_exec_context *c, int rv) 122 { 123 uloop_timeout_cancel(&c->timeout); 124 uloop_process_delete(&c->process); 125 126 if (rv == UBUS_STATUS_OK) 127 { 128 if (!c->stdout_cb && !c->stderr_cb && !c->finish_cb) 129 { 130 blobmsg_add_u32(&c->blob, "code", WEXITSTATUS(c->stat)); 131 rpc_ustream_to_blobmsg(&c->blob, &c->opipe.stream, "stdout"); 132 rpc_ustream_to_blobmsg(&c->blob, &c->epipe.stream, "stderr"); 133 } 134 } 135 136 if (c->finish_cb) 137 rv = c->finish_cb(&c->blob, c->stat, c->priv); 138 139 if (rv == UBUS_STATUS_OK) 140 ubus_send_reply(c->context, &c->request, c->blob.head); 141 142 ubus_complete_deferred_request(c->context, &c->request, rv); 143 144 blob_buf_free(&c->blob); 145 146 ustream_free(&c->opipe.stream); 147 ustream_free(&c->epipe.stream); 148 149 close(c->opipe.fd.fd); 150 close(c->epipe.fd.fd); 151 152 if (c->priv) 153 free(c->priv); 154 155 free(c); 156 } 157 158 static void 159 rpc_exec_reply_cb(struct uloop_timeout *t) 160 { 161 struct rpc_exec_context *c = 162 container_of(t, struct rpc_exec_context, timeout); 163 164 rpc_exec_reply(c, c->deferred_status); 165 } 166 167 static void 168 rpc_exec_schedule_reply(struct rpc_exec_context *c, int rv) 169 { 170 c->deferred_status = rv; 171 c->timeout.cb = rpc_exec_reply_cb; 172 uloop_timeout_set(&c->timeout, 0); 173 } 174 175 static void 176 rpc_exec_timeout_cb(struct uloop_timeout *t) 177 { 178 struct rpc_exec_context *c = 179 container_of(t, struct rpc_exec_context, timeout); 180 181 kill(c->process.pid, SIGKILL); 182 rpc_exec_schedule_reply(c, UBUS_STATUS_TIMEOUT); 183 } 184 185 static void 186 rpc_exec_process_cb(struct uloop_process *p, int stat) 187 { 188 struct rpc_exec_context *c = 189 container_of(p, struct rpc_exec_context, process); 190 191 c->stat = stat; 192 193 ustream_poll(&c->opipe.stream); 194 ustream_poll(&c->epipe.stream); 195 196 close(c->opipe.fd.fd); 197 close(c->epipe.fd.fd); 198 199 /* ustream_free() does not reset the fd, and rpc_exec_reply() closes it 200 * again later. Mark the descriptors as consumed so that the second 201 * close() cannot accidentally close an unrelated, meanwhile reused fd. */ 202 c->opipe.fd.fd = -1; 203 c->epipe.fd.fd = -1; 204 205 ustream_poll(&c->opipe.stream); 206 ustream_poll(&c->epipe.stream); 207 } 208 209 static void 210 rpc_exec_ipipe_write_cb(struct ustream *s, int bytes) 211 { 212 struct rpc_exec_context *c = 213 container_of(s, struct rpc_exec_context, ipipe.stream); 214 215 if (c->stdin_cb(s, c->priv) <= 0) 216 { 217 ustream_free(&c->ipipe.stream); 218 close(c->ipipe.fd.fd); 219 } 220 } 221 222 static void 223 rpc_exec_opipe_read_cb(struct ustream *s, int bytes) 224 { 225 int len, rv; 226 char *buf; 227 struct rpc_exec_context *c = 228 container_of(s, struct rpc_exec_context, opipe.stream); 229 230 if (c->stdout_cb) 231 { 232 do { 233 buf = ustream_get_read_buf(s, &len); 234 235 if (!buf || !len) 236 break; 237 238 rv = c->stdout_cb(&c->blob, buf, len, c->priv); 239 240 if (rv <= 0) 241 break; 242 243 ustream_consume(s, rv); 244 } while(1); 245 } 246 else if (ustream_read_buf_full(s)) 247 { 248 rpc_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED); 249 } 250 } 251 252 static void 253 rpc_exec_epipe_read_cb(struct ustream *s, int bytes) 254 { 255 int len, rv; 256 char *buf; 257 struct rpc_exec_context *c = 258 container_of(s, struct rpc_exec_context, epipe.stream); 259 260 if (c->stderr_cb) 261 { 262 do { 263 buf = ustream_get_read_buf(s, &len); 264 265 if (!buf || !len) 266 break; 267 268 rv = c->stderr_cb(&c->blob, buf, len, c->priv); 269 270 if (rv <= 0) 271 break; 272 273 ustream_consume(s, rv); 274 } while(1); 275 } 276 else if (ustream_read_buf_full(s)) 277 { 278 rpc_exec_schedule_reply(c, UBUS_STATUS_NOT_SUPPORTED); 279 } 280 } 281 282 static void 283 rpc_exec_opipe_state_cb(struct ustream *s) 284 { 285 struct rpc_exec_context *c = 286 container_of(s, struct rpc_exec_context, opipe.stream); 287 288 if (c->opipe.stream.eof && c->epipe.stream.eof) 289 rpc_exec_schedule_reply(c, UBUS_STATUS_OK); 290 } 291 292 static void 293 rpc_exec_epipe_state_cb(struct ustream *s) 294 { 295 struct rpc_exec_context *c = 296 container_of(s, struct rpc_exec_context, epipe.stream); 297 298 if (c->opipe.stream.eof && c->epipe.stream.eof) 299 rpc_exec_schedule_reply(c, UBUS_STATUS_OK); 300 } 301 302 int 303 rpc_exec(const char **args, rpc_exec_write_cb_t in, 304 rpc_exec_read_cb_t out, rpc_exec_read_cb_t err, 305 rpc_exec_done_cb_t end, void *priv, struct ubus_context *ctx, 306 struct ubus_request_data *req) 307 { 308 pid_t pid; 309 310 int ipipe[2]; 311 int opipe[2]; 312 int epipe[2]; 313 314 const char *cmd; 315 struct rpc_exec_context *c; 316 317 cmd = rpc_exec_lookup(args[0]); 318 319 if (!cmd) 320 return UBUS_STATUS_NOT_FOUND; 321 322 c = malloc(sizeof(*c)); 323 324 if (!c) 325 return UBUS_STATUS_UNKNOWN_ERROR; 326 327 if (pipe(ipipe)) 328 goto fail_ipipe; 329 330 if (pipe(opipe)) 331 goto fail_opipe; 332 333 if (pipe(epipe)) 334 goto fail_epipe; 335 336 switch ((pid = fork())) 337 { 338 case -1: 339 goto fail_fork; 340 341 case 0: 342 uloop_done(); 343 344 dup2(ipipe[0], 0); 345 dup2(opipe[1], 1); 346 dup2(epipe[1], 2); 347 348 close(ipipe[0]); 349 close(ipipe[1]); 350 close(opipe[0]); 351 close(opipe[1]); 352 close(epipe[0]); 353 close(epipe[1]); 354 355 if (execv(cmd, (char * const *)args)) 356 _exit(127); 357 358 default: 359 memset(c, 0, sizeof(*c)); 360 blob_buf_init(&c->blob, 0); 361 362 c->stdin_cb = in; 363 c->stdout_cb = out; 364 c->stderr_cb = err; 365 c->finish_cb = end; 366 c->priv = priv; 367 368 ustream_declare_read(c->opipe, opipe[0], opipe); 369 ustream_declare_read(c->epipe, epipe[0], epipe); 370 371 c->process.pid = pid; 372 c->process.cb = rpc_exec_process_cb; 373 uloop_process_add(&c->process); 374 375 c->timeout.cb = rpc_exec_timeout_cb; 376 uloop_timeout_set(&c->timeout, rpc_exec_timeout); 377 378 if (c->stdin_cb) 379 { 380 ustream_declare_write(c->ipipe, ipipe[1], ipipe); 381 rpc_exec_ipipe_write_cb(&c->ipipe.stream, 0); 382 } 383 else 384 { 385 close(ipipe[1]); 386 } 387 388 close(ipipe[0]); 389 close(opipe[1]); 390 close(epipe[1]); 391 392 c->context = ctx; 393 ubus_defer_request(ctx, req, &c->request); 394 } 395 396 return UBUS_STATUS_OK; 397 398 fail_fork: 399 close(epipe[0]); 400 close(epipe[1]); 401 402 fail_epipe: 403 close(opipe[0]); 404 close(opipe[1]); 405 406 fail_opipe: 407 close(ipipe[0]); 408 close(ipipe[1]); 409 410 fail_ipipe: 411 free(c); 412 return rpc_errno_status(); 413 } 414
This page was automatically generated by LXR 0.3.1. • OpenWrt