Esempio n. 1
0
File: io.c Progetto: aosm/distcc
int dcc_select_for_write(int fd, int timeout)
{
    fd_set fds;
    int rs;

    struct timeval tv;

    tv.tv_sec = timeout;
    tv.tv_usec = 0;

    while (1) {
        FD_ZERO(&fds);
        FD_SET(fd, &fds);
        rs_trace("select for write on fd%d", fd);
        
        rs = select(fd + 1, NULL, &fds, &fds, &tv);

        if (rs == -1 && errno == EINTR) {
            rs_trace("select was interrupted");
            continue;
        } else if (rs == -1) {
            rs_log_error("select failed: %s", strerror(errno));
            return EXIT_IO_ERROR;
        } else {
            return 0;
        }
    }
}
Esempio n. 2
0
File: exec.c Progetto: katakk/distcc
/**
 * Run @p argv in a child asynchronously.
 *
 * stdin, stdout and stderr are redirected as shown, unless those
 * filenames are NULL.  In that case they are left alone.
 *
 * @warning When called on the daemon, where stdin/stdout may refer to random
 * network sockets, all of the standard file descriptors must be redirected!
 **/
int dcc_spawn_child(char **argv, pid_t *pidptr,
                    const char *stdin_file,
                    const char *stdout_file,
                    const char *stderr_file)
{
    pid_t pid;

    dcc_trace_argv("forking to execute", argv);

    pid = fork();
    if (pid == -1) {
        rs_log_error("failed to fork: %s", strerror(errno));
        return EXIT_OUT_OF_MEMORY; /* probably */
    } else if (pid == 0) {
        /* If this is a remote compile,
         * put the child in a new group, so we can
         * kill it and all its descendents without killing distccd
         * FIXME: if you kill distccd while it's compiling, and
         * the compiler has an infinite loop bug, the new group
         * will run forever until you kill it.
         */
        if (stdout_file != NULL) {
            if (dcc_new_pgrp() != 0)
                rs_trace("Unable to start a new group\n");
        }
        dcc_inside_child(argv, stdin_file, stdout_file, stderr_file);
        /* !! NEVER RETURN FROM HERE !! */
    } else {
        *pidptr = pid;
        rs_trace("child started as pid%d", (int) pid);
        return 0;
    }
}
Esempio n. 3
0
/** Read from scoop without advancing.
 *
 * Ask for LEN bytes of input from the stream. If that much data is available,
 * then return a pointer to it in PTR, advance the stream input pointer over
 * the data, and return RS_DONE. If there's not enough data, then accept
 * whatever is there into a buffer, advance over it, and return RS_BLOCKED.
 *
 * The data is not actually removed from the input, so this function lets you
 * do readahead. If you want to keep any of the data, you should also call
 * rs_scoop_advance() to skip over it. */
rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr)
{
    rs_buffers_t *stream = job->stream;
    rs_job_check(job);

    if (!job->scoop_avail && stream->avail_in >= len) {
        /* The scoop is empty and there's enough data in the input. */
        *ptr = stream->next_in;
        rs_trace("got " FMT_SIZE " bytes direct from input", len);
        return RS_DONE;
    } else if (job->scoop_avail < len && stream->avail_in) {
        /* There is not enough data in the scoop. */
        rs_trace("scoop has less than " FMT_SIZE " bytes, scooping from "
                 FMT_SIZE " input bytes", len, stream->avail_in);
        rs_scoop_input(job, len);
    }
    if (job->scoop_avail >= len) {
        /* There is enough data in the scoop now. */
        rs_trace("scoop has at least " FMT_SIZE " bytes, this is enough",
                 job->scoop_avail);
        *ptr = job->scoop_next;
        return RS_DONE;
    } else if (stream->eof_in) {
        /* Not enough input data and at EOF. */
        rs_trace("reached end of input stream");
        return RS_INPUT_ENDED;
    } else {
        /* Not enough input data yet. */
        rs_trace("blocked with insufficient input data");
        return RS_BLOCKED;
    }
}
Esempio n. 4
0
/**
 * \brief Copy up to \p max_len bytes from input of \b stream to its output.
 *
 * Return the number of bytes actually copied, which may be less than
 * LEN if there is not enough space in one or the other stream.
 *
 * This always does the copy immediately.  Most functions should call
 * rs_tube_copy() to cause the copy to happen gradually as space
 * becomes available.
 */
