Example #1
0
/**
 * Create the directory @p path, and register it for deletion when this
 * compilation finished.  If it already exists as a directory
 * we succeed, but we don't register the directory for deletion.
 **/
int dcc_mk_tmpdir(const char *path)
{
    struct stat buf;
    int ret;

    if (stat(path, &buf) == -1) {
        if (mkdir(path, 0777) == -1) {
            return EXIT_IO_ERROR;
        }
        if ((ret = dcc_add_cleanup(path))) {
            /* bailing out */
            rmdir(path);
            return ret;
        }
    } else {
        /* we could stat the file successfully; if it's a directory,
         * all is well, but we should not it delete later, since we did
         * not make it.
         */
         if (S_ISDIR(buf.st_mode)) {
             return 0;
         } else {
             rs_log_error("mkdir '%s' failed: %s", path, strerror(errno));
             return EXIT_IO_ERROR;
         }
    }
    return 0;
}
Example #2
0
/* This function returns a directory-name, it does not end in a slash. */
int dcc_get_tmp_top(const char **p_ret)
{
#ifdef __CYGWIN32__
    int ret;

    char *s = malloc(MAXPATHLEN+1);
    int f,ln;
    GetTempPath(MAXPATHLEN+1,s);
    /* Convert slashes */
    for (f = 0, ln = strlen(s); f != ln; f++)
        if (s[f]=='\\') s[f]='/';
    /* Delete trailing slashes -- but leave one slash if s is all slashes */
    for (f = strlen(s)-1; f > 0 && s[f] == '/'; f--)
        s[f]='\0';

    if ((ret = dcc_add_cleanup(s))) {
        free(s);
        return ret;
    }
    *p_ret = s;
    return 0;
#else
    const char *d;

    d = getenv("TMPDIR");

    if (!d || d[0] == '\0') {
        *p_ret = "/tmp";
        return 0;
    } else {
        *p_ret = d;
        return 0;
    }
#endif
}
Example #3
0
/* This function returns a directory-name, it does not end in a slash. */
int dcc_get_tmp_top(const char **p_ret)
{
#ifdef __CYGWIN32__
    int ret;

    char *s = malloc(MAXPATHLEN+1);
    int f,ln;
    GetTempPath(MAXPATHLEN+1,s);
    /* Convert slashes */
    for (f = 0, ln = strlen(s); f != ln; f++)
        if (s[f]=='\\') s[f]='/';
    /* Delete trailing slashes -- but leave one slash if s is all slashes */
    for (f = strlen(s)-1; f > 0 && s[f] == '/'; f--)
        s[f]='\0';

    if ((ret = dcc_add_cleanup(s))) {
        free(s);
        return ret;
    }
    *p_ret = s;
    return 0;
#else
    const char *d;
    char *s;
    int l;
    static const char *tmp_dir = NULL;
    
    if (!tmp_dir) {

        d = getenv("TMPDIR");

        /* Make sure it doesn't end in a slash */
        if (d && d[0] != '\0') {
            l = strlen(d) - 1;
            if (d[l] == '/') {
                s = strdup(d);
                if (s) {
                    tmp_dir = s;
                    /* Loop to handle multiple trailing slashes */
                    while (l && s[l] == '/') {
                        s[l--] = 0;
                    }
                }
            } else {
                tmp_dir = d;
            }
        }
        if (!tmp_dir) {
            /* Env var was not set, or strdup failed */
            tmp_dir = "/tmp";
        }
    }
    *p_ret = tmp_dir;
    return 0;
#endif
}
Example #4
0
/* This function creates a temporary directory, to be used for
 * all (input) files during one compilation.
 * The name of the directory is stored in @p tempdir, which is
 * malloc'ed here. The caller is responsible for freeing it.
 * The format of the directory name is <TMPTOP>/distccd_<randomnumber>
 * Returns the new temp dir in tempdir.
 */
int dcc_get_new_tmpdir(char **tempdir)
{
    int ret;
    const char *tmp_top;
    char *s;
    if ((ret = dcc_get_tmp_top(&tmp_top))) {
        return ret;
    }
    if (asprintf(&s, "%s/distccd_XXXXXX", tmp_top) == -1)
        return EXIT_OUT_OF_MEMORY;
    if ((*tempdir = mkdtemp(s)) == 0) {
        return EXIT_IO_ERROR;
    }
    if ((ret = dcc_add_cleanup(s))) {
        /* bailing out */
        rmdir(s);
        return ret;
    }
    return 0;
}
Example #5
0
int dcc_r_many_files(int in_fd,
                     const char *dirname,
                     enum dcc_compress compr)
{
    int ret = 0;
    unsigned int n_files;
    unsigned int i;
    char *name = 0;
    char *link_target = 0;
    char token[5];

