Beispiel #1
0
struct xenviron*
xenviron_create(const char* const* copy_from)
{
    struct cleanup* cl = cleanup_allocate();
    struct xenviron* xe = calloc(1, sizeof (char*));
    if (xe == NULL)
        die_oom();
    cleanup_commit(cl, xenviron_cleanup, xe);

    if (copy_from == NULL) {
        xe->env = calloc(1, xenviron_allocsz(0));
        if (xe->env == NULL)
            die_oom();
    } else {
        size_t nr = 0;
        for (const char* const* pos = copy_from; *pos; ++pos)
            nr += 1;

        xe->env = calloc(1, xenviron_allocsz(nr));
        if (xe->env == NULL)
            die_oom();

        for (size_t i = 0; i < nr; ++i) {
            xe->env[i] = strdup(copy_from[i]);
            if (xe->env[i] == NULL)
                die_oom();
        }
    }

    return xe;
}
Beispiel #2
0
void
dbglock_init(void)
{
    if (dbglock_fd != -1)
        return;

    if (!dbg_enabled_p())
        return;

    const char envvar[] = "FB_ADB_DBGLOCK_NAME";
    /* No, we can't just inherit the file descriptor.  Without a
     * separate file open, taking the lock won't block.  */

    const char* fn = getenv(envvar);
    if (fn == NULL) {
        const char* pfx = DEFAULT_TEMP_DIR;
        char* tmpfname = xaprintf("%s/fb-adb-dbg-XXXXXX", pfx);
        struct cleanup* cl = cleanup_allocate();
        int tmpfd = mkostemp(tmpfname, O_CLOEXEC);
        if (tmpfd != -1) {
            setenv(envvar, tmpfname, 1);
            cleanup_commit(cl, cleanup_dbginit, tmpfname);
            dbglock_fd = tmpfd;
        }

        return;
    }

    dbglock_fd = open(fn, O_CLOEXEC | O_RDWR);
}
Beispiel #3
0
static struct property_vector*
property_vector_new(void)
{
    struct cleanup* cl = cleanup_allocate();
    struct property_vector* pv = xalloc(sizeof (*pv));
    pv->capacity = 16;
    pv->size = 0;
    pv->props = malloc(sizeof (pv->props[0]) * pv->capacity);
    cleanup_commit(cl, property_vector_cleanup, pv);
    return pv;
}
Beispiel #4
0
void
dbglock(void)
{
    int saved_errno = errno;
    if (!dbg_enabled_p())
        return;

    if (dbglock_fd == -1)
        return;

    if (dbglock_level++ == 0)
        flock(dbglock_fd, LOCK_EX);

    cleanup_commit(cleanup_allocate(), cleanup_dbglock, 0);
    errno = saved_errno;
}
Beispiel #5
0
void
dbglock(void)
{
    int saved_errno = errno;
    if (!dbg_enabled_p())
        return;

    if (dbglock_fd == -1)
        return;

    if (dbglock_level++ == 0) {
        WITH_IO_SIGNALS_ALLOWED();
        flock(dbglock_fd, LOCK_EX);
    }

    cleanup_commit(cleanup_allocate(), cleanup_dbglock, 0);
    errno = saved_errno;
}
Beispiel #6
0
struct fdrecorder*
fdrecorder_new(void)
{
    struct reslist* fdr_rl = reslist_create();
    WITH_CURRENT_RESLIST(fdr_rl);
    struct cleanup* fdr_cl = cleanup_allocate();
    struct fdrecorder* fdr = xcalloc(sizeof (*fdr));
    fdr->owner_rl = fdr_rl;
    fdr->pipe[0] = fdr->pipe[1] = -1;
    cleanup_commit(fdr_cl, fdrecorder_cleanup, fdr);
#if FDRECORDER_USE_PIPE
    if (pipe2(fdr->pipe, O_CLOEXEC) == -1)
        die_errno("pipe2");
#else
    xsocketpairnc(AF_UNIX, SOCK_STREAM, 0, fdr->pipe);
    xshutdown_if_not_broken(fdr->pipe[0], SHUT_WR);
    xshutdown_if_not_broken(fdr->pipe[1], SHUT_RD);
#endif
    fdr->sigio_cookie = sigio_register(fdrecorder_sigio_callback, fdr);
    xF_SETFL(fdr->pipe[0], xF_GETFL(fdr->pipe[0]) | O_ASYNC | O_NONBLOCK);
    if (fcntl(fdr->pipe[0], F_SETOWN, getpid()) == -1)
        die_errno("F_SETOWN(%d)", fdr->pipe[0]);
    return fdr;
}
Beispiel #7
0
static void
compile_dex_with_dexopt(const char* dex_file_name,
                        const char* odex_file_name)
{
    SCOPED_RESLIST(rl);

    int dex_file = xopen(dex_file_name, O_RDONLY, 0);
    const char* odex_temp_filename = xaprintf(
        "%s.tmp.%s",
        odex_file_name,
        gen_hex_random(ENOUGH_ENTROPY));
    cleanup_commit(cleanup_allocate(), cleanup_tmpfile, odex_temp_filename);
    int odex_temp_file = xopen(odex_temp_filename,
                               O_RDWR | O_CREAT | O_EXCL,
                               0644);

    allow_inherit(dex_file);
    allow_inherit(odex_temp_file);

    struct child_start_info csi = {
        .io[0] = CHILD_IO_DEV_NULL,
        .io[1] = CHILD_IO_PIPE,
        .io[2] = CHILD_IO_DUP_TO_STDOUT,
        .exename = "dexopt",
        .argv = ARGV(
            "dexopt",
            "--zip",
            xaprintf("%d", dex_file),
            xaprintf("%d", odex_temp_file),
            dex_file_name,
            "v=ao=fm=y"),
    };

    struct child* dexopt = child_start(&csi);
    struct growable_buffer output = slurp_fd_buf(dexopt->fd[1]->fd);
    int status = child_status_to_exit_code(child_wait(dexopt));
    if (status != 0)
        die(EINVAL,
            "dexopt failed: %s",
            massage_output_buf(output));

    xrename(odex_temp_filename, odex_file_name);
}

