1 /* $NetBSD: exec_command.c,v 1.1.1.2 2013/08/21 20:09:58 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* exec_command 3 6 /* SUMMARY 7 /* execute command 8 /* SYNOPSIS 9 /* #include <exec_command.h> 10 /* 11 /* NORETURN exec_command(command) 12 /* const char *command; 13 /* DESCRIPTION 14 /* \fIexec_command\fR() replaces the current process by an instance 15 /* of \fIcommand\fR. This routine uses a simple heuristic to avoid 16 /* the overhead of running a command shell interpreter. 17 /* DIAGNOSTICS 18 /* This routine never returns. All errors are fatal. 19 /* LICENSE 20 /* .ad 21 /* .fi 22 /* The Secure Mailer license must be distributed with this software. 23 /* AUTHOR(S) 24 /* Wietse Venema 25 /* IBM T.J. Watson Research 26 /* P.O. Box 704 27 /* Yorktown Heights, NY 10598, USA 28 /*--*/ 29 30 /* System library. */ 31 32 #include <sys_defs.h> 33 #include <unistd.h> 34 #include <string.h> 35 #ifdef USE_PATHS_H 36 #include <paths.h> 37 #endif 38 #include <errno.h> 39 #include <string.h> 40 41 /* Utility library. */ 42 43 #include <msg.h> 44 #include <argv.h> 45 #include <exec_command.h> 46 47 /* Application-specific. */ 48 49 #define SPACE_TAB " \t" 50 51 /* exec_command - exec command */ 52 53 NORETURN exec_command(const char *command) 54 { 55 ARGV *argv; 56 57 /* 58 * Character filter. In this particular case, we allow space and tab in 59 * addition to the regular character set. 60 */ 61 static char ok_chars[] = "1234567890!@%-_=+:,./\ 62 abcdefghijklmnopqrstuvwxyz\ 63 ABCDEFGHIJKLMNOPQRSTUVWXYZ" SPACE_TAB; 64 65 /* 66 * See if this command contains any shell magic characters. 67 */ 68 if (command[strspn(command, ok_chars)] == 0 69 && command[strspn(command, SPACE_TAB)] != 0) { 70 71 /* 72 * No shell meta characters found, so we can try to avoid the overhead 73 * of running a shell. Just split the command on whitespace and exec 74 * the result directly. 75 */ 76 argv = argv_split(command, SPACE_TAB); 77 (void) execvp(argv->argv[0], argv->argv); 78 79 /* 80 * Auch. Perhaps they're using some shell built-in command. 81 */ 82 if (errno != ENOENT || strchr(argv->argv[0], '/') != 0) 83 msg_fatal("execvp %s: %m", argv->argv[0]); 84 85 /* 86 * Not really necessary, but... 87 */ 88 argv_free(argv); 89 } 90 91 /* 92 * Pass the command to a shell. 93 */ 94 (void) execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0); 95 msg_fatal("execl %s: %m", _PATH_BSHELL); 96 } 97 98 #ifdef TEST 99 100 /* 101 * Yet another proof-of-concept test program. 102 */ 103 #include <vstream.h> 104 #include <msg_vstream.h> 105 106 int main(int argc, char **argv) 107 { 108 msg_vstream_init(argv[0], VSTREAM_ERR); 109 if (argc != 2) 110 msg_fatal("usage: %s 'command'", argv[0]); 111 exec_command(argv[1]); 112 } 113 114 #endif 115