int rs_buffers_copy(rs_buffers_t *stream, int max_len)
{
    int len = max_len;

    assert(len > 0);

    if ((unsigned) len > stream->avail_in) {
        rs_trace("copy limited to "FMT_SIZE" available input bytes", stream->avail_in);
        len = stream->avail_in;
    }


    if ((unsigned) len > stream->avail_out) {
        rs_trace("copy limited to "FMT_SIZE" available output bytes", stream->avail_out);
        len = stream->avail_out;
    }

    if (!len)
        return 0;
/*     rs_trace("stream copied chunk of %d bytes", len); */

    memcpy(stream->next_out, stream->next_in, len);

    stream->next_out += len;
    stream->avail_out -= len;

    stream->next_in += len;
    stream->avail_in -= len;

    return len;
}
Esempio n. 5
0
/*
 * State of reading a block and trying to generate its sum.
 */
static rs_result
rs_sig_s_generate(rs_job_t *job)
{
    rs_result           result;
    size_t              len;
    void                *block;
        
    /* must get a whole block, otherwise try again */
    len = job->block_len;
    result = rs_scoop_read(job, len, &block);
        
    /* unless we're near eof, in which case we'll accept
     * whatever's in there */
    if ((result == RS_BLOCKED && rs_job_input_is_ending(job))) {
        result = rs_scoop_read_rest(job, &len, &block);
    } else if (result == RS_INPUT_ENDED) {
        return RS_DONE;
    } else if (result != RS_DONE) {
        rs_trace("generate stopped: %s", rs_strerror(result));
        return result;
    }

    rs_trace("got %ld byte block", (long) len);

    return rs_sig_do_block(job, block, len);
}
Esempio n. 6
0
/*
 * Update the ELF file residing at @p path, replacing all occurrences
 * of @p search with @p replace in the section named @p desired_section_name.
 * The replacement string must be the same length or shorter than
 * the search string.
 */
static void update_section(const char *path,
                           const void *base,
                           off_t size,
                           const char *desired_section_name,
                           const char *search,
                           const char *replace) {
  const void *desired_section = NULL;
  int desired_section_size = 0;

  if (FindElfSection(base, size, desired_section_name,
                     &desired_section, &desired_section_size)
      && desired_section_size > 0) {
    /* The local variable below works around a bug in some versions
     * of gcc (4.2.1?), which issues an erroneous warning if
     * 'desired_section_rw' is replaced with '(void *) desired_section'
     * in the call below, causing compile errors with -Werror.
     */
    void *desired_section_rw = (void *) desired_section;
    int count = replace_string(desired_section_rw, desired_section_size,
                               search, replace);
    if (count == 0) {
      rs_trace("\"%s\" section of file %s has no occurrences of \"%s\"",
               desired_section_name, path, search);
    } else {
      rs_log_info("updated \"%s\" section of file \"%s\": "
                  "replaced %d occurrences of \"%s\" with \"%s\"",
                  desired_section_name, path, count, search, replace);
      if (count > 1) {
        rs_log_warning("only expected to replace one occurrence!");
      }
    }
  } else {
    rs_trace("file %s has no \"%s\" section", path, desired_section_name);
  }
}
Esempio n. 7
0
/**
 * Change object file or suffix of -o to @p ofname
 * Frees the old value, if it exists.
 *
 * It's crucially important that in every case where an output file is
 * detected by dcc_scan_args(), it's also correctly identified here.
 * It might be better to make the code shared.
 **/
int dcc_set_output(char **a, char *ofname)
{
    int i;

    for (i = 0; a[i]; i++)
        if (0 == strcmp(a[i], "-o") && a[i+1] != NULL) {
            rs_trace("changed output from \"%s\" to \"%s\"", a[i+1], ofname);
            free(a[i+1]);
            a[i+1] = strdup(ofname);
            if (a[i+1] == NULL) {
                rs_log_crit("failed to allocate space for output parameter");
                return EXIT_OUT_OF_MEMORY;
            }
            dcc_trace_argv("command after", a);
            return 0;
        } else if (0 == strncmp(a[i], "-o", 2)) {
            char *newptr;
            rs_trace("changed output from \"%s\" to \"%s\"", a[i]+2, ofname);
            free(a[i]);
            if (asprintf(&newptr, "-o%s", ofname) == -1) {
                rs_log_crit("failed to allocate space for output parameter");
                return EXIT_OUT_OF_MEMORY;
            }
            a[i] = newptr;
            dcc_trace_argv("command after", a);
            return 0;
        }

    rs_log_error("failed to find \"-o\"");
    return EXIT_DISTCC_FAILED;
}
Esempio n. 8
0
/**
 * Search through the $PATH looking for a directory containing a file called
 * @p compiler_name, which is a symbolic link containing the string "distcc".
 *
 * Trim the path to just after the *last* such directory.
 *
 * If we find a distcc masquerade dir on the PATH, remove all the dirs up
 * to that point.
 **/