static void
compile_dex(const char* dex_file_name,
            const char* odex_file_name)
{
    if (api_level() < 21)
        compile_dex_with_dexopt(dex_file_name, odex_file_name);
}

int
rdex_main(const struct cmd_rdex_info* info)
{
    const char* dex_file_name = info->dexfile;
    struct stat dex_stat = xstat(dex_file_name);
    const char* odex_file_name = make_odex_name(dex_file_name);

    bool need_recompile = true;

    struct stat odex_stat;
    if (stat(odex_file_name, &odex_stat) == 0 &&
        dex_stat.st_mtime <= odex_stat.st_mtime)
    {
        need_recompile = false;
    }

    (void) need_recompile;
    (void) odex_file_name;
    (void) compile_dex;

    if (need_recompile)
        compile_dex(dex_file_name, odex_file_name);

    if (setenv("CLASSPATH", dex_file_name, 1) == -1)
        die_errno("setenv");

    if (info->classname[0] == '-')
        die(EINVAL, "class name cannot begin with '-'");

    execvp("app_process",
           (char* const*)
           ARGV_CONCAT(
               ARGV("app_process",
                    xdirname(dex_file_name),
                    info->classname),
               info->args ?: empty_argv));
    die_errno("execvp(\"app_process\", ...");
}
Beispiel #8
0
void
cleanup_commit_close_fd(struct cleanup* cl, int fd)
{
    cleanup_commit(cl, fd_cleanup, (void*) (intptr_t) (fd));
}
Beispiel #9
0
static void
xfd_op(struct xfd_op_ctx* ctx)
{
    bool old_die_on_quit = hack_die_on_quit;
    hack_die_on_quit = true;

    struct errinfo ei = {
        .want_msg = true,
    };

    if (catch_error(xfd_op_1, ctx, &ei)) {
        deferred_die(ei.err, "%s", ei.msg);
        errno = ei.err < 0 ? EIO : ei.err;
        ctx->result = -1;
    }

    hack_die_on_quit = old_die_on_quit;
}

// xfdopen_read and xfdopen_write are called from inside stdio
// machinery and must always return locally --- never longjmp!  If we
// die inside one of these functions, we "defer" the die and actually
// longjmp at the next safe opportunity.

static custom_stream_ssize_t
xfdopen_read(void* cookie, char* buf, custom_stream_size_t size)
{
    struct xfd_op_ctx ctx = {
        .op = XFD_OP_READ,
        .fd = xfdopen_fd(cookie),
        .buf = buf,
        .size = size
    };

    xfd_op(&ctx);
    return ctx.result;
}

static custom_stream_ssize_t
xfdopen_write(void* cookie, const char* buf, custom_stream_size_t size)
{
    struct xfd_op_ctx ctx = {
        .op = XFD_OP_WRITE,
        .fd = xfdopen_fd(cookie),
        .buf = (void*) buf,
        .size = size
    };

    xfd_op(&ctx);
    return ctx.result;
}

FILE*
xfdopen(int fd, const char* mode)
{
    struct cleanup* cl = cleanup_allocate();
    FILE* f = NULL;

#if defined(HAVE_FOPENCOOKIE)
    cookie_io_functions_t funcs = {
        .read = xfdopen_read,
        .write = xfdopen_write,
        .seek = NULL,
        .close = NULL,
    };

    f = fopencookie((void*) (intptr_t) fd, mode, funcs);
#elif defined(HAVE_FUNOPEN)
    f = funopen((void*) (intptr_t) fd,
                xfdopen_read,
                xfdopen_write,
                NULL,
                NULL);
#else
# error This platform has no custom stdio stream support
#endif
    if (f == NULL)
        die_errno("fdopen");
    cleanup_commit(cl, xfopen_cleanup, f);
    return f;
}

