static void setup_file(void **state) { int rc; setup_dir(state); rc = system("echo \"This is a test\" > /tmp/csync_test/file.txt"); assert_int_equal(rc, 0); }
int priv_vfs_stickyfile_dir_fother_setup(int asroot, int injail, struct test *test) { setup_dir("priv_vfs_stickyfile_fother_setup: dpath", dpath, UID_OTHER, GID_OTHER, 0700); dpath_initialized = 1; return (0); }
int TestBackupMultiDataDir(CuTest *ct) { DB_ENV *dbenv; DB *dbp; DBTYPE dtype; struct handlers *info; int has_callback; u_int32_t flag; dtype = DB_BTREE; info = ct->context; has_callback = 0; flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_FILES; /* Step 1: set up directories and make DB_CONFIG. */ CuAssert(ct, "setup_dir", setup_dir(2, data_dirs) == 0); CuAssert(ct, "make_dbconfig", make_dbconfig("set_data_dir DATA1") == 0); /* Step 2: open db handle. */ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, dtype, 2, data_dirs, data_dirs[0], NULL, 0, NULL) == 0); info->dbenvp = dbenv; info->dbp = dbp; /* Step 3: store records into db. */ CuAssert(ct, "store_records", store_records(dbp, 1) == 0); CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0); /* Step 4: backup the whole environment without callbacks. */ CuAssert(ct, "backup_env", backup_env(ct, dbenv, flag, has_callback) == 0); /* * Step 5: check backup result. * 5a: verify db files are in BACKUP/DATA1. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 0, data_dirs[0], data_dirs[0]) == 0); /* 5b: verify that data_dirs are in backupdir. */ CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA1", 0) == 0); CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA2", 0) == 0); /* 5c: verify that log files are in BACKUP_DIR. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 1, NULL, NULL) == 0); /* 5d: verify that DB_CONFIG is in BACKUP_DIR. */ CuAssert(ct, "verify_dbconfig", verify_dbconfig(1) == 0); return (0); }
int TestBackupSetLogDir(CuTest *ct) { DB_ENV *dbenv; DB *dbp; DBTYPE dtype; struct handlers *info; char *dirs[2]; int has_callback = 1; u_int32_t flag; dtype = DB_BTREE; info = ct->context; has_callback = 1; flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_FILES; dirs[0] = LOG_DIR; dirs[1] = NULL; /* Step 1: set up directories and make DB_CONFIG. */ CuAssert(ct, "setup_dir", setup_dir(1, dirs) == 0); CuAssert(ct, "make_dbconfig", make_dbconfig("set_lg_dir LOG") == 0); /* Step 2: open db handle. */ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, dtype, 0, NULL, NULL, LOG_DIR, 0, NULL) == 0); info->dbenvp = dbenv; info->dbp = dbp; /* Step 3: store records into db. */ CuAssert(ct, "store_records", store_records(dbp, 1) == 0); CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0); /* Step 4: backup the whole environment with callbacks. */ CuAssert(ct, "backup_env", backup_env(ct, dbenv, flag, has_callback) == 0); /* * Step 5: check backup result. * 5a: verify the db file is in BACKUP_DIR. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 0, NULL, NULL) == 0); /* 5b: verify that log files are in BACKUP/LOG. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 1, LOG_DIR, LOG_DIR) == 0); /* 5c: verify that DB_CONFIG is in BACKUP_DIR. */ CuAssert(ct, "verify_dbconfig", verify_dbconfig(1) == 0); return (0); }
int TestBackupPartitionDB(CuTest *ct) { DB_ENV *dbenv; DB *dbp; DBT key1, key2, keys[2]; DBTYPE dtype; struct handlers *info; int has_callback; u_int32_t flag, value1, value2; dtype = DB_BTREE; info = ct->context; has_callback = 0; flag = DB_BACKUP_CLEAN | DB_CREATE | DB_BACKUP_SINGLE_DIR; /* Step 1: set up directories and make DB_CONFIG. */ CuAssert(ct, "setup_dir", setup_dir(1, data_dirs) == 0); CuAssert(ct, "make_dbconfig", make_dbconfig("set_data_dir DATA1") == 0); /* Make the partition keys. */ memset(&key1, 0, sizeof(DBT)); memset(&key2, 0, sizeof(DBT)); value1 = 8; key1.data = &value1; key1.size = sizeof(value1); value2 = 16; key2.data = &value2; key2.size = sizeof(value2); keys[0] = key1; keys[1] = key2; /* Step 2: open db handle. */ CuAssert(ct,"open_dbp", open_dbp(&dbenv, &dbp, dtype, 1, data_dirs, data_dirs[0], NULL, 3, keys) == 0); info->dbenvp = dbenv; info->dbp = dbp; /* Step 3: store records into db. */ CuAssert(ct, "store_records", store_records(dbp, 1) == 0); CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0); /* Step 4: backup the whole environment into a single directory. */ CuAssert(ct, "backup_env", backup_env(ct, dbenv, flag, has_callback) == 0); /* * Step 5: check backup result. * 5a: verify db files are in BACKUP/DATA1. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 1, 0, data_dirs[0], NULL) == 0); /* 5b: verify that creation directory is not in BACKUPD_DIR. */ CuAssert(ct, "__os_exist", __os_exists(NULL, "BACKUP/DATA", 0) != 0); /* 5c: verify log files are in BACKUP_DIR. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 1, NULL, NULL) == 0); /* 5d: verify that DB_CONFIG is not in BACKUP_DIR. */ CuAssert(ct, "verify_dbconfig", verify_dbconfig(0) == 0); return (0); }
int TestBackupSimpleEnvWithConfig(CuTest *ct) { DB_ENV *dbenv; DB *dbp; DBTYPE dtype; struct handlers *info; char **names; int cnt, has_callback; time_t end_time, secs1, secs2, start_time; u_int32_t flag, value; dtype = DB_BTREE; info = ct->context; has_callback = 0; flag = DB_EXCL; end_time = secs1 = secs2 = start_time = 0; /* Step 1: set up directories. */ CuAssert(ct, "setup_dir", setup_dir(0, NULL) == 0); /* Step 2: open db handle. */ CuAssert(ct, "open_dbp", open_dbp(&dbenv, &dbp, dtype, 0, NULL, NULL, NULL, 0, NULL) == 0); info->dbenvp = dbenv; info->dbp = dbp; /* * Step 3: store records into db so that there is more than * 1 data page in the db. */ CuAssert(ct, "store_records", store_records(dbp, 10) == 0); CuAssert(ct, "DB->sync", dbp->sync(dbp, 0) == 0); /* * Step 4: verify the backup handle is NULL, * since we never configure the backup. */ CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, &value) == EINVAL); /* * Step 5: backup without any backup configs. * 5a: backup only the db file without callbacks and record the time. */ start_time = time(NULL); CuAssert(ct, "backup_db", backup_db(ct, dbenv, BACKUP_DB, flag, has_callback) == 0); end_time = time(NULL); secs1 = end_time - start_time; /* 5b: verify db file is in BACKUP_DIR. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 0, NULL, NULL) == 0); /* 5c: verify that no other files are in BACKUP_DIR. */ CuAssert(ct, "__os_dirlist", __os_dirlist(NULL, BACKUP_DIR, 0, &names, &cnt) == 0); CuAssert(ct, "too many files in backupdir", cnt == 1); /* Clean up the backup directory. */ setup_envdir(BACKUP_DIR, 1); /* * Step 6: backup with backup configs. * 6a: configure the backup handle: use direct I/O to write pages to * the disk, the backup buffer size is 256 bytes (which is smaller * than the db page size), the number of pages * to read before pausing is 1, and the number of seconds to sleep * between batches of reads is 1. */ CuAssert(ct, "DB_ENV->set_backup_config", dbenv->set_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, 1) == 0); CuAssert(ct, "DB_ENV->set_backup_config", dbenv->set_backup_config(dbenv, DB_BACKUP_SIZE, 256) == 0); CuAssert(ct, "DB_ENV->set_backup_config", dbenv->set_backup_config(dbenv, DB_BACKUP_READ_COUNT, 1) == 0); CuAssert(ct, "DB_ENV->set_backup_config", dbenv->set_backup_config(dbenv, DB_BACKUP_READ_SLEEP, US_PER_SEC / 2) == 0); /* * 6b: backup only the db file without callbacks and * record the time. */ start_time = time(NULL); CuAssert(ct, "backup_db", backup_db(ct, dbenv, BACKUP_DB, flag, has_callback) == 0); end_time = time(NULL); secs2 = end_time - start_time; /* 6c: verify db file is in BACKUP_DIR. */ CuAssert(ct, "verify_db_log", verify_db_log(dtype, 0, 0, NULL, NULL) == 0); /* 6d: no other files are in BACKUP_DIR. */ CuAssert(ct, "__os_dirlist", __os_dirlist(NULL, BACKUP_DIR, 0, &names, &cnt) == 0); CuAssert(ct, "too many files in backupdir", cnt == 1); /* 6e: verify the backup config. */ CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_READ_SLEEP, &value) == 0); CuAssertTrue(ct, value == US_PER_SEC / 2); /* * Verify the backup config DB_BACKUP_READ_SLEEP works. That is with * the configuration, backup pauses for a number of microseconds * between batches of reads. So for the same backup content, the backup * time with the configuration should be longer than that without it. */ CuAssertTrue(ct, secs2 > secs1); CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_READ_COUNT, &value) == 0); CuAssertTrue(ct, value == 1); CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_SIZE, &value) == 0); CuAssertTrue(ct, value == 256); CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, &value) == 0); CuAssertTrue(ct, value == 1); /* * Step 7: re-configure the backup write direct config and * verify the new config value. */ CuAssert(ct, "DB_ENV->set_backup_config", dbenv->set_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, 0) == 0); CuAssert(ct, "DB_ENV->get_backup_config", dbenv->get_backup_config(dbenv, DB_BACKUP_WRITE_DIRECT, &value) == 0); CuAssertTrue(ct, value == 0); return (0); }
FTS * fts_open (char * const *argv, register int options, int (*compar) (FTSENT const **, FTSENT const **)) { register FTS *sp; register FTSENT *p, *root; register size_t nitems; FTSENT *parent, *tmp = NULL; /* pacify gcc */ size_t len; /* Options check. */ if (options & ~FTS_OPTIONMASK) { __set_errno (EINVAL); return (NULL); } /* Allocate/initialize the stream */ if ((sp = malloc(sizeof(FTS))) == NULL) return (NULL); memset(sp, 0, sizeof(FTS)); sp->fts_compar = compar; sp->fts_options = options; /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ if (ISSET(FTS_LOGICAL)) SET(FTS_NOCHDIR); /* * Start out with 1K of file name space, and enough, in any case, * to hold the user's file names. */ #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif { size_t maxarglen = fts_maxarglen(argv); if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN))) goto mem1; } /* Allocate/initialize root's parent. */ if ((parent = fts_alloc(sp, "", 0)) == NULL) goto mem2; parent->fts_level = FTS_ROOTPARENTLEVEL; /* Allocate/initialize root(s). */ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { /* Don't allow zero-length file names. */ if ((len = strlen(*argv)) == 0) { __set_errno (ENOENT); goto mem3; } if ((p = fts_alloc(sp, *argv, len)) == NULL) goto mem3; p->fts_level = FTS_ROOTLEVEL; p->fts_parent = parent; p->fts_accpath = p->fts_name; p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW) != 0); /* Command-line "." and ".." are real directories. */ if (p->fts_info == FTS_DOT) p->fts_info = FTS_D; /* * If comparison routine supplied, traverse in sorted * order; otherwise traverse in the order specified. */ if (compar) { p->fts_link = root; root = p; } else { p->fts_link = NULL; if (root == NULL) tmp = root = p; else { tmp->fts_link = p; tmp = p; } } } if (compar && nitems > 1) root = fts_sort(sp, root, nitems); /* * Allocate a dummy pointer and make fts_read think that we've just * finished the node before the root(s); set p->fts_info to FTS_INIT * so that everything about the "current" node is ignored. */ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) goto mem3; sp->fts_cur->fts_link = root; sp->fts_cur->fts_info = FTS_INIT; if (! setup_dir (sp)) goto mem3; /* * If using chdir(2), grab a file descriptor pointing to dot to ensure * that we can get back here; this could be avoided for some file names, * but almost certainly not worth the effort. Slashes, symbolic links, * and ".." are all fairly nasty problems. Note, if we can't get the * descriptor we run anyway, just more slowly. */ if (!ISSET(FTS_NOCHDIR) && (sp->fts_rfd = diropen (".")) < 0) SET(FTS_NOCHDIR); return (sp); mem3: fts_lfree(root); free(parent); mem2: free(sp->fts_path); mem1: free(sp); return (NULL); }
FTS * fts_open (char * const *argv, register int options, int (*compar) (FTSENT const **, FTSENT const **)) { register FTS *sp; register FTSENT *p, *root; register size_t nitems; FTSENT *parent = NULL; FTSENT *tmp = NULL; /* pacify gcc */ size_t len; bool defer_stat; /* Options check. */ if (options & ~FTS_OPTIONMASK) { __set_errno (EINVAL); return (NULL); } if ((options & FTS_NOCHDIR) && (options & FTS_CWDFD)) { __set_errno (EINVAL); return (NULL); } if ( ! (options & (FTS_LOGICAL | FTS_PHYSICAL))) { __set_errno (EINVAL); return (NULL); } /* Allocate/initialize the stream */ if ((sp = malloc(sizeof(FTS))) == NULL) return (NULL); memset(sp, 0, sizeof(FTS)); sp->fts_compar = compar; sp->fts_options = options; /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ if (ISSET(FTS_LOGICAL)) { SET(FTS_NOCHDIR); CLR(FTS_CWDFD); } /* Initialize fts_cwd_fd. */ sp->fts_cwd_fd = AT_FDCWD; if ( ISSET(FTS_CWDFD) && ! HAVE_OPENAT_SUPPORT) { /* While it isn't technically necessary to open "." this early, doing it here saves us the trouble of ensuring later (where it'd be messier) that "." can in fact be opened. If not, revert to FTS_NOCHDIR mode. */ int fd = open (".", O_RDONLY); if (fd < 0) { /* Even if `.' is unreadable, don't revert to FTS_NOCHDIR mode on systems like Linux+PROC_FS, where our openat emulation is good enough. Note: on a system that emulates openat via /proc, this technique can still fail, but only in extreme conditions, e.g., when the working directory cannot be saved (i.e. save_cwd fails) -- and that happens on Linux only when "." is unreadable and the CWD would be longer than PATH_MAX. FIXME: once Linux kernel openat support is well established, replace the above open call and this entire if/else block with the body of the if-block below. */ if ( openat_needs_fchdir ()) { SET(FTS_NOCHDIR); CLR(FTS_CWDFD); } } else { close (fd); } } /* * Start out with 1K of file name space, and enough, in any case, * to hold the user's file names. */ #ifndef MAXPATHLEN # define MAXPATHLEN 1024 #endif { size_t maxarglen = fts_maxarglen(argv); if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN))) goto mem1; } /* Allocate/initialize root's parent. */ if (*argv != NULL) { if ((parent = fts_alloc(sp, "", 0)) == NULL) goto mem2; parent->fts_level = FTS_ROOTPARENTLEVEL; } /* The classic fts implementation would call fts_stat with a new entry for each iteration of the loop below. If the comparison function is not specified or if the FTS_DEFER_STAT option is in effect, don't stat any entry in this loop. This is an attempt to minimize the interval between the initial stat/lstat/fstatat and the point at which a directory argument is first opened. This matters for any directory command line argument that resides on a file system without genuine i-nodes. If you specify FTS_DEFER_STAT along with a comparison function, that function must not access any data via the fts_statp pointer. */ defer_stat = (compar == NULL || ISSET(FTS_DEFER_STAT)); /* Allocate/initialize root(s). */ for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { /* Don't allow zero-length file names. */ if ((len = strlen(*argv)) == 0) { __set_errno (ENOENT); goto mem3; } if ((p = fts_alloc(sp, *argv, len)) == NULL) goto mem3; p->fts_level = FTS_ROOTLEVEL; p->fts_parent = parent; p->fts_accpath = p->fts_name; /* Even when defer_stat is true, be sure to stat the first command line argument, since fts_read (at least with FTS_XDEV) requires that. */ if (defer_stat && root != NULL) { p->fts_info = FTS_NSOK; fts_set_stat_required(p, true); } else { p->fts_info = fts_stat(sp, p, false); } /* * If comparison routine supplied, traverse in sorted * order; otherwise traverse in the order specified. */ if (compar) { p->fts_link = root; root = p; } else { p->fts_link = NULL; if (root == NULL) tmp = root = p; else { tmp->fts_link = p; tmp = p; } } } if (compar && nitems > 1) root = fts_sort(sp, root, nitems); /* * Allocate a dummy pointer and make fts_read think that we've just * finished the node before the root(s); set p->fts_info to FTS_INIT * so that everything about the "current" node is ignored. */ if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) goto mem3; sp->fts_cur->fts_link = root; sp->fts_cur->fts_info = FTS_INIT; if (! setup_dir (sp)) goto mem3; /* * If using chdir(2), grab a file descriptor pointing to dot to ensure * that we can get back here; this could be avoided for some file names, * but almost certainly not worth the effort. Slashes, symbolic links, * and ".." are all fairly nasty problems. Note, if we can't get the * descriptor we run anyway, just more slowly. */ if (!ISSET(FTS_NOCHDIR) && !ISSET(FTS_CWDFD) && (sp->fts_rfd = diropen (sp, ".")) < 0) SET(FTS_NOCHDIR); i_ring_init (&sp->fts_fd_ring, -1); return (sp); mem3: fts_lfree(root); free(parent); mem2: free(sp->fts_path); mem1: free(sp); return (NULL); }
int main(int argc, char** argv) { int ret; setup_dir(); /* init globals */ gcc = sa_concat(gcc, "gcc"); /* replaced laterwards if c++ */ gcc = sa_concat(gcc, "-I."); src_lines = sa_concat(src_lines, "#define __LARGE_C__ " VERSION_INT_STR "\n" "#ifdef __cplusplus\n" "extern \"C\" {\n" "#endif\n" "#include <stdio.h>\n" "#include <stdlib.h>\n" "#ifdef __cplusplus\n" "}\n" "#include <iostream>\n" "using namespace std;\n" "#endif\n" "\n" "__LARGE_C_PREFIX__\n"); argv++; { /* parse args, determine cache dir */ char** new_argv = parse_args(argv, NULL, 0); for (; argv != new_argv; argv++) { add_spec(*argv, strlen(*argv) + 1); } if (! keep_files && (oneliner || *argv != NULL)) { struct stat st; if (oneliner) { build_store_dir(); } else if (stat(*argv, &st) == 0) { add_spec(*argv, strlen(*argv) + 1); add_spec(&st.st_size, sizeof(st.st_size)); add_spec(&st.st_mtime, sizeof(st.st_mtime)); build_store_dir(); } } } /* use cache if possible */ if (store_dir != NULL && check_specs()) { char** child_argv = NULL; #ifdef _WIN32 _utime(store_dir, NULL); /* update mtime of the directory */ #else utimes(store_dir, NULL); /* update mtime of the directory */ #endif exec_file = str_concat(str_dup(store_dir), "/"A_OUT); child_argv = sa_concat(child_argv, exec_file); #ifdef _WIN32 { int status; ret = spawn_w32(child_argv, &status); if (status == 0) exit(ret); } #else execv(exec_file, child_argv); #endif // if execv failed, we compile free(exec_file); remove_dir(store_dir); } /* prepare files */ make_temp_dir(); exec_file = str_concat(str_dup(temp_dir), "/"A_OUT); c_file = str_concat(str_dup(temp_dir), "/source.c"); if ((src_fp = fopen(c_file, "wt")) == NULL) { cmd_error("failed to create temporary file: %s : %s\n", c_file, strerror(errno)); } while (src_lines != NULL && *src_lines != NULL) { fputs(*src_lines++, src_fp); } /* write source with adjustments */ if (! oneliner) { FILE* fp; char* file; char* line; int line_no = 0; if (argv[0] == NULL) { fp = stdin; file = "stdin"; } else if (strcmp(argv[0], "-") == 0) { fp = stdin; argv++; file = "stdin"; } else { file = *argv++; if ((fp = fopen(file, "rt")) == NULL) { cmd_error("cannot open file: %s : %s\n", file, strerror(errno)); } fprintf(src_fp, "# 1 \"%s\" 1\n", file); } while ((line = get_line(fp)) != NULL) { int comment_out = 0; line_no++; if (line_no == 1 && strncmp(line, "#!", 2) == 0) { comment_out = 1; } else if (line[0] == '#') { char* buf = str_dup(line + 1); char** tokens = split_tokens(buf); if (*tokens != NULL) { if (strcmp(tokens[0], "option") == 0) { parse_args(tokens + 1, file, line_no); comment_out = 1; } } free(buf); free(tokens); } if (comment_out == 1) { fprintf(src_fp, "// "); } fputs(line, src_fp); } fputs("\n", src_fp); if (fp != stdin) { fclose(fp); } } /* close source file */ fputs("__LARGE_C_SUFFIX__\n", src_fp); fclose(src_fp); src_fp = NULL; /* compile */ if (use_plusplus) { gcc[0] = "g++"; } if (use_main) { gcc = sa_concat(gcc, "-D__LARGE_C_PREFIX__="); gcc = sa_concat(gcc, "-D__LARGE_C_SUFFIX__="); } else { gcc = sa_concat(gcc, "-D__LARGE_C_PREFIX__=int main(int argc, char** argv) {"); gcc = sa_concat(gcc, "-D__LARGE_C_SUFFIX__=; return 0; }"); } gcc = sa_concat(gcc, "-o"); gcc = sa_concat(gcc, show_disassembly ? "-" : exec_file); gcc = sa_concat(gcc, c_file); gcc = sa_merge(gcc, lopts); if ((ret = call_proc(gcc, "could not execute compiler")) != 0) { cleanup(); exit(ret); } if (show_disassembly) { cleanup(); exit(0); } { /* execute */ char** child_argv = NULL; if (use_debugger) { child_argv = sa_concat(child_argv, "gdb"); } child_argv = sa_concat(child_argv, exec_file); child_argv = sa_merge(child_argv, argv); ret = call_proc(child_argv, "could not spawn child process"); } /* move temp_dir to store_dir, if possible. * or, remove work_dir */ if (store_dir == NULL) { cleanup(); } else { save_specs(); update_cache(); if (rename(temp_dir, store_dir) != 0) { cleanup(); } } return ret; }