int dcc_trim_path(const char *compiler_name)
{
    const char *envpath, *newpath, *p, *n;
    char linkbuf[MAXPATHLEN], *buf;
    struct stat sb;
    size_t len;

    if (!(envpath = getenv("PATH"))) {
        rs_trace("PATH seems not to be defined");
        return 0;
    }

    rs_trace("original PATH %s", envpath);
    rs_trace("looking for \"%s\"", compiler_name);

    /* Allocate a buffer that will let us append "/cc" onto any PATH
     * element, even if there is only one item in the PATH. */
    if (!(buf = malloc(strlen(envpath)+1+strlen(compiler_name)+1))) {
        rs_log_error("failed to allocate buffer for PATH munging");
        return EXIT_OUT_OF_MEMORY;
    }

    for (n = p = envpath, newpath = NULL; *n; p = n) {
        n = strchr(p, ':');
        if (n)
            len = n++ - p;
        else {
            len = strlen(p);
            n = p + len;
        }
        strncpy(buf, p, len);

        sprintf(buf + len, "/%s", compiler_name);
        if (lstat(buf, &sb) == -1)
            continue;           /* ENOENT, EACCESS, etc */
        if (!S_ISLNK(sb.st_mode))
            break;
        if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0)
            continue;
        linkbuf[len] = '\0';
        if (strstr(linkbuf, "distcc")) {
            /* Set newpath to the part of the PATH past our match. */
            newpath = n;
        }
    }

    if (newpath) {
        int ret = dcc_set_path(newpath);
        if (ret)
            return ret;
    } else
        rs_trace("not modifying PATH");

    free(buf);
    return 0;
}
Esempio n. 9
0
/*
 * If the stream has no more data available, read some from F into
 * BUF, and let the stream use that.  On return, SEEN_EOF is true if
 * the end of file has passed into the stream.
 */
rs_result rs_infilebuf_fill(rs_job_t *job, rs_buffers_t *buf,
                            void *opaque)
{
    int                     len;
    rs_filebuf_t            *fb = (rs_filebuf_t *) opaque;
    FILE                    *f = fb->f;
        
    /* This is only allowed if either the buf has no input buffer
     * yet, or that buffer could possibly be BUF. */
    if (buf->next_in != NULL) {
        assert(buf->avail_in <= fb->buf_len);
        assert(buf->next_in >= fb->buf);
        assert(buf->next_in <= fb->buf + fb->buf_len);
    } else {
        assert(buf->avail_in == 0);
    }

    if (buf->eof_in || (buf->eof_in = feof(f))) {
        rs_trace("seen end of file on input");
        buf->eof_in = 1;
        return RS_DONE;
    }

    if (buf->avail_in)
        /* Still some data remaining.  Perhaps we should read
           anyhow? */
        return RS_DONE;
        
    len = fread(fb->buf, 1, fb->buf_len, f);
    if (len <= 0) {
        /* This will happen if file size is a multiple of input block len
         */
        if (feof(f)) {
            rs_trace("seen end of file on input");
            buf->eof_in = 1;
            return RS_DONE;
        }
        if (ferror(f)) {
            rs_error("error filling buf from file: %s",
                     strerror(errno));
            return RS_IO_ERROR;
        } else {
            rs_error("no error bit, but got %d return when trying to read",
                     len);
            return RS_IO_ERROR;
        }
    }
    buf->avail_in = len;
    buf->next_in = fb->buf;

    return RS_DONE;
}
Esempio n. 10
0
File: serve.c Progetto: aosm/distcc
/**
 * Find the absolute path for the first occurrence of @p compiler_name on the
 * PATH.  Print a warning if it looks like a symlink to distcc.
 *
 * We want to guard against somebody accidentally running the server with a
 * masqueraded compiler on its $PATH.  The worst that's likely to happen here
 * is wasting some time running a distcc or ccache client that does nothing,
 * so it's not a big deal.  (This could be easy to do if it's on the default
 * PATH and they start the daemon from the command line.)
 *
 * At the moment we don't look for the compiler too.
 **/
