xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/exec_command.c (revision d6384a751f5f4beb133abed41aa9964df66d9f1c)
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 
exec_command(const char * command)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 
main(int argc,char ** argv)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