#include <sys/stat.h>
#include <locale.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dconf.h"
#include "minfree.h"
#include "utils.h"
static const char USAGE[] = "\
Usage: %s [-Henpuy] [-c kernel | curproc | all ]\n\
[-d dump-device | swap | none ] [-m min {k|m|%%} ] [-s savecore-dir]\n\
[-r root-dir] [-z on|off]\n";
static const char OPTS[] = "Heinpuyc:d:m:s:r:z:";
static const char PATH_DEVICE[] = "/dev/dump";
static const char PATH_CONFIG[] = "/etc/dumpadm.conf";
int
main(int argc, char *argv[])
{
const char *pname = getpname(argv[0]);
u_longlong_t minf;
struct stat st;
int c;
int dflag = 0;
int eflag = 0;
int dcmode = DC_CURRENT;
int modified = 0;
char *minfstr = NULL;
dumpconf_t dc;
int chrooted = 0;
int douuid = 0;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
while (optind < argc) {
while ((c = getopt(argc, argv, OPTS)) != (int)EOF) {
if (c == 'r' && ++chrooted && chroot(optarg) == -1)
die(gettext("failed to chroot to %s"), optarg);
else if (c == 'u')
dcmode = DC_OVERRIDE;
else if (c == '?') {
(void) fprintf(stderr, gettext(USAGE), pname);
return (E_USAGE);
}
}
if (optind < argc) {
warn(gettext("illegal argument -- %s\n"), argv[optind]);
(void) fprintf(stderr, gettext(USAGE), pname);
return (E_USAGE);
}
}
if (geteuid() != 0)
die(gettext("you must be root to use %s\n"), pname);
if (access(PATH_CONFIG, F_OK) == -1)
modified++;
if (dconf_open(&dc, PATH_DEVICE, PATH_CONFIG, dcmode) == -1)
return (E_ERROR);
for (optind = 1; optind < argc; optind++) {
while ((c = getopt(argc, argv, OPTS)) != (int)EOF) {
switch (c) {
case 'H':
dc.dc_headers = false;
break;
case 'c':
if (dconf_str2content(&dc, optarg) == -1)
return (E_USAGE);
modified++;
break;
case 'd':
if (dconf_str2device(&dc, optarg) == -1)
return (E_USAGE);
dflag++;
modified++;
break;
case 'e':
eflag++;
break;
case 'i':
if (chrooted) {
warn(gettext("-i and -r cannot be "
"used together\n"));
return (E_USAGE);
}
douuid++;
break;
case 'm':
minfstr = optarg;
break;
case 'n':
dc.dc_enable = DC_OFF;
modified++;
break;
case 'p':
dc.dc_parsable = true;
break;
case 's':
if (stat(optarg, &st) == -1 ||
!S_ISDIR(st.st_mode)) {
warn(gettext("%s is missing or not a "
"directory\n"), optarg);
return (E_USAGE);
}
if (dconf_str2savdir(&dc, optarg) == -1)
return (E_USAGE);
modified++;
break;
case 'y':
dc.dc_enable = DC_ON;
modified++;
break;
case 'z':
if (dconf_str2csave(&dc, optarg) == -1)
return (E_USAGE);
modified++;
break;
}
}
}
if (eflag) {
if (modified < 2 && douuid == 0 && chrooted == 0 &&
dcmode == DC_CURRENT && minfstr == NULL)
return (dconf_get_dumpsize(&dc) ? E_SUCCESS : E_ERROR);
else
die(gettext("-e cannot be used with other options\n"));
}
if (dc.dc_parsable) {
die(gettext("-p can only be used with -e\n"));
}
if (!dc.dc_headers) {
die(gettext("-H can only be used with -e\n"));
}
if (douuid)
return (dconf_write_uuid(&dc) ? E_SUCCESS : E_ERROR);
if (minfstr != NULL) {
if (minfree_compute(dc.dc_savdir, minfstr, &minf) == -1)
return (E_USAGE);
if (minfree_write(dc.dc_savdir, minf) == -1)
return (E_ERROR);
}
if (dcmode == DC_OVERRIDE) {
if (dconf_update(&dc, 0) == -1)
(void) dconf_getdev(&dc);
if (dc.dc_readonly)
warn(gettext("kernel settings updated, but "
"%s is read-only\n"), PATH_CONFIG);
else if (dconf_write(&dc) == -1)
return (E_ERROR);
} else if (modified) {
if (dc.dc_readonly) {
warn(gettext("failed to update settings: %s is "
"read-only\n"), PATH_CONFIG);
return (E_ERROR);
}
if (dconf_update(&dc, dflag) == -1 ||
dconf_write(&dc) == -1)
return (E_ERROR);
}
if (dcmode == DC_CURRENT)
dconf_print(&dc, stdout);
if (dconf_close(&dc) == -1)
warn(gettext("failed to close configuration file"));
return (E_SUCCESS);
}