static int dcc_check_compiler_masq(char *compiler_name)
{
    const char *envpath, *p, *n;
    char *buf = NULL;
    struct stat sb;
    int len;
    char linkbuf[MAXPATHLEN];

    if (compiler_name[0] == '/') 
        return 0;
    
    if (!(envpath = getenv("PATH"))) {
        rs_trace("PATH seems not to be defined");
        return 0;
    }

    for (n = p = envpath; *n; p = n) {
        n = strchr(p, ':');
        if (n)
            len = n++ - p;
        else {
            len = strlen(p);
            n = p + len;
        }
        if (asprintf(&buf, "%.*s/%s", len, p, compiler_name) == -1) {
            rs_log_crit("asnprintf failed");
            return EXIT_DISTCC_FAILED;
        }

        if (lstat(buf, &sb) == -1)
            continue;           /* ENOENT, EACCESS, etc */
        if (!S_ISLNK(sb.st_mode)) {
            rs_trace("%s is not a symlink", buf);
            break;              /* found it */
        }
        if ((len = readlink(buf, linkbuf, sizeof linkbuf)) <= 0)
            continue;
        linkbuf[len] = '\0';
        
        if (strstr(linkbuf, "distcc")) {
            rs_log_warning("%s on distccd's path is %s and really a link to %s",
                           compiler_name, buf, linkbuf);
            break;              /* but use it anyhow */
        } else {
            rs_trace("%s is a safe symlink to %s", buf, linkbuf);
            break;              /* found it */
        }
    }

    free(buf);
    return 0;
}
Esempio n. 11
0
/*
 * Transmit the body of a file using sendfile().
 *
 * Linux at the moment requires the input be page-based -- ie a disk file, and
 * only on particular filesystems.  If the sendfile() call fails in a way that
 * makes us think that regular IO might work, then we try that instead.  For
 * example, the /tmp filesystem may not support sendfile().
 */
int
dcc_pump_sendfile(int ofd, int ifd, size_t size)
{
    ssize_t sent;
    off_t offset = 0;
    int ret;

    while (size) {
        /* Handle possibility of partial transmission, e.g. if
         * sendfile() is interrupted by a signal.  size is decremented
         * as we go. */

        sent = sys_sendfile(ofd, ifd, &offset, size);
        if (sent == -1) {
            if ((errno == ENOSYS || errno == EINVAL) && offset == 0) {
                /* The offset==0 tests is because we may be part way through
                 * the file.  We can't just naively go back to read/write
                 * because sendfile() does not update the file pointer: we
                 * would need to lseek() first.  That case is not handled at
                 * the moment because it's unlikely that sendfile() would
                 * suddenly be unsupported while we're using it.  A failure
                 * halfway through probably indicates a genuine error.*/

                rs_log_info("decided to use read/write rather than sendfile");
                return dcc_pump_readwrite(ofd, ifd, size);
            } else if (errno == EAGAIN) {
                /* Sleep until we're able to write out more data. */
                if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0)
                    return ret;
                rs_trace("select() returned, continuing to write");
            } else if (errno == EINTR) {
                rs_trace("sendfile() interrupted, continuing");
            } else {
                rs_log_error("sendfile failed: %s", strerror(errno));
                return EXIT_IO_ERROR;
            }
        } else if (sent == 0) {
            rs_log_error("sendfile returned 0? can't cope");
            return EXIT_IO_ERROR;
        } else if (sent != (ssize_t) size) {
            /* offset is automatically updated by sendfile. */
            size -= sent;
            rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld",
                          (long) sent, (long) size, (long) offset);
        } else {
            /* normal case, everything was sent. */
            break;
        }
    }
    return 0;
}
Esempio n. 12
0
/**
 * Read in @p filename from inside @p dirname, and try to parse it as
 * a status file.
 *
 * If a new entry is read, a pointer to it is returned in @p lp.
 **/
static int dcc_mon_do_file(char *dirname, char *filename,
                           struct dcc_task_state **lp)
{
    int fd;
    char *fullpath;
    int ret;

    *lp = NULL;

    /* Is this a file we want to see */
    if (!str_startswith(dcc_state_prefix, filename)) {
/*         rs_trace("skipped"); */
        return 0;
    }

    checked_asprintf(&fullpath, "%s/%s", dirname, filename);
    if (fullpath == NULL) {
      return EXIT_OUT_OF_MEMORY;
    }
    rs_trace("process %s", fullpath);

    /* Remember that the file might disappear at any time, so open it
     * now so that we can hang on. */
    if ((fd = open(fullpath, O_RDONLY|O_BINARY, 0)) == -1) {
        if (errno == ENOENT) {
            rs_trace("%s disappeared", fullpath);
            ret = 0;
            goto out_free;
        } else { /* hm */
            rs_log_warning("failed to open %s: %s",
                           fullpath, strerror(errno));
            ret = EXIT_IO_ERROR;
            goto out_free;
        }
    }

    if ((ret = dcc_mon_kill_old(fd, fullpath))) {
        /* closes fd on failure */
        goto out_free;
    }

