aboutsummaryrefslogtreecommitdiff
path: root/src/config.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-07-20 14:55:38 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-07-20 14:55:38 +0300
commitf338532e1ae9b79c666d2ff66cc8be33ab7e5759 (patch)
treec67afd62dd2e7ac0eec28c95fc8d9af71bf0130c /src/config.c
parentdd9d9c1240774e21c7eb50052225ff1e4cc376ee (diff)
downloadwydawca-f338532e1ae9b79c666d2ff66cc8be33ab7e5759.tar.gz
wydawca-f338532e1ae9b79c666d2ff66cc8be33ab7e5759.tar.bz2
Create backup storage directories.
Any spool directories are actually created only if create-directories yes; appears in the configuration file. The global directory-mode and directory-owner statements provide global defaults for the directory metadata. These two keywords can also appear within a spool.archive block. * src/backup.c (split_filename): Change to extern. * src/config.c: Global directory-mode and directory-owner statements. New global statement create-directories. spool.archive.directory-mode and directory-owner statements. (cb_user,cb_supp_groups): Set wydawca_runas. (create_spool_dir): Don't mkdir unless create-directories was set. Honor wy_dry_run. Don't bail out on EPERM wheb uid is not 0. (create_spool_dirs): Compute effective metadata. Create archive directories. * src/diskio.c (create_hierarchy): Fix stack overflow if baselen==0. * src/wydawca.c (wydawca_runas): New global. (main): Intitialize wydawca_uid and wydawca_gid to current values. Run wydawca_userprivs only if wydawca_runas is set. * src/wydawca.h (archive_descr) <metadata>: New member. (wydawca_runas): New extern. * tests/etc/wydawca.rcin: Add create-directories statement. * tests/upload-dry.at: Fix expected output.
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c406
1 files changed, 262 insertions, 144 deletions
diff --git a/src/config.c b/src/config.c
index ca0d750..3ad263d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -17,6 +17,8 @@
#include "wydawca.h"
#include "sql.h"
+static int create_directories;
+static struct directory_metadata global_directory_metadata;
struct keyword {
char *name;
@@ -598,6 +600,140 @@ static struct grecs_keyword syslog_kw[] = {
{ NULL },
};
+static int
+cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value;
+ unsigned long m;
+ char *p;
+ struct directory_metadata *mp = varptr;
+
+ if (wy_assert_string_arg(locus, cmd, value))
+ return 1;
+ m = strtoul(value->v.string, &p, 8);
+ if (*p) {
+ grecs_error(&value->locus, 0, _("invalid file mode (near %s)"),
+ p);
+ return 1;
+ }
+ if (m & ~07777) {
+ grecs_error(&value->locus, 0, "%s",
+ _("file mode out of range"));
+ return 1;
+ }
+ mp->flags |= METADATA_MODE;
+ mp->mode = m;
+ return 0;
+}
+
+static int
+arg_to_uid(grecs_value_t *value, uid_t *uid)
+{
+ char const *user = value->v.string;
+ unsigned long n;
+ char *p;
+ struct passwd *pw;
+
+ if (user[0] == '+') {
+ user++;
+
+ errno = 0;
+ n = strtoul(user, &p, 10);
+ if (errno || *p) {
+ grecs_error(&value->locus, 0,
+ _("invalid user ID: %s"), user);
+ return 1;
+ }
+ *uid = n;
+ return 0;
+ } else if (isdigit(user[0])) {
+ errno = 0;
+ n = strtoul(user, &p, 10);
+ if (errno) {
+ grecs_error(&value->locus, 0,
+ _("invalid user ID: %s"), user);
+ return 1;
+ }
+ if (*p == 0) {
+ *uid = 0;
+ return 0;
+ }
+ }
+ pw = getpwnam(user);
+ if (!pw) {
+ grecs_error(&value->locus, 0,
+ _("no such user: %s"), user);
+ return 1;
+ }
+ *uid = pw->pw_uid;
+ return 0;
+}
+
+static int
+arg_to_gid(grecs_value_t *value, gid_t *gid)
+{
+ char const *group = value->v.string;
+ unsigned long n;
+ char *p;
+ struct group *grp;
+
+ if (group[0] == '+') {
+ group++;
+
+ errno = 0;
+ n = strtoul(group, &p, 10);
+ if (errno || *p) {
+ grecs_error(&value->locus, 0,
+ _("invalid GID: %s"), group);
+ return 1;
+ }
+ *gid = n;
+ return 0;
+ } else if (isdigit(group[0])) {
+ errno = 0;
+ n = strtoul(group, &p, 10);
+ if (errno) {
+ grecs_error(&value->locus, 0,
+ _("invalid GID: %s"), group);
+ return 1;
+ }
+ if (*p == 0) {
+ *gid = 0;
+ return 0;
+ }
+ }
+ grp = getgrnam(group);
+ if (!grp) {
+ grecs_error(&value->locus, 0,
+ _("no such group: %s"), group);
+ return 1;
+ }
+ *gid = grp->gr_gid;
+ return 0;
+}
+
+static int
+cb_metadata_owner(enum grecs_callback_command cmd, grecs_node_t *node,
+ void *varptr, void *cb_data)
+{
+ grecs_locus_t *locus = &node->locus;
+ grecs_value_t *value = node->v.value, *uval, *gval;
+ struct directory_metadata *mp = varptr;
+
+ if (!(uval = get_arg(value, 0, GRECS_TYPE_STRING)))
+ return 1;
+ if (!(gval = get_arg(value, 1, GRECS_TYPE_STRING)))
+ return 1;
+ if (arg_to_uid(uval, &mp->uid))
+ return 1;
+ if (arg_to_gid(gval, &mp->gid))
+ return 1;
+ mp->flags |= METADATA_OWNER;
+ return 0;
+}
+
static struct keyword backup_tab[] = {
{ "none", no_backups },
{ "off", no_backups },
@@ -654,6 +790,18 @@ static struct grecs_keyword archive_kw[] = {
grecs_type_string, GRECS_CONST,
NULL, offsetof(struct archive_descr, backup_type),
cb_backup },
+ { "directory-mode",
+ N_("mode: octal"),
+ N_("mode for the archive directory"),
+ grecs_type_string, GRECS_CONST,
+ NULL, offsetof(struct archive_descr, metadata),
+ cb_metadata_mode },
+ { "directory-owner",
+ N_("uid: name-or-uid> <gid: name-or-gid"),
+ N_("owner user and group for the archive directory"),
+ grecs_type_string, GRECS_CONST,
+ NULL, offsetof(struct archive_descr, metadata),
+ cb_metadata_owner },
{ NULL }
};
@@ -977,140 +1125,6 @@ cb_url(enum grecs_callback_command cmd, grecs_node_t *node,
*purl = url;
return 0;
}
-
-static int
-cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t *node,
- void *varptr, void *cb_data)
-{
- grecs_locus_t *locus = &node->locus;
- grecs_value_t *value = node->v.value;
- unsigned long m;
- char *p;
- struct directory_metadata *mp = varptr;
-
- if (wy_assert_string_arg(locus, cmd, value))
- return 1;
- m = strtoul(value->v.string, &p, 8);
- if (*p) {
- grecs_error(&value->locus, 0, _("invalid file mode (near %s)"),
- p);
- return 1;
- }
- if (m & ~07777) {
- grecs_error(&value->locus, 0, "%s",
- _("file mode out of range"));
- return 1;
- }
- mp->flags |= METADATA_MODE;
- mp->mode = m;
- return 0;
-}
-
-static int
-arg_to_uid(grecs_value_t *value, uid_t *uid)
-{
- char const *user = value->v.string;
- unsigned long n;
- char *p;
- struct passwd *pw;
-
- if (user[0] == '+') {
- user++;
-
- errno = 0;
- n = strtoul(user, &p, 10);
- if (errno || *p) {
- grecs_error(&value->locus, 0,
- _("invalid user ID: %s"), user);
- return 1;
- }
- *uid = n;
- return 0;
- } else if (isdigit(user[0])) {
- errno = 0;
- n = strtoul(user, &p, 10);
- if (errno) {
- grecs_error(&value->locus, 0,
- _("invalid user ID: %s"), user);
- return 1;
- }
- if (*p == 0) {
- *uid = 0;
- return 0;
- }
- }
- pw = getpwnam(user);
- if (!pw) {
- grecs_error(&value->locus, 0,
- _("no such user: %s"), user);
- return 1;
- }
- *uid = pw->pw_uid;
- return 0;
-}
-
-static int
-arg_to_gid(grecs_value_t *value, gid_t *gid)
-{
- char const *group = value->v.string;
- unsigned long n;
- char *p;
- struct group *grp;
-
- if (group[0] == '+') {
- group++;
-
- errno = 0;
- n = strtoul(group, &p, 10);
- if (errno || *p) {
- grecs_error(&value->locus, 0,
- _("invalid GID: %s"), group);
- return 1;
- }
- *gid = n;
- return 0;
- } else if (isdigit(group[0])) {
- errno = 0;
- n = strtoul(group, &p, 10);
- if (errno) {
- grecs_error(&value->locus, 0,
- _("invalid GID: %s"), group);
- return 1;
- }
- if (*p == 0) {
- *gid = 0;
- return 0;
- }
- }
- grp = getgrnam(group);
- if (!grp) {
- grecs_error(&value->locus, 0,
- _("no such group: %s"), group);
- return 1;
- }
- *gid = grp->gr_gid;
- return 0;
-}
-
-static int
-cb_metadata_owner(enum grecs_callback_command cmd, grecs_node_t *node,
- void *varptr, void *cb_data)
-{
- grecs_locus_t *locus = &node->locus;
- grecs_value_t *value = node->v.value, *uval, *gval;
- struct directory_metadata *mp = varptr;
-
- if (!(uval = get_arg(value, 0, GRECS_TYPE_STRING)))
- return 1;
- if (!(gval = get_arg(value, 1, GRECS_TYPE_STRING)))
- return 1;
- if (arg_to_uid(uval, &mp->uid))
- return 1;
- if (arg_to_gid(gval, &mp->gid))
- return 1;
- mp->flags |= METADATA_OWNER;
- return 0;
-}
static struct grecs_keyword spool_kw[] = {
{ "url", N_("arg"), N_("URL corresponding to this spool"),
@@ -1270,6 +1284,7 @@ cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
wydawca_uid = pw->pw_uid;
wydawca_gid = pw->pw_gid;
+ wydawca_runas = 1;
return 0;
}
@@ -1317,6 +1332,7 @@ cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t *node,
wydawca_supp_groups[i] = grp->gr_gid;
}
}
+ wydawca_runas = 1;
return 0;
}
@@ -1530,6 +1546,24 @@ static struct grecs_keyword wydawca_kw[] = {
{ "gpg-homedir", NULL, N_("GPG home directory"),
grecs_type_string, GRECS_CONST, &wy_gpg_homedir },
+ { "create-directories", NULL,
+ N_("Create missing directories."),
+ grecs_type_bool, GRECS_DFLT, &create_directories },
+
+ { "directory-mode",
+ N_("mode: octal"),
+ N_("mode for created directories"),
+ grecs_type_string, GRECS_CONST,
+ &global_directory_metadata, 0,
+ cb_metadata_mode },
+
+ { "directory-owner",
+ N_("uid: name-or-uid> <gid: name-or-gid"),
+ N_("owner user and group for created directory"),
+ grecs_type_string, GRECS_CONST,
+ &global_directory_metadata, 0,
+ cb_metadata_owner },
+
{NULL}
};
@@ -1570,14 +1604,24 @@ create_spool_dir(struct spool *spool, char const *dir,
{
struct stat st;
int rc;
-
+
if ((rc = stat(dir, &st)) != 0) {
if (errno != ENOENT) {
grecs_error(NULL, errno, _("%s: cannot stat %s %s"),
spool->tag, descr, dir);
return 1;
+ } else if (!create_directories) {
+ grecs_error(NULL, 0,
+ _("%s: %s %s does not exist"),
+ spool->tag, descr, dir);
+ grecs_error(NULL, 0,
+ "%s",
+ _("use \"create-directories yes\" t create it"));
+ return 1;
} else {
wy_debug(1, (_("%s: creating %s"), spool->tag, descr));
+ if (wy_dry_run)
+ return 0;
if (create_hierarchy(dir, 0)) {
return 1;
}
@@ -1588,37 +1632,111 @@ create_spool_dir(struct spool *spool, char const *dir,
return 1;
}
+ if (wy_dry_run)
+ return 0;
+
if ((meta->flags & METADATA_OWNER)
&& (rc
|| st.st_uid != meta->uid
|| st.st_gid != meta->gid)
&& chown(dir, meta->uid, meta->gid)) {
- grecs_error(NULL, errno, _("%s: can't chown %s %s"),
- spool->tag, descr, dir);
- return 1;
+ if (errno == EPERM && getuid() != 0) {
+ wy_log(LOG_WARNING,
+ _("%s: can't chown %s %s; not running as root"),
+ spool->tag, descr, dir);
+ } else {
+ grecs_error(NULL, errno, _("%s: can't chown %s %s"),
+ spool->tag, descr, dir);
+ return 1;
+ }
}
if ((meta->flags & METADATA_MODE)
&& (rc || (st.st_mode & 07777) != meta->mode)
&& chmod(dir, meta->mode)) {
- grecs_error(NULL, errno, _("%s: can't chmod %s %s"),
- spool->tag, descr, dir);
- return 1;
+ if (errno == EPERM && getuid() != 0) {
+ wy_log(LOG_WARNING,
+ _("%s: can't chmod %s %s; not running as root"),
+ spool->tag, descr, dir);
+ } else {
+ grecs_error(NULL, errno, _("%s: can't chmod %s %s"),
+ spool->tag, descr, dir);
+ return 1;
+ }
}
return 0;
}
+static struct directory_metadata *
+effective_metadata(struct directory_metadata *storage,
+ struct directory_metadata const *meta)
+{
+ if (create_directories) {
+ if (global_directory_metadata.flags) {
+ *storage = global_directory_metadata;
+ } else {
+ storage->mode = 0755;
+ storage->uid = wydawca_uid;
+ storage->gid = wydawca_gid;
+ storage->flags = METADATA_MODE|METADATA_OWNER;
+ }
+
+ if (meta->flags & METADATA_MODE) {
+ storage->mode = meta->mode;
+ storage->flags |= METADATA_MODE;
+ }
+
+ if (meta->flags & METADATA_OWNER) {
+ storage->uid = meta->uid;
+ storage->gid = meta->gid;
+ storage->flags |= METADATA_OWNER;
+ }
+ } else {
+ storage->flags = 0;
+ }
+
+ return storage;
+}
+
static int
create_spool_dirs(struct spool *spool, void *data)
{
- if (create_spool_dir(spool, spool->source_dir, &spool->source_metadata,
+ struct directory_metadata dm;
+
+ if (create_spool_dir(spool, spool->source_dir,
+ effective_metadata(&dm, &spool->source_metadata),
_("source directory")))
*(int*)data = 1;
- if (!wy_url_is_local(spool->dest_url)
+ if (wy_url_is_local(spool->dest_url)
&& create_spool_dir(spool, spool->dest_dir,
- &spool->dest_metadata,
+ effective_metadata(&dm, &spool->dest_metadata),
_("destination directory")))
*(int*)data = 1;
+
+ switch (spool->archive.type) {
+ case archive_none:
+ break;
+
+ case archive_tar: {
+ char *dir;
+ split_filename(spool->archive.name, &dir);
+ if (create_spool_dir(spool, dir,
+ effective_metadata(&dm,
+ &spool->archive.metadata),
+ _("archive directory")))
+ *(int*)data = 1;
+ free(dir);
+ }
+ break;
+
+ case archive_directory:
+ if (create_spool_dir(spool, spool->archive.name,
+ effective_metadata(&dm,
+ &spool->archive.metadata),
+ _("archive directory")))
+ *(int*)data = 1;
+ break;
+ }
return 0;
}

Return to:

Send suggestions and report system problems to the System administrator.