    if ((ret = dcc_r_token_int(in_fd, "NFIL", &n_files)))
        return ret;

    for (i = 0; i < n_files; ++i) {
        /* like dcc_r_argv */
        unsigned int link_or_file_len;

        if ((ret = dcc_r_token_string(in_fd, "NAME", &name)))
            goto out_cleanup;

        /* FIXME: verify that name starts with '/' and doesn't contain '..'. */
        if ((ret = prepend_dir_to_name(dirname, &name)))
            goto out_cleanup;

        if ((ret = dcc_r_sometoken_int(in_fd, token, &link_or_file_len)))
            goto out_cleanup;

        /* Must prepend the dirname for the file name, a link's target name. */
        if (strncmp(token, "LINK", 4) == 0) {

            if ((ret = dcc_r_str_alloc(in_fd, link_or_file_len, &link_target))){
                goto out_cleanup;
            }
            /* FIXME: verify that link_target doesn't contain '..'.
             * But the include server uses '..' to reference system
             * directories (see _MakeLinkFromMirrorToRealLocation
             * in include_server/compiler_defaults.py), so we'll need to
             * modify that first. */
            if (link_target[0] == '/') {
                if ((ret = prepend_dir_to_name(dirname, &link_target))) {
                    goto out_cleanup;
                }
            }
            if ((ret = dcc_mk_tmp_ancestor_dirs(name))) {
                goto out_cleanup;
            }
            if (symlink(link_target, name) != 0) {
                rs_log_error("failed to create path for %s: %s", name,
                             strerror(errno));
                ret = 1;
                goto out_cleanup;
            }
            if ((ret = dcc_add_cleanup(name))) {
                /* bailing out */
                unlink(name);
                goto out_cleanup;
            }
        } else if (strncmp(token, "FILE", 4) == 0) {
            if ((ret = dcc_r_file(in_fd, name, link_or_file_len, compr))) {
                goto out_cleanup;
            }
            if ((ret = dcc_add_cleanup(name))) {
              /* bailing out */
              unlink(name);
              goto out_cleanup;
            }
        } else {
            char buf[4 + sizeof(link_or_file_len)];
            /* unexpected token */
            rs_log_error("protocol derailment: expected token FILE or LINK");
            /* We should explain what happened here, but we have already read
             * a few more bytes.
             */
            strncpy(buf, token, 4);
            /* TODO(manos): this is probably not kosher */
            memcpy(&buf[4], &link_or_file_len, sizeof(link_or_file_len));
            dcc_explain_mismatch(buf, 12, in_fd);
            ret = EXIT_PROTOCOL_ERROR;
            goto out_cleanup;
        }

out_cleanup:
        free(name);
        name = NULL;
        free(link_target);
        link_target = NULL;
        if (ret)
            break;
    }
    return ret;
}
Example #6
0
/**
 * Create a file inside the temporary directory and register it for
 * later cleanup, and return its name.
 *
 * The file will be reopened later, possibly in a child.  But we know
 * that it exists with appropriately tight permissions.
 **/
int dcc_make_tmpnam(const char *prefix,
                    const char *suffix,
                    char **name_ret)
{
    char *s = NULL;
    const char *tempdir;
    int ret;
    unsigned long random_bits;
    int fd;

    if ((ret = dcc_get_tmp_top(&tempdir)))
        return ret;

    if (access(tempdir, W_OK|X_OK) == -1) {
        rs_log_error("can't use TMPDIR \"%s\": %s", tempdir, strerror(errno));
        return EXIT_IO_ERROR;
    }

    random_bits = (unsigned long) getpid() << 16;

# if HAVE_GETTIMEOFDAY
    {
        struct timeval tv;
        gettimeofday(&tv, NULL);
        random_bits ^= tv.tv_usec << 16;
        random_bits ^= tv.tv_sec;
    }
# else
    random_bits ^= time(NULL);
# endif

#if 0
    random_bits = 0;            /* FOR TESTING */
#endif

    do {
        free(s);

        if (asprintf(&s, "%s/%s_%08lx%s",
                     tempdir,
                     prefix,
                     random_bits & 0xffffffffUL,
                     suffix) == -1)
            return EXIT_OUT_OF_MEMORY;

        /* Note that if the name already exists as a symlink, this
         * open call will fail.
         *
         * The permissions are tight because nobody but this process
         * and our children should do anything with it. */
        fd = open(s, O_WRONLY | O_CREAT | O_EXCL, 0600);
        if (fd == -1) {
            /* try again */
            rs_trace("failed to create %s: %s", s, strerror(errno));
            random_bits += 7777; /* fairly prime */
            continue;
        }

        if (close(fd) == -1) {  /* huh? */
            rs_log_warning("failed to close %s: %s", s, strerror(errno));
            return EXIT_IO_ERROR;
        }

        break;
    } while (1);

    if ((ret = dcc_add_cleanup(s))) {
        /* bailing out */
        unlink(s);
        free(s);
        return ret;
    }

    *name_ret = s;
    return 0;
}
Example #7
0
int dcc_r_many_files(int in_fd,
                     const char *dirname,
                     enum dcc_compress compr)
{
    int ret = 0;
    unsigned int n_files;
    unsigned int i;
    char *name = NULL;
    char *link_target = NULL;
    char token[5];

#ifdef XCODE_INTEGRATION
    /* NOTE: If this function is ever used for something besides pump
     * mode support for receiving things to be compiled, then it should
     * take another argument to include/exclude this fixup. */
    char *xci_name, *xci_link_target, *extension;
#endif