    ret = dcc_mon_load_state(fd, fullpath, lp);

    dcc_close(fd);

    out_free:
    free(fullpath);
    return ret;           /* ok */
}
Esempio n. 13
0
/**
 * Called when we're executing a COPY command and waiting for all the
 * data to be retrieved from the callback.
 */
static rs_result rs_patch_s_copying(rs_job_t *job)
{
    rs_result       result;
    size_t          desired_len, len;
    void            *ptr;
    rs_buffers_t    *buffs = job->stream;

    /* copy only as much as will fit in the output buffer, so that we
     * don't have to block or store the input. */
    desired_len = len = (buffs->avail_out < job->basis_len) ? buffs->avail_out : job->basis_len;

    if (!len)
        return RS_BLOCKED;

    rs_trace("copy " PRINTF_FORMAT_U64 " bytes from basis at offset " PRINTF_FORMAT_U64 "",
             PRINTF_CAST_U64(len), PRINTF_CAST_U64(job->basis_pos));

    ptr = buffs->next_out;

    result = (job->copy_cb)(job->copy_arg, job->basis_pos, &len, &ptr);
    if (result != RS_DONE)
        return result;
    else
        rs_trace("copy callback returned %s", rs_strerror(result));

    rs_trace("got " PRINTF_FORMAT_U64 " bytes back from basis callback", PRINTF_CAST_U64(len));

    if (len > desired_len) {
        rs_trace("warning: copy_cb returned more than the requested length.");
        len = desired_len;
    }

    /* copy back to out buffer only if the callback has used its own buffer */
    if (ptr != buffs->next_out)
        memcpy(buffs->next_out, ptr, len);

    buffs->next_out += len;
    buffs->avail_out -= len;

    job->basis_pos += len;
    job->basis_len -= len;

    if (!job->basis_len) {
        /* Done! */
        job->statefn = rs_patch_s_cmdbyte;
    }

    return RS_RUNNING;
}
Esempio n. 14
0
int dcc_recursion_safeguard(void)
{
    char *env = getenv(dcc_safeguard_name);

    if (env) {
	rs_trace("safeguard: %s", env);
	if (!(dcc_safeguard_level = atoi(env)))
	    dcc_safeguard_level = 1;
    }
    else
	dcc_safeguard_level = 0;
    rs_trace("safeguard level=%d", dcc_safeguard_level);

    return dcc_safeguard_level;
}
Esempio n. 15
0
File: clinet.c Progetto: aosm/distcc
/**
 * Open a socket to a tcp remote host with the specified port.
 **/
int dcc_connect_by_name(const char *host, int port, int *p_fd)
{
    struct addrinfo hints;
    struct addrinfo *res;
    int error;
    int ret;
    char portname[20];

    rs_trace("connecting to %s port %d", host, port);
    
    /* Unfortunately for us, getaddrinfo wants the port (service) as a string */
    snprintf(portname, sizeof portname, "%d", port);

    memset(&hints, 0, sizeof(hints));
    /* set-up hints structure */
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    error = getaddrinfo(host, portname, &hints, &res);
    if (error) {
        rs_log_error("failed to resolve host %s port %d: %s", host, port,
                     gai_strerror(error));
        return EXIT_CONNECT_FAILED;
    }

    /* Try each of the hosts possible addresses. */
    do {
        ret = dcc_connect_by_addr(res->ai_addr, res->ai_addrlen, p_fd);
    } while (ret != 0 && (res = res->ai_next));

    return ret;
}
Esempio n. 16
0
/**
 * Read the "DONE" token from the network that introduces a response.
 **/
int dcc_r_result_header(int ifd,
                        enum dcc_protover expect_ver)
{
    unsigned vers;
    int ret;

    if ((ret = dcc_r_token_int(ifd, "DONE", &vers)))
        rs_log_error("server provided no answer. "
                     "Is the server configured to allow access from your IP"
                     " address? Is the server performing authentication and"
                     " your client isn't? Does the server have the compiler"
                     " installed? Is the server configured to access the"
                     " compiler?");
        return ret;

    if (vers != expect_ver) {
        rs_log_error("got version %d not %d in response from server",
                     vers, expect_ver);
        return EXIT_PROTOCOL_ERROR;
    }

    rs_trace("got response header");

    return 0;
}
Esempio n. 17
0
File: rpc.c Progetto: aosm/distcc
/**
 * Transmit token name (4 characters) and value (32-bit int, as 8 hex
 * characters).
 **/