// Like xdup, but return a structure that allows the fd to be
// individually closed.
struct fdh*
fdh_dup(int fd)
{
    struct reslist* rl = reslist_create();
    WITH_CURRENT_RESLIST(rl);

    struct fdh* fdh = xalloc(sizeof (*fdh));
    fdh->rl = rl;
    fdh->fd = xdup(fd);
    return fdh;
}

void
fdh_destroy(struct fdh* fdh)
{
    reslist_destroy(fdh->rl);
}

int
xF_GETFL(int fd)
{
    int flags = fcntl(fd, F_GETFL);
    if (flags == -1)
        die_errno("fcntl(%d, F_GETFL)", fd);
    return flags;
}
Beispiel #10
0
static void
do_xfer_recv(const struct xfer_opts xfer_opts,
             const char* filename,
             const char* desired_basename,
             int from_peer)
{
    struct xfer_msg statm = recv_xfer_msg(from_peer);
    if (statm.type != XFER_MSG_STAT)
        die(ECOMM, "expected stat msg");

    struct cleanup* error_cl = cleanup_allocate();
    struct stat st;
    const char* parent_directory = NULL;
    const char* rename_to = NULL;
    const char* write_mode = NULL;
    int dest_fd;

    if (stat(filename, &st) == 0) {
        if (S_ISDIR(st.st_mode)) {
            if (desired_basename == NULL)
                die(EISDIR, "\"%s\" is a directory", filename);
            parent_directory = filename;
            filename = xaprintf("%s/%s",
                                parent_directory,
                                desired_basename);
        } else if (S_ISREG(st.st_mode)) {
            if (st.st_nlink > 1)
                write_mode = "inplace";
        } else {
            write_mode = "inplace";
        }
    }

    if (parent_directory == NULL)
        parent_directory = xdirname(filename);

    if (write_mode == NULL)
        write_mode = xfer_opts.write_mode;

    bool atomic;
    bool automatic_mode = false;
    if (write_mode == NULL) {
        automatic_mode = true;
        atomic = true;
    } else if (strcmp(write_mode, "atomic") == 0) {
        atomic = true;
    } else if (strcmp(write_mode, "inplace") == 0) {
        atomic = false;
    } else {
        die(EINVAL, "unknown write mode \"%s\"", write_mode);
    }

    bool regular_file = true;
    bool preallocated = false;
    bool chmod_explicit = false;
    mode_t chmod_explicit_modes = 0;

    if (xfer_opts.preserve) {
        chmod_explicit = true;
        chmod_explicit_modes = statm.u.stat.ugo_bits;
    }

    if (xfer_opts.mode) {
        char* endptr = NULL;
        errno = 0;
        unsigned long omode = strtoul(xfer_opts.mode, &endptr, 8);
        if (errno != 0 || *endptr != '\0' || (omode &~ 0777) != 0)
            die(EINVAL, "invalid mode bits: %s", xfer_opts.mode);
        chmod_explicit = true;
        chmod_explicit_modes = (mode_t) omode;
    }

    mode_t creat_mode = (chmod_explicit_modes ? 0200 : 0666);

    if (atomic) {
        rename_to = filename;
        filename =
            xaprintf("%s.fb-adb-%s",
                     filename,
                     gen_hex_random(ENOUGH_ENTROPY));
        dest_fd = try_xopen(
            filename,
            O_CREAT | O_WRONLY | O_EXCL,
            creat_mode);
        if (dest_fd == -1) {
            if (errno == EACCES && automatic_mode) {
                atomic = false;
                filename = rename_to;
                rename_to = NULL;
            } else {
                die_errno("open(\"%s\")", filename);
            }
        }
    }

    if (!atomic) {
        dest_fd = xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, creat_mode);
        if (!S_ISREG(xfstat(dest_fd).st_mode))
            regular_file = false;
    }

    if (regular_file)
        cleanup_commit(error_cl, unlink_cleanup, filename);

    if (regular_file && statm.u.stat.size > 0)
        preallocated = fallocate_if_supported(
            dest_fd,
            statm.u.stat.size);

    uint64_t total_written = copy_loop_posix_recv(from_peer, dest_fd);

    if (preallocated && total_written < statm.u.stat.size)
        xftruncate(dest_fd, total_written);

    if (xfer_opts.preserve) {
        struct timeval times[2] = {
            { statm.u.stat.atime, statm.u.stat.atime_ns / 1000 },
            { statm.u.stat.mtime, statm.u.stat.mtime_ns / 1000 },
        };
#ifdef HAVE_FUTIMES
        if (futimes(dest_fd, times) == -1)
            die_errno("futimes");
#else
        if (utimes(filename, times) == -1)
            die_errno("times");
#endif
    }

    if (chmod_explicit)
        if (fchmod(dest_fd, chmod_explicit_modes) == -1)
            die_errno("fchmod");

    if (xfer_opts.sync)
        xfsync(dest_fd);

    if (rename_to)
        xrename(filename, rename_to);

    if (xfer_opts.sync)
        xfsync(xopen(parent_directory, O_DIRECTORY|O_RDONLY, 0));

    cleanup_forget(error_cl);
}