1 /*
2  * libdpkg - Debian packaging suite library routines
3  * command.c - command execution support
4  *
5  * Copyright © 2010-2012 Guillem Jover <guillem@debian.org>
6  *
7  * This is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include <config.h>
22 #include <compat.h>
23 
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 
28 #include <dpkg/dpkg.h>
29 #include <dpkg/i18n.h>
30 #include <dpkg/string.h>
31 #include <dpkg/path.h>
32 #include <dpkg/command.h>
33 
34 /**
35  * Initialize a command structure.
36  *
37  * If name is NULL, then the last component of the filename path will be
38  * used to initialize the name member.
39  *
40  * @param cmd The command structure to initialize.
41  * @param filename The filename of the command to execute.
42  * @param name The description of the command to execute.
43  */
44 void
command_init(struct command * cmd,const char * filename,const char * name)45 command_init(struct command *cmd, const char *filename, const char *name)
46 {
47 	cmd->filename = filename;
48 	if (name == NULL)
49 		cmd->name = path_basename(filename);
50 	else
51 		cmd->name = name;
52 	cmd->argc = 0;
53 	cmd->argv_size = 10;
54 	cmd->argv = m_malloc(cmd->argv_size * sizeof(const char *));
55 	cmd->argv[0] = NULL;
56 }
57 
58 /**
59  * Destroy a command structure.
60  *
61  * Free the members managed by the command functions (i.e. the argv pointer
62  * array), and zero all members of a command structure.
63  *
64  * @param cmd The command structure to free.
65  */
66 void
command_destroy(struct command * cmd)67 command_destroy(struct command *cmd)
68 {
69 	cmd->filename = NULL;
70 	cmd->name = NULL;
71 	cmd->argc = 0;
72 	cmd->argv_size = 0;
73 	free(cmd->argv);
74 	cmd->argv = NULL;
75 }
76 
77 static void
command_grow_argv(struct command * cmd,int need)78 command_grow_argv(struct command *cmd, int need)
79 {
80 	/* We need a ghost byte for the NUL character. */
81 	need++;
82 
83 	/* Check if we already have enough room. */
84 	if ((cmd->argv_size - cmd->argc) >= need)
85 		return;
86 
87 	cmd->argv_size = (cmd->argv_size + need) * 2;
88 	cmd->argv = m_realloc(cmd->argv, cmd->argv_size * sizeof(const char *));
89 }
90 
91 /**
92  * Append an argument to the command's argv.
93  *
94  * @param cmd The command structure to act on.
95  * @param arg The argument to append to argv.
96  */
97 void
command_add_arg(struct command * cmd,const char * arg)98 command_add_arg(struct command *cmd, const char *arg)
99 {
100 	command_grow_argv(cmd, 1);
101 
102 	cmd->argv[cmd->argc++] = arg;
103 	cmd->argv[cmd->argc] = NULL;
104 }
105 
106 /**
107  * Append an argument array to the command's argv.
108  *
109  * @param cmd The command structure to act on.
110  * @param argv The NULL terminated argument array to append to argv.
111  */
112 void
command_add_argl(struct command * cmd,const char ** argv)113 command_add_argl(struct command *cmd, const char **argv)
114 {
115 	int i, add_argc = 0;
116 
117 	while (argv[add_argc] != NULL)
118 		add_argc++;
119 
120 	command_grow_argv(cmd, add_argc);
121 
122 	for (i = 0; i < add_argc; i++)
123 		cmd->argv[cmd->argc++] = argv[i];
124 
125 	cmd->argv[cmd->argc] = NULL;
126 }
127 
128 /**
129  * Append a va_list of argument to the command's argv.
130  *
131  * @param cmd The command structure to act on.
132  * @param args The NULL terminated va_list of argument array to append to argv.
133  */
134 void
command_add_argv(struct command * cmd,va_list args)135 command_add_argv(struct command *cmd, va_list args)
136 {
137 	va_list args_copy;
138 	int i, add_argc = 0;
139 
140 	va_copy(args_copy, args);
141 	while (va_arg(args_copy, const char *) != NULL)
142 		add_argc++;
143 	va_end(args_copy);
144 
145 	command_grow_argv(cmd, add_argc);
146 
147 	for (i = 0; i < add_argc; i++)
148 		cmd->argv[cmd->argc++] = va_arg(args, const char *);
149 
150 	cmd->argv[cmd->argc] = NULL;
151 }
152 
153 /**
154  * Append a variable list of argument to the command's argv.
155  *
156  * @param cmd The command structure to act on.
157  * @param ... The NULL terminated variable list of argument to append to argv.
158  */
159 void
command_add_args(struct command * cmd,...)160 command_add_args(struct command *cmd, ...)
161 {
162 	va_list args;
163 
164 	va_start(args, cmd);
165 	command_add_argv(cmd, args);
166 	va_end(args);
167 }
168 
169 /**
170  * Execute the command specified.
171  *
172  * The command is executed searching the PATH if the filename does not
173  * contain any slashes, or using the full path if it's either a relative or
174  * absolute pathname. This functions does not return.
175  *
176  * @param cmd The command structure to act on.
177  */
178 void
command_exec(struct command * cmd)179 command_exec(struct command *cmd)
180 {
181 	execvp(cmd->filename, (char * const *)cmd->argv);
182 	ohshite(_("unable to execute %s (%s)"), cmd->name, cmd->filename);
183 }
184 
185 /**
186  * Execute a shell with a possible command.
187  *
188  * @param cmd The command string to execute, if it's NULL an interactive
189  *            shell will be executed instead.
190  * @param name The description of the command to execute.
191  */
192 void
command_shell(const char * cmd,const char * name)193 command_shell(const char *cmd, const char *name)
194 {
195 	const char *shell;
196 	const char *mode;
197 
198 	if (cmd == NULL) {
199 		mode = "-i";
200 		shell = getenv("SHELL");
201 	} else {
202 		mode = "-c";
203 		shell = NULL;
204 	}
205 
206 	if (str_is_unset(shell))
207 		shell = DEFAULTSHELL;
208 
209 	execlp(shell, shell, mode, cmd, NULL);
210 	ohshite(_("unable to execute %s (%s)"), name, cmd);
211 }
212