int dcc_x_token_int(int ofd, const char *token, unsigned param)
{
    char buf[13];
    int shift;
    char *p;
    const char *hex = "0123456789abcdef";

    if (strlen(token) != 4) {
        rs_log_crit("token \"%s\" seems wrong", token);
        return EXIT_PROTOCOL_ERROR;
    }
    memcpy(buf, token, 4);

    /* Quick and dirty int->hex.  The only standard way is to call snprintf
     * (?), which is undesirably slow for such a frequently-called
     * function. */
    for (shift=28, p = &buf[4];
         shift >= 0;
         shift -= 4, p++) {
        *p = hex[(param >> shift) & 0xf];
    }
    buf[12] = '\0';

    rs_trace("send %s", buf);
    return dcc_writex(ofd, buf, 12);
}
Esempio n. 18
0
/* Write a LITERAL command. */
void
rs_emit_literal_cmd(rs_job_t *job, int len)
{
    int cmd;
    int param_len;

    switch (param_len = rs_int_len(len)) {
    case 1:
        cmd = RS_OP_LITERAL_N1;
        break;
    case 2:
        cmd = RS_OP_LITERAL_N2;
        break;
    case 4:
        cmd = RS_OP_LITERAL_N4;
        break;
    default:
        rs_fatal("What?");
    }

    rs_trace("emit LITERAL_N%d(len=%d), cmd_byte=%#x", param_len, len, cmd);
    rs_squirt_byte(job, cmd);
    rs_squirt_netint(job, len, param_len);

    job->stats.lit_cmds++;
    job->stats.lit_bytes += len;
    job->stats.lit_cmdbytes += 1 + param_len;
}
Esempio n. 19
0
/**
 * Check if the state file @p fd is too old to be believed -- probably
 * because it was left over from a client that was killed.
 *
 * If so, close @p fd, unlink the file, and return EXIT_GONE.
 *
 * fd is closed on failure.
 **/
static int dcc_mon_kill_old(int fd,
                            char *fullpath)
{
    struct stat st;
    time_t now;

    /* Check if the file is old. */
    if (fstat(fd, &st) == -1) {
        dcc_close(fd);
        rs_log_warning("error statting %s: %s", fullpath, strerror(errno));
        return EXIT_IO_ERROR;
    }
    time(&now);

    /* Time you hear the siren / it's already too late */
    if (now - st.st_mtime > dcc_phase_max_age) {
        dcc_close(fd);          /* close first for windoze */
        rs_trace("unlink %s", fullpath);
        if (unlink(fullpath) == -1) {
            rs_log_warning("unlink %s failed: %s", fullpath, strerror(errno));
            return EXIT_IO_ERROR;
        }
        return EXIT_GONE;
    }

    return 0;
}
Esempio n. 20
0
/*
 * Edit the ELF file residing at @p path, changing all occurrences of
 * the path @p server_path to @p client_path in the debugging info.
 *
 * We're a bit sloppy about that; rather than properly parsing
 * the DWARF debug info, finding the DW_AT_comp_dir (compilation working
 * directory) field and the DW_AT_name (source file name) field,
 * we just do a search-and-replace in the ".debug_info" and ".debug_str"
 * sections.  But this is good enough.
 *
 * Returns 0 on success (whether or not the ".debug_info" and ".debug_str"
 * sections were found or updated).
 * Returns 1 on serious error that should cause distcc to fail.
 */
int dcc_fix_debug_info(const char *path, const char *client_path,
                              const char *server_path)
{
#ifndef HAVE_ELF_H
  rs_trace("no <elf.h>, so can't change %s to %s in debug info for %s",
           server_path, client_path, path);
  return 0;
#else
  /*
   * We can only safely replace a string with another of exactly
   * the same length.  (Replacing a string with a shorter string
   * results in errors from gdb.)
   * So we append trailing slashes on the client side path.
   */
  size_t client_path_len = strlen(client_path);
  size_t server_path_len = strlen(server_path);
  assert(client_path_len <= server_path_len);
  char *client_path_plus_slashes = malloc(server_path_len + 1);
  if (!client_path_plus_slashes) {
    rs_log_crit("failed to allocate memory");
    return 1;
  }
  strcpy(client_path_plus_slashes, client_path);
  while (client_path_len < server_path_len) {
    client_path_plus_slashes[client_path_len++] = '/';
  }
  client_path_plus_slashes[client_path_len] = '\0';
  rs_log_info("client_path_plus_slashes = %s", client_path_plus_slashes);
  return update_debug_info(path, server_path, client_path_plus_slashes);
#endif
}
Esempio n. 21
0
/**
 * Add a just-read-in checksum pair to the signature block.
 */
