1/*	$NetBSD$	*/
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
53NORETURN 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!@%-_=+:,./\
62abcdefghijklmnopqrstuvwxyz\
63ABCDEFGHIJKLMNOPQRSTUVWXYZ" SPACE_TAB;
64
65    /*
66     * See if this command contains any shell magic characters.
67     */
68    if (command[strspn(command, ok_chars)] == 0) {
69
70	/*
71	 * No shell meta characters found, so we can try to avoid the overhead
72	 * of running a shell. Just split the command on whitespace and exec
73	 * the result directly.
74	 */
75	argv = argv_split(command, SPACE_TAB);
76	(void) execvp(argv->argv[0], argv->argv);
77
78	/*
79	 * Auch. Perhaps they're using some shell built-in command.
80	 */
81	if (errno != ENOENT || strchr(argv->argv[0], '/') != 0)
82	    msg_fatal("execvp %s: %m", argv->argv[0]);
83
84	/*
85	 * Not really necessary, but...
86	 */
87	argv_free(argv);
88    }
89
90    /*
91     * Pass the command to a shell.
92     */
93    (void) execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0);
94    msg_fatal("execl %s: %m", _PATH_BSHELL);
95}
96
97#ifdef TEST
98
99 /*
100  * Yet another proof-of-concept test program.
101  */
102#include <vstream.h>
103#include <msg_vstream.h>
104
105int     main(int argc, char **argv)
106{
107    msg_vstream_init(argv[0], VSTREAM_ERR);
108    if (argc != 2)
109	msg_fatal("usage: %s 'command'", argv[0]);
110    exec_command(argv[1]);
111}
112
113#endif
114