pexec

execute a program from standard input
git clone git://git.2f30.org/pexec.git
Log | Files | Refs

pexec.c (2517B)


      1 /*
      2  * Copyright (c) 2018 Dimitris Papastamos <sin@2f30.org>
      3  *
      4  * Permission to use, copy, modify, and distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 /*
     18  * execute a program from stdin
     19  *
     20  * example: ssh user@host pexec ls -la < /bin/ls
     21  *
     22  * This is true cloud computing!
     23  */
     24 
     25 #include <sys/stat.h>
     26 #include <sys/syscall.h>
     27 #include <err.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <unistd.h>
     31 #include "arg.h"
     32 
     33 char *argv0;
     34 
     35 static ssize_t
     36 xread(int fd, void *buf, size_t nbytes)
     37 {
     38 	unsigned char *bp = buf;
     39 	ssize_t total = 0;
     40 
     41 	while (nbytes > 0) {
     42 		ssize_t n;
     43 
     44 		n = read(fd, &bp[total], nbytes);
     45 		if (n < 0)
     46 			err(1, "read");
     47 		else if (n == 0)
     48 			return total;
     49 		total += n;
     50 		nbytes -= n;
     51 	}
     52 	return total;
     53 }
     54 
     55 static ssize_t
     56 xwrite(int fd, const void *buf, size_t nbytes)
     57 {
     58 	const unsigned char *bp = buf;
     59 	ssize_t total = 0;
     60 
     61 	while (nbytes > 0) {
     62 		ssize_t n;
     63 
     64 		n = write(fd, &bp[total], nbytes);
     65 		if (n < 0)
     66 			err(1, "write");
     67 		else if (n == 0)
     68 			return total;
     69 		total += n;
     70 		nbytes -= n;
     71 	}
     72 	return total;
     73 }
     74 
     75 static int
     76 memfd_create(const char *name, unsigned int flags)
     77 {
     78 	return syscall(__NR_memfd_create, name, flags);
     79 }
     80 
     81 void
     82 pexec(int ifd, char *argv[], char *envp[])
     83 {
     84 	char buf[BUFSIZ];
     85 	ssize_t n;
     86 	int fd;
     87 
     88 	fd = memfd_create(argv[0], 0);
     89 	if (fd < 0)
     90 		err(1, "memfd_create");
     91 
     92 	if (fchmod(fd, 0755) < 0)
     93 		err(1, "fchmod");
     94 
     95 	while ((n = xread(ifd, buf, sizeof(buf))) > 0)
     96 		xwrite(fd, buf, n);
     97 
     98 	if (fexecve(fd, argv, envp) < 0)
     99 		err(1, "fexecve");
    100 }
    101 
    102 static void
    103 usage(void)
    104 {
    105 	fprintf(stderr, "usage: pexec [-i] argv[0] [argv[1]...]\n");
    106 	exit(1);
    107 }
    108 
    109 int
    110 main(int argc, char *argv[])
    111 {
    112 	char *envp[] = { NULL };
    113 	int iflag = 0;
    114 
    115 	ARGBEGIN {
    116 	case 'i':
    117 		iflag = 1;
    118 		break;
    119 	default:
    120 		usage();
    121 	} ARGEND
    122 
    123 	if (argc == 0)
    124 		usage();
    125 
    126 	extern char **environ;
    127 	pexec(STDIN_FILENO, argv, iflag ? envp : environ);
    128 	/* unreachable */
    129 }