static rs_result rs_loadsig_add_sum(rs_job_t *job, rs_strong_sum_t *strong)
{
    size_t              new_size;
    rs_signature_t      *sig = job->signature;
    rs_block_sig_t      *asignature;

    sig->count++;
    new_size = sig->count * sizeof(rs_block_sig_t);

    sig->block_sigs = realloc(sig->block_sigs, new_size);
    
    if (sig->block_sigs == NULL) {
        return RS_MEM_ERROR;
    }
    asignature = &(sig->block_sigs[sig->count - 1]);

    asignature->weak_sum = job->weak_sig;
    asignature->i = sig->count;

    memcpy(asignature->strong_sum, strong, sig->strong_sum_len);

    if (rs_trace_enabled()) {
        char                hexbuf[RS_MAX_STRONG_SUM_LENGTH * 2 + 2];
        rs_hexify(hexbuf, strong, sig->strong_sum_len);

        rs_trace("read in checksum: weak=%#x, strong=%s", asignature->weak_sum,
                 hexbuf);
    }

    job->stats.sig_blocks++;

    return RS_RUNNING;
}
Esempio n. 22
0
/**
 * Main loop for the parent process with the new preforked implementation.
 * The parent is just responsible for keeping a pool of children and they
 * accept connections themselves.
 **/
int dcc_preforking_parent(int listen_fd)
{
    while (1) {
        pid_t kid;

        while (dcc_nkids < dcc_max_kids) {
            if ((kid = fork()) == -1) {
                rs_log_error("fork failed: %s", strerror(errno));
                return EXIT_OUT_OF_MEMORY; /* probably */
            } else if (kid == 0) {
                dcc_exit(dcc_preforked_child(listen_fd));
            } else {
                /* in parent */
                ++dcc_nkids;
                rs_trace("up to %d children", dcc_nkids);
            }

            /* Don't start them too quickly, or we might overwhelm a machine
             * that's having trouble. */
            sleep(1);

            dcc_reap_kids(FALSE);
        }

        /* wait for any children to exit, and then start some more */
        dcc_reap_kids(TRUE);

        /* Another little safety brake here: since children should not exit
         * too quickly, pausing before starting them should be harmless. */
        sleep(1);
    }
}
Esempio n. 23
0
int dcc_trace_version(void)
{
    rs_trace("%s %s %s; built %s %s",
             rs_program_name, PACKAGE_VERSION, GNU_HOST,
             __DATE__, __TIME__);
    return 0;
}
Esempio n. 24
0
static rs_result rs_patch_s_copy(rs_job_t *job)
{
    rs_long_t  where, len;
    rs_stats_t      *stats;

    where = job->param1;
    len = job->param2;
        
    rs_trace("COPY(where=" PRINTF_FORMAT_U64 ", len=" PRINTF_FORMAT_U64 ")", PRINTF_CAST_U64(where), PRINTF_CAST_U64(len));

    if (len < 0) {
        rs_log(RS_LOG_ERR, "invalid length=" PRINTF_FORMAT_U64 " on COPY command", PRINTF_CAST_U64(len));
        return RS_CORRUPT;
    }

    if (where < 0) {
        rs_log(RS_LOG_ERR, "invalid where=" PRINTF_FORMAT_U64 " on COPY command", PRINTF_CAST_U64(where));
        return RS_CORRUPT;
    }

    job->basis_pos = where;
    job->basis_len = len;

    stats = &job->stats;

    stats->copy_cmds++;
    stats->copy_bytes += len;
    stats->copy_cmdbytes += 1 + job->cmd->len_1 + job->cmd->len_2;

    job->statefn = rs_patch_s_copying;
    return RS_RUNNING;
}
Esempio n. 25
0
File: lock.c Progetto: aosm/distcc
void dcc_unlock_cpp_lock()
{
    if (cpp_lock != -1) {
        close(cpp_lock);
        rs_trace("gave up cpp lock: %s", cpp_lock_filename);
    }
}
Esempio n. 26
0
static rs_result rs_delta_s_flush(rs_job_t *job)
{
    rs_long_t      match_pos;
    size_t         match_len;
    rs_result      result;

    rs_job_check(job);
    /* read the input into the scoop */
    rs_getinput(job);
    /* output any pending output */
    result=rs_tube_catchup(job);
    /* while output is not blocked and there is any remaining data */
    while ((result==RS_DONE) && (job->scoop_pos < job->scoop_avail)) {
        /* check if this block matches */
        if (rs_findmatch(job,&match_pos,&match_len)) {
            /* append the match and reset the weak_sum */
            result=rs_appendmatch(job,match_pos,match_len);
            RollsumInit(&job->weak_sum);
        } else {
            /* rollout from weak_sum and append the miss byte */
            RollsumRollout(&job->weak_sum,job->scoop_next[job->scoop_pos]);
            rs_trace("block reduced to %d", (int)job->weak_sum.count);
            result=rs_appendmiss(job,1);
        }
    }
    /* if we are not blocked, flush and set end statefn. */
    if (result==RS_DONE) {
        result=rs_appendflush(job);
        job->statefn=rs_delta_s_end;
    }
    if (result==RS_DONE) {
        return RS_RUNNING;
    }
    return result;
}
Esempio n. 27
0
/**
 * Called when we're executing a COPY command and waiting for all the
 * data to be retrieved from the callback.
 */
