summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org>2019-07-19 11:39:55 (GMT)
committer Sergey Poznyakoff <gray@gnu.org>2019-07-19 11:48:24 (GMT)
commitaf538cc27228edf816edea1bf52c84b5bb4f8720 (patch) (side-by-side diff)
tree070e83b5149a53b84b63e707c6b2f108d911223e
parentf6657a46e2422d903d62565868f77c430a612a42 (diff)
downloadwydawca-af538cc27228edf816edea1bf52c84b5bb4f8720.tar.gz
wydawca-af538cc27228edf816edea1bf52c84b5bb4f8720.tar.bz2
Create source directories if necessary
Missing source directories are created if at least one of the source-mode or source-owner statements are present. If the directory already exists, wydawca makes sure its ownership and mode matches those requested by these statements. The syntax of the two new statements is: source-mode OCTAL; source-owner USER GROUP; USER and GROUP can be either symbolic user and group names or numeric UID and GID. In the latter case, the number can be preceded by a plus sign.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/config.c220
-rw-r--r--src/wydawca.h12
2 files changed, 218 insertions, 14 deletions
diff --git a/src/config.c b/src/config.c
index 692dbd5..eb5f7f5 100644
--- a/src/config.c
+++ b/src/config.c
@@ -1,6 +1,5 @@
/* wydawca - automatic release submission daemon
- Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2017, 2019
- Sergey Poznyakoff
+ Copyright (C) 2007-2019 Sergey Poznyakoff
Wydawca is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -978,6 +977,140 @@ 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"),
@@ -989,6 +1122,18 @@ static struct grecs_keyword spool_kw[] = {
{ "source", N_("dir"), N_("Source directory"),
grecs_type_string, GRECS_CONST,
NULL, offsetof(struct spool, source_dir) },
+ { "source-mode",
+ N_("mode: octal"),
+ N_("mode for the source directory"),
+ grecs_type_string, GRECS_CONST,
+ NULL, offsetof(struct spool, source_metadata),
+ cb_metadata_mode },
+ { "source-owner",
+ N_("uid: name-or-uid> <gid: name-or-gid"),
+ N_("owner user and group for the source directory"),
+ grecs_type_string, GRECS_CONST,
+ NULL, offsetof(struct spool, source_metadata),
+ cb_metadata_owner },
{ "destination", N_("dir"), N_("Destination directory"),
grecs_type_string, GRECS_CONST,
NULL, offsetof(struct spool, dest_url),
@@ -1043,6 +1188,7 @@ cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
for (i = 0; i < NITEMS(spool->dictionary); i++)
spool->dictionary[i] = default_dictionary[i];
spool->archive = default_archive_descr;
+ spool->source_metadata.flags = METADATA_NONE;
*pdata = spool;
break;
@@ -1052,17 +1198,8 @@ cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
if (!spool->source_dir) {
grecs_error(locus, 0, _("source is not given"));
rc = 1;
- } else if (test_dir(spool->source_dir, &ec)) {
- if (ec)
- grecs_error(locus, ec, _("cannot access %s"),
- spool->source_dir);
- else
- grecs_error(locus, 0,
- _("%s is not a directory"),
- spool->source_dir);
- rc = 1;
}
-
+
if (!spool->dest_url) {
grecs_error(locus, 0, _("destination is not given"));
rc = 1;
@@ -1414,11 +1551,62 @@ config_init()
default_dictionary[i] = dictionary_new(i, dictionary_builtin);
}
+static int
+create_source(struct spool *spool, void *data)
+{
+ struct stat st;
+ int rc;
+
+ if ((rc = stat(spool->source_dir, &st)) != 0) {
+ if (errno != ENOENT) {
+ grecs_error(NULL, errno, _("%s: cannot stat %s"),
+ spool->tag, spool->source_dir);
+ *(int*)data = 1;
+ return 0;
+ } else {
+ wy_debug(1, (_("creating spool source directory %s"),
+ spool->source_dir));
+ if (create_hierarchy(spool->source_dir, 0)) {
+ *(int*)data = 1;
+ return 0;
+ }
+ }
+ } else if (!S_ISDIR(st.st_mode)) {
+ grecs_error(NULL, errno, _("%s: %s is not a directory"),
+ spool->tag, spool->source_dir);
+ *(int*)data = 1;
+ return 0;
+ }
+
+ if ((spool->source_metadata.flags & METADATA_OWNER)
+ && (rc
+ || st.st_uid != spool->source_metadata.uid
+ || st.st_gid != spool->source_metadata.gid)
+ && chown(spool->source_dir,
+ spool->source_metadata.uid,
+ spool->source_metadata.gid)) {
+ grecs_error(NULL, errno, _("%s: can't chown %s"),
+ spool->tag, spool->source_dir);
+ *(int*)data = 1;
+ return 0;
+ }
+ if ((spool->source_metadata.flags & METADATA_MODE)
+ && (rc || (st.st_mode & 07777) != spool->source_metadata.mode)
+ && chmod(spool->source_dir, spool->source_metadata.mode)) {
+ grecs_error(NULL, errno, _("%s: can't chmod %s"),
+ spool->tag, spool->source_dir);
+ *(int*)data = 1;
+ }
+
+ return 0;
+}
+
void
config_finish(struct grecs_node *tree)
{
struct grecs_node *p;
-
+ int err;
+
if (grecs_tree_process(tree, wydawca_kw))
exit(EX_CONFIG);
for (p = tree->down; p; p = p->next) {
@@ -1431,5 +1619,9 @@ config_finish(struct grecs_node *tree)
grecs_error(&p->v.value->locus, 0,
_("unknown module"));
}
- }
+ }
+
+ err = 0;
+ if (for_each_spool(create_source, &err) || err)
+ exit(EX_CONFIG);
}
diff --git a/src/wydawca.h b/src/wydawca.h
index b448904..1001694 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -215,6 +215,17 @@ struct virt_tab {
const char *file_name);
};
+#define METADATA_NONE 0
+#define METADATA_MODE 0x1
+#define METADATA_OWNER 0x2
+
+struct directory_metadata {
+ int flags;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+};
+
/* An upload spool. This structure contains all data necessary for releasing
files from source to destination */
struct spool {
@@ -222,6 +233,7 @@ struct spool {
struct grecs_list *aliases;
char *url; /* Download URL */
char *source_dir; /* Source directory */
+ struct directory_metadata source_metadata;
wy_url_t dest_url; /* Destination URL */
const char *dest_dir; /* Directory part of the above */
struct virt_tab vtab; /* Virtual method table */

Return to:

Send suggestions and report system problems to the System administrator.