Branch data Line data Source code
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/varbuf.h>
32 : : #include <dpkg/file.h>
33 : : #include <dpkg/path.h>
34 : : #include <dpkg/command.h>
35 : :
36 : : /**
37 : : * Initialize a command structure.
38 : : *
39 : : * If name is NULL, then the last component of the filename path will be
40 : : * used to initialize the name member.
41 : : *
42 : : * @param cmd The command structure to initialize.
43 : : * @param filename The filename of the command to execute.
44 : : * @param name The description of the command to execute.
45 : : */
46 : : void
47 : 71 : command_init(struct command *cmd, const char *filename, const char *name)
48 : : {
49 : 71 : cmd->filename = filename;
50 [ + + ]: 71 : if (name == NULL)
51 : 6 : cmd->name = path_basename(filename);
52 : : else
53 : 65 : cmd->name = name;
54 : 71 : cmd->argc = 0;
55 : 71 : cmd->argv_size = 10;
56 : 71 : cmd->argv = m_malloc(cmd->argv_size * sizeof(cmd->argv[0]));
57 : 71 : cmd->argv[0] = NULL;
58 : 71 : }
59 : :
60 : : /**
61 : : * Destroy a command structure.
62 : : *
63 : : * Free the members managed by the command functions (i.e. the argv pointer
64 : : * array), and zero all members of a command structure.
65 : : *
66 : : * @param cmd The command structure to free.
67 : : */
68 : : void
69 : 8 : command_destroy(struct command *cmd)
70 : : {
71 : 8 : cmd->filename = NULL;
72 : 8 : cmd->name = NULL;
73 : 8 : cmd->argc = 0;
74 : 8 : cmd->argv_size = 0;
75 : 8 : free(cmd->argv);
76 : 8 : cmd->argv = NULL;
77 : 8 : }
78 : :
79 : : static void
80 : 292 : command_grow_argv(struct command *cmd, int need)
81 : : {
82 : : /* We need a ghost byte for the NUL character. */
83 : 292 : need++;
84 : :
85 : : /* Check if we already have enough room. */
86 [ + + ]: 292 : if ((cmd->argv_size - cmd->argc) >= need)
87 : 255 : return;
88 : :
89 : 37 : cmd->argv_size = (cmd->argv_size + need) * 2;
90 : 37 : cmd->argv = m_realloc(cmd->argv, cmd->argv_size * sizeof(cmd->argv[0]));
91 : : }
92 : :
93 : : /**
94 : : * Append an argument to the command's argv.
95 : : *
96 : : * @param cmd The command structure to act on.
97 : : * @param arg The argument to append to argv.
98 : : */
99 : : void
100 : 171 : command_add_arg(struct command *cmd, const char *arg)
101 : : {
102 : 171 : command_grow_argv(cmd, 1);
103 : :
104 : 171 : cmd->argv[cmd->argc++] = arg;
105 : 171 : cmd->argv[cmd->argc] = NULL;
106 : 171 : }
107 : :
108 : : /**
109 : : * Append an argument array to the command's argv.
110 : : *
111 : : * @param cmd The command structure to act on.
112 : : * @param argv The NULL terminated argument array to append to argv.
113 : : */
114 : : void
115 : 1 : command_add_argl(struct command *cmd, const char **argv)
116 : : {
117 : 1 : int i, add_argc = 0;
118 : :
119 [ + + ]: 4 : while (argv[add_argc] != NULL)
120 : 3 : add_argc++;
121 : :
122 : 1 : command_grow_argv(cmd, add_argc);
123 : :
124 [ + + ]: 4 : for (i = 0; i < add_argc; i++)
125 : 3 : cmd->argv[cmd->argc++] = argv[i];
126 : :
127 : 1 : cmd->argv[cmd->argc] = NULL;
128 : 1 : }
129 : :
130 : : /**
131 : : * Append a va_list of argument to the command's argv.
132 : : *
133 : : * @param cmd The command structure to act on.
134 : : * @param args The NULL terminated va_list of argument array to append to argv.
135 : : */
136 : : void
137 : 120 : command_add_argv(struct command *cmd, va_list args)
138 : : {
139 : : va_list args_copy;
140 : 120 : int i, add_argc = 0;
141 : :
142 : 120 : va_copy(args_copy, args);
143 [ + + ]: 707 : while (va_arg(args_copy, const char *) != NULL)
144 : 587 : add_argc++;
145 : 120 : va_end(args_copy);
146 : :
147 : 120 : command_grow_argv(cmd, add_argc);
148 : :
149 [ + + ]: 707 : for (i = 0; i < add_argc; i++)
150 : 587 : cmd->argv[cmd->argc++] = va_arg(args, const char *);
151 : :
152 : 120 : cmd->argv[cmd->argc] = NULL;
153 : 120 : }
154 : :
155 : : /**
156 : : * Append a variable list of argument to the command's argv.
157 : : *
158 : : * @param cmd The command structure to act on.
159 : : * @param ... The NULL terminated variable list of argument to append to argv.
160 : : */
161 : : void
162 : 120 : command_add_args(struct command *cmd, ...)
163 : : {
164 : : va_list args;
165 : :
166 : 120 : va_start(args, cmd);
167 : 120 : command_add_argv(cmd, args);
168 : 120 : va_end(args);
169 : 120 : }
170 : :
171 : : /**
172 : : * Execute the command specified.
173 : : *
174 : : * The command is executed searching the PATH if the filename does not
175 : : * contain any slashes, or using the full path if it's either a relative or
176 : : * absolute pathname. This functions does not return.
177 : : *
178 : : * @param cmd The command structure to act on.
179 : : */
180 : : void
181 : 64 : command_exec(struct command *cmd)
182 : : {
183 : 64 : execvp(cmd->filename, (char * const *)cmd->argv);
184 : 64 : ohshite(_("unable to execute %s (%s)"), cmd->name, cmd->filename);
185 : : }
186 : :
187 : : /**
188 : : * Execute a shell with a possible command.
189 : : *
190 : : * @param cmd The command string to execute, if it's NULL an interactive
191 : : * shell will be executed instead.
192 : : * @param name The description of the command to execute.
193 : : */
194 : : void
195 : 6 : command_shell(const char *cmd, const char *name)
196 : : {
197 : : const char *shell;
198 : : const char *mode;
199 : :
200 [ - + ]: 6 : if (cmd == NULL) {
201 : 0 : mode = "-i";
202 : 0 : shell = getenv("SHELL");
203 : : } else {
204 : 6 : mode = "-c";
205 : 6 : shell = NULL;
206 : : }
207 : :
208 [ + - ]: 6 : if (str_is_unset(shell))
209 : 6 : shell = DPKG_DEFAULT_SHELL;
210 : :
211 : : #if HAVE_DPKG_SHELL_WITH_DASH_DASH
212 : 6 : execlp(shell, shell, mode, "--", cmd, NULL);
213 : : #else
214 : : execlp(shell, shell, mode, cmd, NULL);
215 : : #endif
216 : 6 : ohshite(_("unable to execute %s (%s)"), name, cmd);
217 : : }
218 : :
219 : : /**
220 : : * Check whether a command can be found in PATH.
221 : : *
222 : : * @param cmd The command name to check. This is a relative pathname.
223 : : *
224 : : * @return A boolean denoting whether the command has been found.
225 : : */
226 : : bool
227 : 24 : command_in_path(const char *cmd)
228 : : {
229 : 24 : struct varbuf filename = VARBUF_INIT;
230 : : const char *path_list;
231 : : const char *path, *path_end;
232 : :
233 [ - + ]: 24 : if (cmd[0] == '/')
234 : 0 : return file_is_exec(cmd);
235 : :
236 : 24 : path_list = getenv("PATH");
237 [ - + ]: 24 : if (!path_list)
238 : 0 : ohshit(_("PATH is not set"));
239 : :
240 [ + + + + ]: 48 : for (path = path_list; path; path = *path_end ? path_end + 1 : NULL) {
241 : : size_t path_len;
242 : :
243 : 31 : path_end = strchrnul(path, ':');
244 : 31 : path_len = (size_t)(path_end - path);
245 : :
246 : 31 : varbuf_set_buf(&filename, path, path_len);
247 [ + + ]: 31 : if (path_len)
248 : 27 : varbuf_add_char(&filename, '/');
249 : 31 : varbuf_add_str(&filename, cmd);
250 : :
251 [ + + ]: 31 : if (file_is_exec(filename.buf)) {
252 : 7 : varbuf_destroy(&filename);
253 : 7 : return true;
254 : : }
255 : : }
256 : :
257 : 17 : varbuf_destroy(&filename);
258 : 17 : return false;
259 : : }
|