    if ((ret = dcc_r_token_int(in_fd, "NFIL", &n_files)))
        return ret;

    for (i = 0; i < n_files; ++i) {
        /* like dcc_r_argv */
        unsigned int link_or_file_len;

        if ((ret = dcc_r_token_string(in_fd, "NAME", &name)))
            goto out_cleanup;

#ifdef XCODE_INTEGRATION
        xci_name = dcc_xci_unmask_developer_dir(name);
        if (xci_name) {
            free(name);
            name = xci_name;
            xci_name = NULL;
        } else {
            ret = EXIT_OUT_OF_MEMORY;
            goto out_cleanup;
        }
#endif

        /* FIXME: verify that name starts with '/' and doesn't contain '..'. */
        if ((ret = prepend_dir_to_name(dirname, &name)))
            goto out_cleanup;

        if ((ret = dcc_r_sometoken_int(in_fd, token, &link_or_file_len)))
            goto out_cleanup;

        /* Must prepend the dirname for the file name, a link's target name. */
        if (strncmp(token, "LINK", 4) == 0) {

            if ((ret = dcc_r_str_alloc(in_fd, link_or_file_len, &link_target))){
                goto out_cleanup;
            }
            rs_trace("got '%s'", link_target);

#ifdef XCODE_INTEGRATION
            xci_link_target = dcc_xci_unmask_developer_dir(link_target);
            if (xci_link_target) {
                free(link_target);
                link_target = xci_link_target;
                xci_link_target = NULL;
            } else {
                ret = EXIT_OUT_OF_MEMORY;
                goto out_cleanup;
            }
#endif
          
            /* FIXME: verify that link_target doesn't contain '..'.
             * But the include server uses '..' to reference system
             * directories (see _MakeLinkFromMirrorToRealLocation
             * in include_server/compiler_defaults.py), so we'll need to
             * modify that first. */
            if (link_target[0] == '/') {
                if ((ret = prepend_dir_to_name(dirname, &link_target))) {
                    goto out_cleanup;
                }
            }
            if ((ret = dcc_mk_tmp_ancestor_dirs(name))) {
                goto out_cleanup;
            }
            if (symlink(link_target, name) != 0) {
                rs_log_error("failed to create path for %s: %s", name,
                             strerror(errno));
                ret = 1;
                goto out_cleanup;
            }
            if ((ret = dcc_add_cleanup(name))) {
                /* bailing out */
                unlink(name);
                goto out_cleanup;
            }
        } else if (strncmp(token, "FILE", 4) == 0) {
            if ((ret = dcc_r_file(in_fd, name, link_or_file_len, compr))) {
                goto out_cleanup;
            }
#ifdef XCODE_INTEGRATION
            if ((extension = dcc_find_extension(name))
                 && !strcmp(extension, ".hmap")
                 && (ret = dcc_xci_headermap_fix(name, dirname))) {
                unlink(name);
                goto out_cleanup;
            }
#endif
            if ((ret = dcc_add_cleanup(name))) {
              /* bailing out */
              unlink(name);
              goto out_cleanup;
            }
        } else {
            char buf[4 + sizeof(link_or_file_len)];
            /* unexpected token */
            rs_log_error("protocol derailment: expected token FILE or LINK");
            /* We should explain what happened here, but we have already read
             * a few more bytes.
             */
            strncpy(buf, token, 4);
            /* TODO(manos): this is probably not kosher */
            memcpy(&buf[4], &link_or_file_len, sizeof(link_or_file_len));
            dcc_explain_mismatch(buf, 12, in_fd);
            ret = EXIT_PROTOCOL_ERROR;
            goto out_cleanup;
        }

out_cleanup:
        if (name) {
            free(name);
            name = NULL;
        }
        if (link_target) {
            free(link_target);
            link_target = NULL;
        }
        if (ret)
            break;
    }
    return ret;
}