/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 1991-1998 University of Maryland at College Park
* Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of U.M. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. U.M. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Authors: the Amanda Development Team. Its members are listed in a
* file named AUTHORS, in the root directory of this distribution.
*/
/*
* $Id: amtrmidx.c,v 1.42 2006/07/25 18:27:57 martinea Exp $
*
* trims number of index files to only those still in system. Well
* actually, it keeps a few extra, plus goes back to the last level 0
* dump.
*/
#include "amanda.h"
#include "conffile.h"
#include "diskfile.h"
#include "tapefile.h"
#include "find.h"
#include "amutil.h"
#include "amindex.h"
#include "pipespawn.h"
typedef struct inames {
gboolean header;
gboolean index_gz;
gboolean index_sorted;
gboolean index_sorted_gz;
gboolean index_unsorted;
gboolean index_unsorted_gz;
gboolean state_gz;
} inames;
static int sort_by_name_reversed(const void *a, const void *b);
static gboolean file_exists(char *filename);
static pid_t run_compress(int fd_in, int *fd_out, int *fd_err,
char *source_filename, char *dest_filename);
static pid_t run_uncompress(int fd_in, int *fd_out, int *fd_err,
char *source_filename, char *dest_filename);
static pid_t run_sort(int fd_in, int *fd_out, int *fd_err,
char *source_filename, char *dest_filename);
static gboolean wait_process(pid_t pid, int fd_err, char *name);
int main(int argc, char **argv);
static int sort_by_name_reversed(
const void *a,
const void *b)
{
char **ap = (char **) a;
char **bp = (char **) b;
return -1 * strcmp(*ap, *bp);
}
int
main(
int argc,
char ** argv)
{
GList *dlist;
GList *dlist1;
disk_t *diskp;
disklist_t diskl;
size_t i;
char *conf_diskfile;
char *conf_tapelist;
char *conf_indexdir;
find_result_t *output_find;
GHashTable *dump_hash;
time_t tmp_time;
int amtrmidx_debug = 0;
config_overrides_t *cfg_ovr = NULL;
gboolean compress_index;
gboolean sort_index;
char *lock_file;
file_lock *lock_index;
glib_init();
if (argc > 1 && argv[1] && g_str_equal(argv[1], "--version")) {
printf("amtrmidx-%s\n", VERSION);
return (0);
}
/*
* Configure program for internationalization:
* 1) Only set the message locale for now.
* 2) Set textdomain for all amanda related programs to "amanda"
* We don't want to be forced to support dozens of message catalogs.
*/
setlocale(LC_MESSAGES, "C");
textdomain("amanda");
safe_fd(-1, 0);
safe_cd();
set_pname("amtrmidx");
/* Don't die when child closes pipe */
signal(SIGPIPE, SIG_IGN);
dbopen(DBG_SUBDIR_SERVER);
dbprintf(_("%s: version %s\n"), argv[0], VERSION);
cfg_ovr = extract_commandline_config_overrides(&argc, &argv);
if (argc > 1 && g_str_equal(argv[1], "-t")) {
amtrmidx_debug = 1;
argc--;
argv++;
}
if (argc < 2) {
g_fprintf(stderr, _("Usage: %s [-t] <config> [-o configoption]*\n"), argv[0]);
return 1;
}
set_config_overrides(cfg_ovr);
config_init_with_global(CONFIG_INIT_EXPLICIT_NAME | CONFIG_INIT_USE_CWD, argv[1]);
conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
read_diskfile(conf_diskfile, &diskl);
amfree(conf_diskfile);
if (config_errors(NULL) >= CFGERR_WARNINGS) {
config_print_errors();
if (config_errors(NULL) >= CFGERR_ERRORS) {
g_critical(_("errors processing config file"));
}
}
check_running_as(RUNNING_AS_DUMPUSER);
dbrename(get_config_name(), DBG_SUBDIR_SERVER);
conf_tapelist = config_dir_relative(getconf_str(CNF_TAPELIST));
if(read_tapelist(conf_tapelist)) {
error(_("could not load tapelist \"%s\""), conf_tapelist);
/*NOTREACHED*/
}
amfree(conf_tapelist);
compress_index = getconf_boolean(CNF_COMPRESS_INDEX);
sort_index = getconf_boolean(CNF_SORT_INDEX);
output_find = find_dump(&diskl, 1);
dump_hash = make_dump_hash(output_find);
conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR));
/* take a lock file to prevent concurent trim */
lock_file = g_strdup_printf("%s/%s", conf_indexdir, "lock");
lock_index = file_lock_new(lock_file);
if (file_lock_lock_wr(lock_index) != 0)
goto lock_failed;
/* now go through the list of disks and find which have indexes */
time(&tmp_time);
tmp_time -= 7*24*60*60; /* back one week */
for (dlist = diskl.head; dlist != NULL; dlist = dlist->next)
{
diskp = dlist->data;
if (diskp->index)
{
char *indexdir, *qindexdir;
DIR *d;
struct dirent *f;
char **names;
size_t name_length;
size_t name_count;
char *host;
char *disk, *qdisk;
disk_t *dp;
GSList *matching_dp = NULL;
GHashTable *hash_inames = g_hash_table_new_full(g_str_hash, g_str_equal, &g_free, &g_free);
inames *iname;
/* get listing of indices, newest first */
host = sanitise_filename(diskp->host->hostname);
disk = sanitise_filename(diskp->name);
qdisk = quote_string(diskp->name);
indexdir = g_strjoin(NULL, conf_indexdir, "/",
host, "/",
disk, "/",
NULL);
qindexdir = quote_string(indexdir);
/* find all dles that use the same indexdir */
for (dlist1 = diskl.head; dlist1 != NULL; dlist1 = dlist1->next)
{
char *dp_host, *dp_disk;
dp = dlist1->data;
dp_host = sanitise_filename(dp->host->hostname);
dp_disk = sanitise_filename(dp->name);
if (g_str_equal(host, dp_host) &&
g_str_equal(disk, dp_disk)) {
matching_dp = g_slist_append(matching_dp, dp);
}
amfree(dp_host);
amfree(dp_disk);
}
dbprintf("%s %s -> %s\n", diskp->host->hostname,
qdisk, qindexdir);
amfree(qdisk);
if ((d = opendir(indexdir)) == NULL) {
dbprintf(_("could not open index directory %s: %s\n"), qindexdir, strerror(errno));
amfree(host);
amfree(disk);
amfree(indexdir);
amfree(qindexdir);
g_slist_free(matching_dp);
continue;
}
name_length = 100;
names = (char **)g_malloc(name_length * sizeof(char *));
name_count = 0;
while ((f = readdir(d)) != NULL) {
size_t l;
char *n;
size_t len_date = 0;
char *name;
gboolean is_new = FALSE;
if (is_dot_or_dotdot(f->d_name)) {
continue;
}
name = g_strdup(f->d_name);
n = name;
while (((*n >= '0' && *n <= '9') || *n == '_')) {
if (*n == '_')
len_date = n -name;
n++;
}
/* len_date=8 for YYYYMMDD */
/* len_date=14 for YYYYMMDDHHMMSS */
if((len_date != 8 && len_date != 14)
|| f->d_name[len_date] != '_'
|| ! isdigit((int)(f->d_name[len_date+1]))) {
g_free(name);
continue; /* not an index file */
}
/*
* Clear out old index temp files.
*/
l = strlen(f->d_name) - (sizeof(".tmp")-1);
if ((l > (len_date + 1))
&& (g_str_equal(f->d_name + l, ".tmp"))) {
struct stat sbuf;
char *path, *qpath;
path = g_strconcat(indexdir, f->d_name, NULL);
qpath = quote_string(path);
if(lstat(path, &sbuf) != -1
&& ((sbuf.st_mode & S_IFMT) == S_IFREG)
&& ((time_t)sbuf.st_mtime < tmp_time)) {
dbprintf("rm %s\n", qpath);
if(amtrmidx_debug == 0 && unlink(path) == -1) {
dbprintf(_("Error removing %s: %s\n"),
qpath, strerror(errno));
}
}
amfree(qpath);
amfree(path);
g_free(name);
continue;
}
if(name_count >= name_length) {
char **new_names;
new_names = g_malloc((name_length * 2) * sizeof(char *));
memcpy(new_names, names, name_length * sizeof(char *));
amfree(names);
names = new_names;
name_length *= 2;
}
*n = '\0';
n++;
iname = g_hash_table_lookup(hash_inames, name);
if (!iname) {
iname = g_new0(struct inames, 1);
is_new = TRUE;
}
if (strcmp(n, "header") == 0) {
iname->header = TRUE;
} else if (strcmp(n, "gz") == 0) {
iname->index_gz = TRUE;
} else if (strcmp(n, "sorted") == 0) {
iname->index_sorted = TRUE;
} else if (strcmp(n, "sorted.gz") == 0) {
iname->index_sorted_gz = TRUE;
} else if (strcmp(n, "unsorted") == 0) {
iname->index_unsorted = TRUE;
} else if (strcmp(n, "unsorted.gz") == 0) {
iname->index_unsorted_gz = TRUE;
} else if (strcmp(n, "state.gz") == 0) {
iname->state_gz = TRUE;
} else {
char *path, *qpath;
path = g_strconcat(indexdir, f->d_name, NULL);
qpath = quote_string(path);
dbprintf("rm %s\n", qpath);
if (amtrmidx_debug == 0 && unlink(path) == -1) {
dbprintf("Error removing %s: %s\n",
qpath, strerror(errno));
}
g_free(name);
continue;
}
if (is_new) {
g_hash_table_insert(hash_inames, g_strdup(name), iname);
names[name_count++] = g_strdup(name);
}
g_free(name);
}
closedir(d);
qsort(names, name_count, sizeof(char *), sort_by_name_reversed);
/*
* Search for the first full dump past the minimum number
* of index files to keep.
*/
for (i = 0; i < name_count; i++) {
char *datestamp;
int level;
size_t len_date;
int matching = 0;
GSList *mdp;
for (len_date = 0; len_date < sizeof("YYYYMMDDHHMMSS")-1; len_date++) {
if (!isdigit((int)(names[i][len_date]))) {
break;
}
}
iname = g_hash_table_lookup(hash_inames, names[i]);
datestamp = g_strdup(names[i]);
datestamp[len_date] = '\0';
if (sscanf(&names[i][len_date+1], "%d", &level) != 1)
level = 0;
for (mdp = matching_dp; mdp != NULL; mdp = mdp->next) {
dp = mdp->data;
if (dump_hash_exist(dump_hash, dp->host->hostname,
dp->name, datestamp, level)) {
matching = 1;
}
}
if (!matching) {
struct stat sbuf;
char *path;
path = g_strconcat(indexdir, names[i], NULL);
if (iname && iname->header) {
char *filepath = g_strconcat(path, ".header", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->index_gz) {
char *filepath = g_strconcat(path, ".gz", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->index_sorted) {
char *filepath = g_strconcat(path, "-sorted", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->index_sorted_gz) {
char *filepath = g_strconcat(path, "-sorted.gz", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->index_unsorted_gz) {
char *filepath = g_strconcat(path, "-unsorted.gz", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->index_unsorted) {
char *filepath = g_strconcat(path, "-unsorted", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
if (iname && iname->state_gz) {
char *filepath = g_strconcat(path, ".state.gz", NULL);
if (lstat(filepath, &sbuf) != -1 &&
((sbuf.st_mode & S_IFMT) == S_IFREG) &&
((time_t)sbuf.st_mtime < tmp_time)) {
char *qfilepath = quote_string(filepath);
g_debug("rm %s", qfilepath);
if(amtrmidx_debug == 0 && unlink(filepath) == -1) {
g_debug("Error removing %s: %s",
qfilepath, strerror(errno));
}
amfree(qfilepath);
}
amfree(filepath);
}
amfree(path);
} else {
/* Did it require un/compression and/or sorting */
char *orig_name = getindexfname(host, disk, datestamp, level);
char *sorted_name = getindex_sorted_fname(host, disk, datestamp, level);
char *sorted_gz_name = getindex_sorted_gz_fname(host, disk, datestamp, level);
char *unsorted_name = getindex_unsorted_fname(host, disk, datestamp, level);
char *unsorted_gz_name = getindex_unsorted_gz_fname(host, disk, datestamp, level);
gboolean orig_exist = FALSE;
gboolean sorted_exist = FALSE;
gboolean sorted_gz_exist = FALSE;
gboolean unsorted_exist = FALSE;
gboolean unsorted_gz_exist = FALSE;
int fd;
int uncompress_err_fd = -1;
int sort_err_fd = -1;
int compress_err_fd = -1;
pid_t uncompress_pid = -1;
pid_t sort_pid = -1;
pid_t compress_pid = -1;
iname = g_hash_table_lookup(hash_inames, names[i]);
if (iname) {
orig_exist = iname->index_gz;
sorted_exist = iname->index_sorted;
sorted_gz_exist = iname->index_sorted_gz;
unsorted_exist = iname->index_unsorted;
unsorted_gz_exist = iname->index_unsorted_gz;
} else {
orig_exist = file_exists(orig_name);
sorted_exist = file_exists(sorted_name);
sorted_gz_exist = file_exists(sorted_gz_name);
unsorted_exist = file_exists(unsorted_name);
unsorted_gz_exist = file_exists(unsorted_gz_name);
}
if (sort_index && compress_index) {
if (!sorted_gz_exist) {
if (sorted_exist) {
// COMPRESS
compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name);
unlink(sorted_name);
} else if (unsorted_exist) {
// SORT AND COMPRESS
sort_pid = run_sort(-1, &fd, &sort_err_fd, unsorted_name, NULL);
compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name);
unlink(unsorted_name);
} else if (unsorted_gz_exist) {
// UNCOMPRESS SORT AND COMPRESS
uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL);
sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL);
compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name);
unlink(unsorted_gz_name);
} else if (orig_exist) {
// UNCOMPRESS SORT AND COMPRESS
uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL);
sort_pid = run_sort(fd, &fd, &sort_err_fd, NULL, NULL);
compress_pid = run_compress(fd, NULL, &compress_err_fd, NULL, sorted_gz_name);
unlink(orig_name);
}
} else {
if (sorted_exist) {
unlink(sorted_name);
}
if (unsorted_exist) {
unlink(unsorted_name);
}
if (unsorted_gz_exist) {
unlink(unsorted_gz_name);
}
}
} else if (sort_index && !compress_index) {
if (!sorted_exist) {
if (sorted_gz_exist) {
// UNCOMPRESS
uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name);
unlink(sorted_gz_name);
} else if (unsorted_exist) {
// SORT
sort_pid = run_sort(-1, NULL, &sort_err_fd, unsorted_name, sorted_name);
unlink(unsorted_name);
} else if (unsorted_gz_exist) {
// UNCOMPRESS AND SORT
uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, unsorted_gz_name, NULL);
sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name);
unlink(unsorted_gz_name);
} else if (orig_exist) {
// UNCOMPRESS AND SORT
uncompress_pid = run_uncompress(-1, &fd, &uncompress_err_fd, orig_name, NULL);
sort_pid = run_sort(fd, NULL, &sort_err_fd, NULL, sorted_name);
unlink(orig_name);
}
} else {
if (sorted_gz_exist) {
unlink(sorted_gz_name);
}
if (unsorted_exist) {
unlink(unsorted_name);
}
if (unsorted_gz_exist) {
unlink(unsorted_gz_name);
}
}
} else if (!sort_index && compress_index) {
if (!sorted_gz_exist && !unsorted_gz_exist) {
if (sorted_exist) {
// COMPRESS sorted
compress_pid = run_compress(-1, NULL, &compress_err_fd, sorted_name, sorted_gz_name);
unlink(sorted_name);
} else if (unsorted_exist) {
// COMPRESS unsorted
compress_pid = run_compress(-1, NULL, &compress_err_fd, unsorted_name, unsorted_gz_name);
unlink(unsorted_name);
} else if (orig_exist) {
// RENAME orig
rename(orig_name, unsorted_gz_name);
}
} else {
if (sorted_exist) {
unlink(sorted_name);
}
if (unsorted_exist) {
unlink(unsorted_name);
}
if (sorted_gz_exist && unsorted_gz_exist) {
unlink(unsorted_gz_name);
}
}
} else if (!sort_index && !compress_index) {
if (!sorted_exist && !unsorted_exist) {
if (sorted_gz_exist) {
// UNCOMPRESS sorted
uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, sorted_gz_name, sorted_name);
unlink(sorted_gz_name);
} else if (unsorted_gz_exist) {
// UNCOMPRESS unsorted
uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, unsorted_gz_name, unsorted_name);
unlink(unsorted_gz_name);
} else if (orig_exist) {
// UNCOMPRESS orig
uncompress_pid = run_uncompress(-1, NULL, &uncompress_err_fd, orig_name, unsorted_name);
unlink(orig_name);
}
} else {
if (sorted_gz_exist) {
unlink(sorted_gz_name);
}
if (unsorted_gz_exist) {
unlink(unsorted_gz_name);
}
if (sorted_exist && unsorted_exist) {
unlink(unsorted_name);
}
}
}
if (uncompress_pid != -1)
wait_process(uncompress_pid, uncompress_err_fd, "uncompress");
if (sort_pid != -1)
wait_process(sort_pid, sort_err_fd, "sort");
if (compress_pid != -1)
wait_process(compress_pid, compress_err_fd, "compress");
g_free(orig_name);
g_free(sorted_name);
g_free(sorted_gz_name);
g_free(unsorted_name);
g_free(unsorted_gz_name);
}
amfree(datestamp);
amfree(names[i]);
}
g_slist_free(matching_dp);
amfree(names);
amfree(host);
amfree(disk);
amfree(indexdir);
amfree(qindexdir);
g_hash_table_destroy(hash_inames);
}
}
file_lock_unlock(lock_index);
lock_failed:
file_lock_free(lock_index);
amfree(conf_indexdir);
amfree(lock_file);
free_find_result(&output_find);
free_dump_hash(dump_hash);
clear_tapelist();
free_disklist(&diskl);
unload_disklist();
dbclose();
return 0;
}
static gboolean
file_exists(
char *filename)
{
struct stat stat_buf;
if (stat(filename, &stat_buf) != 0) {
if (errno == ENOENT) {
return FALSE;
}
}
return TRUE;
}
static pid_t
run_compress(
int fd_in,
int *fd_out,
int *fd_err,
char *source_filename,
char *dest_filename)
{
int in_fd;
int out_fd;
int create_pipe = STDERR_PIPE;
pid_t pid;
if (fd_in == -1) {
in_fd = open(source_filename, O_RDONLY);
} else {
in_fd = fd_in;
}
if (dest_filename) {
out_fd = open(dest_filename, O_WRONLY|O_CREAT, S_IRUSR);
} else {
create_pipe |= STDOUT_PIPE;
}
pid = pipespawn(COMPRESS_PATH, create_pipe, 0,
&in_fd, &out_fd, fd_err,
COMPRESS_PATH, COMPRESS_BEST_OPT, NULL);
close(in_fd);
if (dest_filename) {
close(out_fd);
} else {
*fd_out = out_fd;
}
return pid;
}
static pid_t
run_uncompress(
int fd_in,
int *fd_out,
int *fd_err,
char *source_filename,
char *dest_filename)
{
int in_fd;
int out_fd;
int create_pipe = STDERR_PIPE;
pid_t pid;
if (fd_in == -1) {
in_fd = open(source_filename, O_RDONLY);
} else {
in_fd = fd_in;
}
if (dest_filename) {
out_fd = open(dest_filename, O_WRONLY|O_CREAT, S_IRUSR);
} else {
create_pipe |= STDOUT_PIPE;
}
pid = pipespawn(UNCOMPRESS_PATH, create_pipe, 0,
&in_fd, &out_fd, fd_err,
UNCOMPRESS_PATH, UNCOMPRESS_OPT, NULL);
close(in_fd);
if (dest_filename) {
close(out_fd);
} else {
*fd_out = out_fd;
}
return pid;
}
static pid_t
run_sort(
int fd_in,
int *fd_out,
int *fd_err,
char *source_filename,
char *dest_filename)
{
int in_fd;
int out_fd;
int create_pipe = STDERR_PIPE;
pid_t pid;
gchar *tmpdir = getconf_str(CNF_TMPDIR);
if (fd_in == -1) {
in_fd = open(source_filename, O_RDONLY);
} else {
in_fd = fd_in;
}
if (dest_filename) {
out_fd = open(dest_filename, O_WRONLY|O_CREAT, S_IRUSR);
} else {
create_pipe |= STDOUT_PIPE;
}
pid = pipespawn(SORT_PATH, create_pipe, 0,
&in_fd, &out_fd, fd_err,
SORT_PATH, "-T", tmpdir, NULL);
close(in_fd);
if (dest_filename) {
close(out_fd);
} else {
*fd_out = out_fd;
}
return pid;
}
static gboolean
wait_process(
pid_t pid,
int fd_err,
char *name)
{
gboolean rval = TRUE;
amwait_t wait_status;
char *line;
while ((line = areads(fd_err)) != NULL) {
g_debug("%s stderr: %s", name, line);
rval = FALSE;
free(line);
}
aaclose(fd_err);
waitpid(pid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
g_debug("%s terminated with signal %d", name, WTERMSIG(wait_status));
rval = FALSE;
} else if (WIFEXITED(wait_status)) {
if (WEXITSTATUS(wait_status) != 0) {
g_debug("%s exited with status %d", name, WEXITSTATUS(wait_status));
rval = FALSE;
}
} else {
g_debug("%s got bad exit", name);
rval = FALSE;
}
return rval;
}