1/* buildcmd.c -- build command lines from a list of arguments.
2   Copyright (C) 1990, 91, 92, 93, 94, 2000, 2003, 2005, 2006, 2007 Free Software Foundation, Inc.
3
4   This program is free software: you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation, either version 3 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13
14   You should have received a copy of the GNU General Public License
15   along with this program.  If not, see <http://www.gnu.org/licenses/>.
16*/
17
18#include <config.h>
19
20# ifndef PARAMS
21#  if defined PROTOTYPES || (defined __STDC__ && __STDC__)
22#   define PARAMS(Args) Args
23#  else
24#   define PARAMS(Args) ()
25#  endif
26# endif
27
28#if defined(HAVE_STRING_H) || defined(STDC_HEADERS)
29#include <string.h>
30#endif
31
32
33#if DO_MULTIBYTE
34# if HAVE_MBRLEN
35#  include <wchar.h>
36# else
37   /* Simulate mbrlen with mblen as best we can.  */
38#  define mbstate_t int
39#  define mbrlen(s, n, ps) mblen (s, n)
40# endif
41#endif
42
43#ifdef HAVE_LOCALE_H
44#include <locale.h>
45#endif
46#if ENABLE_NLS
47# include <libintl.h>
48# define _(Text) gettext (Text)
49#else
50# define _(Text) Text
51#define textdomain(Domain)
52#define bindtextdomain(Package, Directory)
53#endif
54#ifdef gettext_noop
55# define N_(String) gettext_noop (String)
56#else
57/* See locate.c for explanation as to why not use (String) */
58# define N_(String) String
59#endif
60
61#ifndef _POSIX_SOURCE
62#include <sys/param.h>
63#endif
64
65#ifdef HAVE_LIMITS_H
66#include <limits.h>
67#endif
68
69/* The presence of unistd.h is assumed by gnulib these days, so we
70 * might as well assume it too.
71 */
72/* for sysconf() */
73#include <unistd.h>
74
75#include <assert.h>
76
77/* COMPAT:  SYSV version defaults size (and has a max value of) to 470.
78   We try to make it as large as possible. */
79#if !defined(ARG_MAX) && defined(_SC_ARG_MAX)
80#define ARG_MAX sysconf (_SC_ARG_MAX)
81#endif
82#ifndef ARG_MAX
83#define ARG_MAX NCARGS
84#endif
85
86
87
88#include <xalloc.h>
89#include <error.h>
90
91#include "buildcmd.h"
92
93
94extern char **environ;
95
96
97static char *mbstrstr PARAMS ((const char *haystack, const char *needle));
98
99/* Replace all instances of `replace_pat' in ARG with `linebuf',
100   and add the resulting string to the list of arguments for the command
101   to execute.
102   ARGLEN is the length of ARG, not including the null.
103   LBLEN is the length of LINEBUF, not including the null.
104   PFXLEN is the length of PREFIX.  Substitution is not performed on
105   the prefix.   The prefix is used if the argument contains replace_pat.
106
107   COMPAT: insertions on the SYSV version are limited to 255 chars per line,
108   and a max of 5 occurrences of replace_pat in the initial-arguments.
109   Those restrictions do not exist here.  */
110
111void
112bc_do_insert (const struct buildcmd_control *ctl,
113              struct buildcmd_state *state,
114              char *arg, size_t arglen,
115              const char *prefix, size_t pfxlen,
116              const char *linebuf, size_t lblen,
117              int initial_args)
118{
119  /* Temporary copy of each arg with the replace pattern replaced by the
120     real arg.  */
121  static char *insertbuf;
122  char *p;
123  size_t bytes_left = ctl->arg_max - 1;    /* Bytes left on the command line.  */
124  int need_prefix;
125
126  /* XXX: on systems lacking an upper limit for exec args, ctl->arg_max
127   *      may have been set to LONG_MAX (see bc_get_arg_max()).  Hence
128   *      this xmalloc call may be a bad idea, especially since we are
129   *      adding 1 to it...
130   */
131  if (!insertbuf)
132    insertbuf = (char *) xmalloc (ctl->arg_max + 1);
133  p = insertbuf;
134
135  do
136    {
137      size_t len;               /* Length in ARG before `replace_pat'.  */
138      char *s = mbstrstr (arg, ctl->replace_pat);
139      if (s)
140        {
141          len = s - arg;
142        }
143      else
144        {
145          len = arglen;
146        }
147
148      if (bytes_left <= len)
149        break;
150      else
151	bytes_left -= len;
152
153      strncpy (p, arg, len);
154      p += len;
155      arg += len;
156      arglen -= len;
157
158      if (s)
159        {
160	  if (bytes_left <= (lblen + pfxlen))
161	    break;
162	  else
163	    bytes_left -= (lblen + pfxlen);
164
165	  if (prefix)
166	    {
167	      strcpy (p, prefix);
168	      p += pfxlen;
169	    }
170          strcpy (p, linebuf);
171          p += lblen;
172
173          arg += ctl->rplen;
174          arglen -= ctl->rplen;
175        }
176    }
177  while (*arg);
178  if (*arg)
179    error (1, 0, _("command too long"));
180  *p++ = '\0';
181
182  bc_push_arg (ctl, state,
183               insertbuf, p - insertbuf,
184               NULL, 0,
185               initial_args);
186}
187
188static
189void do_exec(const struct buildcmd_control *ctl,
190             struct buildcmd_state *state)
191{
192  (ctl->exec_callback)(ctl, state);
193}
194
195
196/* Return nonzero if there would not be enough room for an additional
197 * argument.  We check the total number of arguments only, not the space
198 * occupied by those arguments.
199 *
200 * If we return zero, there still may not be enough room for the next
201 * argument, depending on its length.
202 */
203static int
204bc_argc_limit_reached(int initial_args,
205		      const struct buildcmd_control *ctl,
206		      struct buildcmd_state *state)
207{
208  /* Check to see if we about to exceed a limit set by xargs' -n option */
209  if (!initial_args && ctl->args_per_exec &&
210      ( (state->cmd_argc - ctl->initial_argc) == ctl->args_per_exec))
211    return 1;
212
213  /* We deliberately use an equality test here rather than >= in order
214   * to force a software failure if the code is modified in such a way
215   * that it fails to call this function for every new argument.
216   */
217  return state->cmd_argc == ctl->max_arg_count;
218}
219
220
221/* Add ARG to the end of the list of arguments `cmd_argv' to pass
222   to the command.
223   LEN is the length of ARG, including the terminating null.
224   If this brings the list up to its maximum size, execute the command.  */
225
226void
227bc_push_arg (const struct buildcmd_control *ctl,
228             struct buildcmd_state *state,
229             const char *arg, size_t len,
230             const char *prefix, size_t pfxlen,
231             int initial_args)
232{
233  if (!initial_args)
234    state->todo = 1;
235
236  if (arg)
237    {
238      if (state->cmd_argv_chars + len > ctl->arg_max)
239        {
240          if (initial_args || state->cmd_argc == ctl->initial_argc)
241            error (1, 0, _("can not fit single argument within argument list size limit"));
242          /* option -i (replace_pat) implies -x (exit_if_size_exceeded) */
243          if (ctl->replace_pat
244              || (ctl->exit_if_size_exceeded &&
245                  (ctl->lines_per_exec || ctl->args_per_exec)))
246            error (1, 0, _("argument list too long"));
247          do_exec (ctl, state);
248        }
249
250      if (bc_argc_limit_reached(initial_args, ctl, state))
251	do_exec (ctl, state);
252    }
253
254  if (state->cmd_argc >= state->cmd_argv_alloc)
255    {
256      if (!state->cmd_argv)
257        {
258          state->cmd_argv_alloc = 64;
259          state->cmd_argv = (char **) xmalloc (sizeof (char *) * state->cmd_argv_alloc);
260        }
261      else
262        {
263          state->cmd_argv_alloc *= 2;
264          state->cmd_argv = (char **) xrealloc (state->cmd_argv,
265                                         sizeof (char *) * state->cmd_argv_alloc);
266        }
267    }
268
269  if (!arg)
270    state->cmd_argv[state->cmd_argc++] = NULL;
271  else
272    {
273      state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars;
274      if (prefix)
275        {
276          strcpy (state->argbuf + state->cmd_argv_chars, prefix);
277          state->cmd_argv_chars += pfxlen;
278        }
279
280      strcpy (state->argbuf + state->cmd_argv_chars, arg);
281      state->cmd_argv_chars += len;
282
283      /* If we have now collected enough arguments,
284       * do the exec immediately.  This must be
285       * conditional on arg!=NULL, since do_exec()
286       * actually calls bc_push_arg(ctl, state, NULL, 0, false).
287       */
288      if (bc_argc_limit_reached(initial_args, ctl, state))
289	do_exec (ctl, state);
290    }
291
292  /* If this is an initial argument, set the high-water mark. */
293  if (initial_args)
294    {
295      state->cmd_initial_argv_chars = state->cmd_argv_chars;
296    }
297}
298
299
300/* Finds the first occurrence of the substring NEEDLE in the string
301   HAYSTACK.  Both strings can be multibyte strings.  */
302
303static char *
304mbstrstr (const char *haystack, const char *needle)
305{
306#if DO_MULTIBYTE
307  if (MB_CUR_MAX > 1)
308    {
309      size_t hlen = strlen (haystack);
310      size_t nlen = strlen (needle);
311      mbstate_t mbstate;
312      size_t step;
313
314      memset (&mbstate, 0, sizeof (mbstate_t));
315      while (hlen >= nlen)
316        {
317          if (memcmp (haystack, needle, nlen) == 0)
318            return (char *) haystack;
319          step = mbrlen (haystack, hlen, &mbstate);
320          if (step <= 0)
321            break;
322          haystack += step;
323          hlen -= step;
324        }
325      return NULL;
326    }
327#endif
328  return strstr (haystack, needle);
329}
330
331static size_t
332get_line_max(void)
333{
334  long val;
335#ifdef _SC_LINE_MAX
336  val = sysconf(_SC_LINE_MAX);
337#else
338  val = -1;
339#endif
340
341  if (val > 0)
342    return val;
343
344  /* either _SC_LINE_MAX was not available or
345   * there is no particular limit.
346   */
347#ifdef LINE_MAX
348  val = LINE_MAX;
349#endif
350
351  if (val > 0)
352    return val;
353
354  return 2048L;			/* a reasonable guess. */
355}
356
357
358size_t
359bc_get_arg_max(void)
360{
361  long val;
362
363  /* We may resort to using LONG_MAX, so check it fits. */
364  /* XXX: better to do a compile-time check */
365  assert( (~(size_t)0) >= LONG_MAX);
366
367#ifdef _SC_ARG_MAX
368  val = sysconf(_SC_ARG_MAX);
369#else
370  val = -1;
371#endif
372
373  if (val > 0)
374    return val;
375
376  /* either _SC_ARG_MAX was not available or
377   * there is no particular limit.
378   */
379#ifdef ARG_MAX
380  val = ARG_MAX;
381#endif
382
383  if (val > 0)
384    return val;
385
386  /* The value returned by this function bounds the
387   * value applied as the ceiling for the -s option.
388   * Hence it the system won't tell us what its limit
389   * is, we allow the user to specify more or less
390   * whatever value they like.
391   */
392  return LONG_MAX;
393}
394
395
396static int cb_exec_noop(const struct buildcmd_control *ctl,
397                         struct buildcmd_state *state)
398{
399  /* does nothing. */
400  (void) ctl;
401  (void) state;
402
403  return 0;
404}
405
406
407/* Return how much of ARG_MAX is used by the environment.  */
408size_t
409bc_size_of_environment (void)
410{
411  size_t len = 0u;
412  char **envp = environ;
413
414  while (*envp)
415    len += strlen (*envp++) + 1;
416
417  return len;
418}
419
420
421enum BC_INIT_STATUS
422bc_init_controlinfo(struct buildcmd_control *ctl)
423{
424  size_t size_of_environment = bc_size_of_environment();
425  size_t arg_max;
426
427  ctl->posix_arg_size_min = get_line_max();
428  arg_max = bc_get_arg_max();
429
430  /* POSIX.2 requires subtracting 2048.  */
431  assert(arg_max > 2048u);	/* XXX: this is an external condition, should not check it with assert. */
432  ctl->posix_arg_size_max = (arg_max - 2048);
433
434  ctl->exit_if_size_exceeded = 0;
435
436  /* Take the size of the environment into account.  */
437  if (size_of_environment > ctl->posix_arg_size_max)
438    {
439      return BC_INIT_ENV_TOO_BIG;
440    }
441  else
442    {
443      ctl->posix_arg_size_max - size_of_environment;
444    }
445
446  /* need to subtract 2 on the following line - for Linux/PPC */
447  ctl->max_arg_count = (ctl->posix_arg_size_max / sizeof(char*)) - 2u;
448  assert(ctl->max_arg_count > 0);
449  ctl->rplen = 0u;
450  ctl->replace_pat = NULL;
451  ctl->initial_argc = 0;
452  ctl->exec_callback = cb_exec_noop;
453  ctl->lines_per_exec = 0;
454  ctl->args_per_exec = 0;
455
456  /* Set the initial value of arg_max to the largest value we can
457   * tolerate.
458   */
459  ctl->arg_max = ctl->posix_arg_size_max;
460
461  return BC_INIT_OK;
462}
463
464void
465bc_use_sensible_arg_max(struct buildcmd_control *ctl)
466{
467  size_t env_size = bc_size_of_environment();
468  const size_t arg_size = (128u * 1024u) + env_size;
469
470  /* Check against the upper and lower limits. */
471  if (arg_size > ctl->posix_arg_size_max)
472    ctl->arg_max = ctl->posix_arg_size_max - env_size;
473  else if (arg_size < ctl->posix_arg_size_min)
474    ctl->arg_max = ctl->posix_arg_size_min;
475  else
476    ctl->arg_max = arg_size;
477}
478
479
480
481
482void
483bc_init_state(const struct buildcmd_control *ctl,
484              struct buildcmd_state *state,
485              void *context)
486{
487  state->cmd_argc = 0;
488  state->cmd_argv_chars = 0;
489  state->cmd_argv = NULL;
490  state->cmd_argv_alloc = 0;
491
492  /* XXX: the following memory allocation is inadvisable on systems
493   * with no ARG_MAX, because ctl->arg_max may actually be close to
494   * LONG_MAX.   Adding one to it is safe though because earlier we
495   * subtracted 2048.
496   */
497  assert(ctl->arg_max <= (LONG_MAX - 2048L));
498  state->argbuf = (char *) xmalloc (ctl->arg_max + 1u);
499
500  state->cmd_argv_chars = state->cmd_initial_argv_chars = 0;
501  state->todo = 0;
502  state->usercontext = context;
503}
504
505void
506bc_clear_args(const struct buildcmd_control *ctl,
507              struct buildcmd_state *state)
508{
509  state->cmd_argc = ctl->initial_argc;
510  state->cmd_argv_chars = state->cmd_initial_argv_chars;
511  state->todo = 0;
512}
513
514