dependencies: Fix parsing of shebangs with spaces

While finding an external program, we should only split the shebang
once since that is what Linux and BSD also do. This is also why
everyone uses #!/usr/bin/env in their shebangs since that allows
you to run an interpreter in a path with spaces in it.

See `man execve` for more details, specifically the sections for
interpreter scripts.
pull/2708/head
Nirbheek Chauhan 7 years ago
parent 120f7a4c40
commit abcace7ee1
  1. 6
      mesonbuild/dependencies/base.py
  2. 1
      test cases/common/167 external program shebang parsing/input.txt
  3. 79
      test cases/common/167 external program shebang parsing/main.c
  4. 21
      test cases/common/167 external program shebang parsing/meson.build
  5. 2
      test cases/common/167 external program shebang parsing/script.int.in

@ -560,7 +560,11 @@ class ExternalProgram:
with open(script) as f:
first_line = f.readline().strip()
if first_line.startswith('#!'):
commands = first_line[2:].split('#')[0].strip().split()
# In a shebang, everything before the first space is assumed to
# be the command to run and everything after the first space is
# the single argument to pass to that command. So we must split
# exactly once.
commands = first_line[2:].split('#')[0].strip().split(maxsplit=1)
if mesonlib.is_windows():
# Windows does not have UNIX paths so remove them,
# but don't remove Windows paths

@ -0,0 +1,79 @@
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef _WIN32
#include <io.h>
#include <windows.h>
#else
#include <unistd.h>
#endif
static int
intrp_copyfile (char * src, char * dest)
{
#ifdef _WIN32
if (!CopyFile (src, dest, FALSE))
return 1;
return 0;
#else
return execlp ("cp", "copyfile", src, dest, NULL);
#endif
}
static char*
parser_get_line (FILE * f)
{
ssize_t size;
size_t n = 0;
char *line = NULL;
size = getline (&line, &n, f);
if (size < 0) {
fprintf (stderr, "%s\n", strerror (errno));
free (line);
return NULL;
}
return line;
}
int
main (int argc, char * argv[])
{
FILE *f;
char *line = NULL;
if (argc != 4) {
fprintf (stderr, "Invalid number of arguments: %i\n", argc);
goto err;
}
if ((f = fopen (argv[1], "r")) == NULL) {
fprintf (stderr, "%s\n", strerror (errno));
goto err;
}
line = parser_get_line (f);
if (!line || line[0] != '#' || line[1] != '!') {
fprintf (stderr, "Invalid script\n");
goto err;
}
free (line);
line = parser_get_line (f);
if (!line || strncmp (line, "copy", 4) != 0) {
fprintf (stderr, "Syntax error\n");
goto err;
}
return intrp_copyfile (argv[2], argv[3]);
err:
free (line);
return 1;
}

@ -0,0 +1,21 @@
project('shebang parsing', 'c')
interpreter = executable('aninterp', 'main.c', native : true)
cdata = configuration_data()
cdata.set('INTRP', interpreter.full_path())
f = configure_file(input : 'script.int.in',
output : 'script.int',
configuration : cdata)
# Test that parsing a shebang with spaces works properly. See `man execve`,
# specifically the section on "Interpreter scripts" and the one under "NOTES".
script = find_program(f)
custom_target('interpthis',
input : 'input.txt',
output : 'output.txt',
depends : interpreter,
command : [script, '@INPUT@', '@OUTPUT@'],
build_by_default : true)
Loading…
Cancel
Save