/* This file is part of GDBM, the GNU data base manager.
Copyright (C) 2011-2021 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GDBM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDBM. If not, see . */
# include "autoconf.h"
# include "gdbm.h"
# include "gdbmapp.h"
# include "gdbmdefs.h"
# include
# include
int replace = 0;
int meta_mask = 0;
int no_meta_option;
int mode;
uid_t owner_uid;
gid_t owner_gid;
char *parseopt_program_doc = N_("load a GDBM database from a file");
char *parseopt_program_args = N_("FILE [DB_FILE]");
struct gdbm_option optab[] = {
{ 'r', "replace", NULL, N_("replace records in the existing database") },
{ 'm', "mode", N_("MODE"), N_("set file mode") },
{ 'u', "user", N_("NAME|UID[:NAME|GID]"), N_("set file owner") },
{ 'n', "no-meta", NULL, N_("do not attempt to set file meta-data") },
{ 'M', "mmap", NULL, N_("use memory mapping") },
{ 'c', "cache-size", N_("NUM"), N_("set the cache size") },
{ 'b', "block-size", N_("NUM"), N_("set the block size") },
{ 0 }
};
static int
set_meta_info (GDBM_FILE dbf)
{
if (meta_mask)
{
int fd = gdbm_fdesc (dbf);
if (meta_mask & GDBM_META_MASK_OWNER)
{
if (fchown (fd, owner_uid, owner_gid))
{
GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE);
return 1;
}
}
if ((meta_mask & GDBM_META_MASK_MODE) && fchmod (fd, mode))
{
GDBM_SET_ERRNO (dbf, GDBM_ERR_FILE_OWNER, FALSE);
return 1;
}
}
return 0;
}
static int
get_int (const char *arg)
{
char *p;
long n;
errno = 0;
n = strtol (arg, &p, 0);
if (*p)
{
error (_("invalid number: %s"), arg);
exit (EXIT_USAGE);
}
if (errno)
{
error (_("invalid number: %s: %s"), arg, strerror (errno));
exit (EXIT_USAGE);
}
return n;
}
int
main (int argc, char **argv)
{
GDBM_FILE dbf = NULL;
int rc, opt;
char *dbname, *filename;
FILE *fp;
unsigned long err_line, n;
char *end;
int oflags = GDBM_NEWDB|GDBM_NOMMAP;
int cache_size = 0;
int block_size = 0;
#ifdef HAVE_SETLOCALE
setlocale (LC_ALL, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
set_progname (argv[0]);
for (opt = parseopt_first (argc, argv, optab);
opt != EOF;
opt = parseopt_next ())
{
switch (opt)
{
case 'b':
block_size = get_int (optarg);
break;
case 'c':
cache_size = get_int (optarg);
break;
case 'm':
{
errno = 0;
n = strtoul (optarg, &end, 8);
if (*end == 0 && errno == 0)
{
mode = n & 0777;
meta_mask |= GDBM_META_MASK_MODE;
}
else
{
error ("%s", _("invalid octal number"));
exit (EXIT_USAGE);
}
}
break;
case 'u':
{
size_t len;
struct passwd *pw;
len = strcspn (optarg, ".:");
if (optarg[len])
optarg[len++] = 0;
pw = getpwnam (optarg);
if (pw)
owner_uid = pw->pw_uid;
else
{
errno = 0;
n = strtoul (optarg, &end, 10);
if (*end == 0 && errno == 0)
owner_uid = n;
else
{
error (_("invalid user name: %s"), optarg);
exit (EXIT_USAGE);
}
}
if (optarg[len])
{
char *grname = optarg + len;
struct group *gr = getgrnam (grname);
if (gr)
owner_gid = gr->gr_gid;
else
{
errno = 0;
n = strtoul (grname, &end, 10);
if (*end == 0 && errno == 0)
owner_gid = n;
else
{
error (_("invalid group name: %s"), grname);
exit (EXIT_USAGE);
}
}
}
else
{
if (!pw)
{
pw = getpwuid (owner_uid);
if (!pw)
{
error (_("no such UID: %lu"), (unsigned long)owner_uid);
exit (EXIT_USAGE);
}
}
owner_gid = pw->pw_gid;
}
meta_mask |= GDBM_META_MASK_OWNER;
}
break;
case 'r':
replace = 1;
break;
case 'n':
no_meta_option = 1;
break;
case 'M':
oflags &= ~GDBM_NOMMAP;
break;
default:
error (_("unknown option"));
exit (EXIT_USAGE);
}
}
argc -= optind;
argv += optind;
if (argc == 0)
{
parseopt_print_help ();
exit (EXIT_OK);
}
if (argc > 2)
{
error (_("too many arguments; try `%s -h' for more info"), progname);
exit (EXIT_USAGE);
}
filename = argv[0];
if (argc == 2)
dbname = argv[1];
else
dbname = NULL;
if (strcmp (filename, "-") == 0)
{
filename = "";
fp = stdin;
}
else
{
fp = fopen (filename, "r");
if (!fp)
{
sys_perror (errno, _("cannot open %s"), filename);
exit (EXIT_FATAL);
}
}
if (dbname)
{
dbf = gdbm_open (dbname, block_size, oflags, 0600, NULL);
if (!dbf)
{
gdbm_perror (_("gdbm_open failed"));
exit (EXIT_FATAL);
}
if (cache_size &&
gdbm_setopt (dbf, GDBM_SETCACHESIZE, &cache_size, sizeof (int)) == -1)
error (_("gdbm_setopt failed: %s"), gdbm_strerror (gdbm_errno));
}
rc = gdbm_load_from_file (&dbf, fp, replace,
no_meta_option ?
(GDBM_META_MASK_MODE | GDBM_META_MASK_OWNER) :
meta_mask,
&err_line);
if (rc)
{
switch (gdbm_errno)
{
case GDBM_ERR_FILE_OWNER:
case GDBM_ERR_FILE_MODE:
error (_("error restoring metadata: %s (%s)"),
gdbm_strerror (gdbm_errno), strerror (errno));
rc = EXIT_MILD;
break;
default:
if (err_line)
gdbm_perror ("%s:%lu", filename, err_line);
else
gdbm_perror (_("cannot load from %s"), filename);
rc = EXIT_FATAL;
}
}
if (dbf)
{
if (!no_meta_option && set_meta_info (dbf))
{
error (_("error restoring metadata: %s (%s)"),
gdbm_strerror (gdbm_errno), strerror (errno));
rc = EXIT_MILD;
}
if (!dbname)
{
if (gdbm_setopt (dbf, GDBM_GETDBNAME, &dbname, sizeof (dbname)))
gdbm_perror (_("gdbm_setopt failed"));
else
{
printf ("%s: created %s\n", progname, dbname);
free (dbname);
}
}
gdbm_close (dbf);
}
exit (rc);
}