blob: e46d87e56239dee5641b2c8450866dd0a5b62a29 [file]
/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*-
*
* This file is part of PRoot.
*
* Copyright (C) 2014 STMicroelectronics
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
#include <string.h> /* str*(3), */
#include <assert.h> /* assert(3), */
#include <stdio.h> /* printf(3), fflush(3), */
#include <unistd.h> /* write(2), */
#include "cli/cli.h"
#include "cli/note.h"
#include "extension/extension.h"
#include "path/binding.h"
#include "attribute.h"
/* These should be included last. */
#include "build.h"
#include "cli/proot.h"
static int handle_option_r(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
Binding *binding;
/* ``chroot $PATH`` is semantically equivalent to ``mount
* --bind $PATH /``. */
binding = new_binding(tracee, value, "/", true);
if (binding == NULL)
return -1;
return 0;
}
static int handle_option_b(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
char *host;
char *guest;
host = talloc_strdup(tracee->ctx, value);
if (host == NULL) {
note(tracee, ERROR, INTERNAL, "can't allocate memory");
return -1;
}
guest = strchr(host, ':');
if (guest != NULL) {
*guest = '\0';
guest++;
}
new_binding(tracee, host, guest, true);
return 0;
}
static int handle_option_q(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
const char *ptr;
size_t nb_args;
bool last;
size_t i;
nb_args = 0;
ptr = value;
while (1) {
nb_args++;
/* Keep consecutive non-space characters. */
while (*ptr != ' ' && *ptr != '\0')
ptr++;
/* End-of-string ? */
if (*ptr == '\0')
break;
/* Skip consecutive space separators. */
while (*ptr == ' ' && *ptr != '\0')
ptr++;
/* End-of-string ? */
if (*ptr == '\0')
break;
}
tracee->qemu = talloc_zero_array(tracee, char *, nb_args + 1);
if (tracee->qemu == NULL)
return -1;
talloc_set_name_const(tracee->qemu, "@qemu");
i = 0;
ptr = value;
do {
const void *start;
const void *end;
last = true;
/* Keep consecutive non-space characters. */
start = ptr;
while (*ptr != ' ' && *ptr != '\0')
ptr++;
end = ptr;
/* End-of-string ? */
if (*ptr == '\0')
goto next;
/* Remove consecutive space separators. */
while (*ptr == ' ' && *ptr != '\0')
ptr++;
/* End-of-string ? */
if (*ptr == '\0')
goto next;
last = false;
next:
tracee->qemu[i] = talloc_strndup(tracee->qemu, start, end - start);
if (tracee->qemu[i] == NULL)
return -1;
i++;
} while (!last);
assert(i == nb_args);
new_binding(tracee, "/", HOST_ROOTFS, true);
new_binding(tracee, "/dev/null", "/etc/ld.so.preload", false);
return 0;
}
static int handle_option_w(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
tracee->fs->cwd = talloc_strdup(tracee->fs, value);
if (tracee->fs->cwd == NULL)
return -1;
talloc_set_name_const(tracee->fs->cwd, "$cwd");
return 0;
}
static int handle_option_k(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
int status;
status = initialize_extension(tracee, kompat_callback, value);
if (status < 0)
note(tracee, WARNING, INTERNAL, "option \"-k %s\" discarded", value);
return 0;
}
static int handle_option_i(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
(void) initialize_extension(tracee, fake_id0_callback, value);
return 0;
}
static int handle_option_0(Tracee *tracee, const Cli *cli, const char *value UNUSED)
{
return handle_option_i(tracee, cli, "0:0");
}
static int handle_option_v(Tracee *tracee, const Cli *cli UNUSED, const char *value)
{
int status;
status = parse_integer_option(tracee, &tracee->verbose, value, "-v");
if (status < 0)
return status;
global_verbose_level = tracee->verbose;
return 0;
}
extern unsigned char WEAK _binary_licenses_start;
extern unsigned char WEAK _binary_licenses_end;
static int handle_option_V(Tracee *tracee UNUSED, const Cli *cli, const char *value UNUSED)
{
size_t size;
print_version(cli);
printf("\n%s\n", cli->colophon);
fflush(stdout);
size = &_binary_licenses_end - &_binary_licenses_start;
if (size > 0)
write(1, &_binary_licenses_start, size);
exit_failure = false;
return -1;
}
static int handle_option_h(Tracee *tracee, const Cli *cli, const char *value UNUSED)
{
print_usage(tracee, cli, true);
exit_failure = false;
return -1;
}
static void new_bindings(Tracee *tracee, const char *bindings[], const char *value)
{
int i;
for (i = 0; bindings[i] != NULL; i++) {
const char *path;
path = (strcmp(bindings[i], "*path*") != 0
? expand_front_variable(tracee->ctx, bindings[i])
: value);
new_binding(tracee, path, NULL, false);
}
}
static int handle_option_R(Tracee *tracee, const Cli *cli, const char *value)
{
int status;
status = handle_option_r(tracee, cli, value);
if (status < 0)
return status;
new_bindings(tracee, recommended_bindings, value);
return 0;
}
static int handle_option_S(Tracee *tracee, const Cli *cli, const char *value)
{
int status;
status = handle_option_0(tracee, cli, value);
if (status < 0)
return status;
status = handle_option_r(tracee, cli, value);
if (status < 0)
return status;
new_bindings(tracee, recommended_su_bindings, value);
return 0;
}
/**
* Initialize @tracee->qemu.
*/
static int post_initialize_exe(Tracee *tracee, const Cli *cli UNUSED,
size_t argc UNUSED, char *const argv[] UNUSED, size_t cursor UNUSED)
{
char path[PATH_MAX];
int status;
/* Nothing else to do ? */
if (tracee->qemu == NULL)
return 0;
/* Resolve the full guest path to tracee->qemu[0]. */
status = which(tracee->reconf.tracee, tracee->reconf.paths, path, tracee->qemu[0]);
if (status < 0)
return -1;
/* Actually tracee->qemu[0] has to be a host path from the tracee's
* point-of-view, not from the PRoot's point-of-view. See
* translate_execve() for details. */
if (tracee->reconf.tracee != NULL) {
status = detranslate_path(tracee->reconf.tracee, path, NULL);
if (status < 0)
return -1;
}
tracee->qemu[0] = talloc_strdup(tracee->qemu, path);
if (tracee->qemu[0] == NULL)
return -1;
return 0;
}
/**
* Initialize @tracee's fields that are mandatory for PRoot but that
* are not required on the command line, i.e. "-w" and "-r".
*/
static int pre_initialize_bindings(Tracee *tracee, const Cli *cli,
size_t argc UNUSED, char *const argv[] UNUSED, size_t cursor)
{
int status;
/* Default to "." if no CWD were specified. */
if (tracee->fs->cwd == NULL) {
status = handle_option_w(tracee, cli, ".");
if (status < 0)
return -1;
}
/* The default guest rootfs is "/" if none was specified. */
if (get_root(tracee) == NULL) {
status = handle_option_r(tracee, cli, "/");
if (status < 0)
return -1;
}
return cursor;
}
const Cli *get_proot_cli(TALLOC_CTX *context UNUSED)
{
global_tool_name = proot_cli.name;
return &proot_cli;
}