static rs_result rs_patch_s_copying(rs_job_t *job)
{
    rs_result       result;
    size_t          len;
    void            *buf, *ptr;
    rs_buffers_t    *buffs = job->stream;

    len = job->basis_len;
    
    /* copy only as much as will fit in the output buffer, so that we
     * don't have to block or store the input. */
    if (len > buffs->avail_out)
        len = buffs->avail_out;

    if (!len)
        return RS_BLOCKED;

    rs_trace("copy " PRINTF_FORMAT_U64 " bytes from basis at offset " PRINTF_FORMAT_U64 "",
             PRINTF_CAST_U64(len), PRINTF_CAST_U64(job->basis_pos));

    ptr = buf = rs_alloc(len, "basis buffer");
    
    result = (job->copy_cb)(job->copy_arg, job->basis_pos, &len, &ptr);
    if (result != RS_DONE)
        return result;
    else
        rs_trace("copy callback returned %s", rs_strerror(result));
    
    rs_trace("got " PRINTF_FORMAT_U64 " bytes back from basis callback", PRINTF_CAST_U64(len));

    memcpy(buffs->next_out, ptr, len);

    buffs->next_out += len;
    buffs->avail_out -= len;

    job->basis_pos += len;
    job->basis_len -= len;

    free(buf);

    if (!job->basis_len) {
        /* Done! */
        job->statefn = rs_patch_s_cmdbyte;
    } 

    return RS_RUNNING;
}
Esempio n. 28
0
/** Write an END command. */
void
rs_emit_end_cmd(rs_job_t *job)
{
    int cmd = RS_OP_END;

    rs_trace("emit END, cmd_byte=%#x", cmd);
    rs_squirt_byte(job, cmd);
}
Esempio n. 29
0
/* Ask for the server not to be awakened until some data has arrived
 * on the socket.  This works for our protocol because the client
 * sends a request immediately after connection without waiting for
 * anything from the server. */
void dcc_defer_accept(int POSSIBLY_UNUSED(listen_fd))
{
#ifdef TCP_DEFER_ACCEPT
    int val = 1;

    if (!dcc_getenv_bool("DISTCC_TCP_DEFER_ACCEPT", 1)) {
        rs_trace("TCP_DEFER_ACCEPT disabled");
        return;
    }

    if (setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof val) == -1) {
        rs_log_warning("failed to set TCP_DEFER_ACCEPT: %s", strerror(errno));
    } else {
        rs_trace("TCP_DEFER_ACCEPT turned on");
    }
#endif
}
Esempio n. 30
0
static int dcc_mon_read_state(int fd, char *fullpath,
                              struct dcc_task_state *lp)
{
    int nread;

    /* Don't use dcc_readx(), because not being able to read it is not
     * a big deal. */
    nread = read(fd, lp, sizeof *lp);
    if (nread == -1) {
        rs_trace("failed to read state from %s: %s",
                 fullpath, strerror(errno));
        return EXIT_IO_ERROR;
    } else if (nread == 0) {
        /* empty file; just bad timing. */
        return EXIT_IO_ERROR;
    } else if (nread != sizeof *lp) {
        rs_trace("short read getting state from %s",
                 fullpath);
        return EXIT_IO_ERROR;
    }

    /* sanity-check some fields */

    if (lp->magic != DCC_STATE_MAGIC) {
        rs_log_warning("wrong magic number: %s",
                       fullpath);
        return EXIT_IO_ERROR;
    }

    if (lp->struct_size != sizeof (struct dcc_task_state)) {
        rs_log_warning("wrong structure size: %s: version mismatch?",
                       fullpath);
        return EXIT_IO_ERROR;
    }

    lp->file[sizeof lp->file - 1] = '\0';
    lp->host[sizeof lp->host - 1] = '\0';
    if (lp->curr_phase > DCC_PHASE_DONE) {
        lp->curr_phase = DCC_PHASE_COMPILE;
    }

    lp->next = 0;

    return 0;
}