aboutsummaryrefslogtreecommitdiff
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
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.
-rw-r--r--src/backup.c2
-rw-r--r--src/config.c406
-rw-r--r--src/diskio.c5
-rw-r--r--src/wydawca.c12
-rw-r--r--src/wydawca.h25
-rw-r--r--tests/etc/wydawca.rcin2
-rw-r--r--tests/upload-dry.at3
7 files changed, 294 insertions, 161 deletions
diff --git a/src/backup.c b/src/backup.c
index 64902f7..0bf6c63 100644
--- a/src/backup.c
+++ b/src/backup.c
@@ -20,3 +20,3 @@ char const *simple_backup_suffix = "~";
-static const char *
+const char *
split_filename(char const *file, char **pdir)
diff --git a/src/config.c b/src/config.c
index ca0d750..3ad263d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -19,2 +19,4 @@
+static int create_directories;
+static struct directory_metadata global_directory_metadata;
@@ -600,2 +602,136 @@ static struct grecs_keyword syslog_kw[] = {
+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[] = {
@@ -656,2 +792,14 @@ static struct grecs_keyword archive_kw[] = {
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 }
@@ -979,136 +1127,2 @@ cb_url(enum grecs_callback_command cmd, grecs_node_t *node,
}
-
-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;
-}
@@ -1272,2 +1286,3 @@ cb_user(enum grecs_callback_command cmd, grecs_node_t *node,
wydawca_gid = pw->pw_gid;
+ wydawca_runas = 1;
return 0;
@@ -1319,2 +1334,3 @@ cb_supp_groups(enum grecs_callback_command cmd, grecs_node_t *node,
}
+ wydawca_runas = 1;
return 0;
@@ -1532,2 +1548,20 @@ static struct grecs_keyword wydawca_kw[] = {
+ { "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}
@@ -1572,3 +1606,3 @@ create_spool_dir(struct spool *spool, char const *dir,
int rc;
-
+
if ((rc = stat(dir, &st)) != 0) {
@@ -1578,4 +1612,14 @@ create_spool_dir(struct spool *spool, char const *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)) {
@@ -1590,2 +1634,5 @@ create_spool_dir(struct spool *spool, char const *dir,
+ if (wy_dry_run)
+ return 0;
+
if ((meta->flags & METADATA_OWNER)
@@ -1595,5 +1642,11 @@ create_spool_dir(struct spool *spool, char const *dir,
&& 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;
+ }
}
@@ -1602,5 +1655,11 @@ create_spool_dir(struct spool *spool, char const *dir,
&& 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;
+ }
}
@@ -1610,2 +1669,33 @@ create_spool_dir(struct spool *spool, char const *dir,
+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
@@ -1613,10 +1703,38 @@ 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;
diff --git a/src/diskio.c b/src/diskio.c
index 6bed916..00ac097 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -88,5 +88,8 @@ create_hierarchy(char const *dir, size_t baselen)
*p = 0;
+ rc = create_hierarchy(dir, baselen);
+ } else {
+ /* Current directory always exists */
+ rc = 0;
}
- rc = create_hierarchy(dir, baselen);
if (rc == 0) {
diff --git a/src/wydawca.c b/src/wydawca.c
index 0803aa7..4bd3620 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -25,2 +25,4 @@ size_t wydawca_supp_groupc;
gid_t *wydawca_supp_groups;
+int wydawca_runas; /* Set to 1 if any of the four variables above have
+ been set in the configuration */
char *conffile = SYSCONFDIR "/wydawca.rc";
@@ -349,2 +351,5 @@ main(int argc, char **argv)
+ wydawca_uid = getuid();
+ wydawca_gid = getgid();
+
argv += optind;
@@ -410,5 +415,6 @@ main(int argc, char **argv)
}
- } else if (wydawca_userprivs(wydawca_uid, wydawca_gid,
- wydawca_supp_groups,
- wydawca_supp_groupc))
+ } else if (wydawca_runas
+ && wydawca_userprivs(wydawca_uid, wydawca_gid,
+ wydawca_supp_groups,
+ wydawca_supp_groupc))
exit(EX_UNAVAILABLE);
diff --git a/src/wydawca.h b/src/wydawca.h
index cfd3ae2..581a7fe 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -120,2 +120,14 @@ extern char const *simple_backup_suffix;
char *find_backup_file_name(char const *, enum backup_type);
+const char *split_filename(char const *file, char **pdir);
+
+#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;
+};
@@ -137,2 +149,3 @@ struct archive_descr {
type == archive_directory */
+ struct directory_metadata metadata; /* Directory metadata */
};
@@ -218,13 +231,2 @@ struct virt_tab {
-#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
@@ -346,2 +348,3 @@ extern size_t wydawca_supp_groupc;
extern gid_t *wydawca_supp_groups;
+extern int wydawca_runas;
extern char *conffile; /* Configuration file name */
diff --git a/tests/etc/wydawca.rcin b/tests/etc/wydawca.rcin
index a655537..369ddc2 100644
--- a/tests/etc/wydawca.rcin
+++ b/tests/etc/wydawca.rcin
@@ -65,2 +65,4 @@ dictionary project-uploader {
+create-directories yes;
+
spool test {
diff --git a/tests/upload-dry.at b/tests/upload-dry.at
index 77a3212..bda0370 100644
--- a/tests/upload-dry.at
+++ b/tests/upload-dry.at
@@ -19,3 +19,4 @@ AT_SETUP([Dry-run upload])
AT_DATA([template],
-[wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
+[wydawca: [[DEBUG]] test: creating archive directory
+wydawca: [[NOTICE]] AT_PACKAGE_TARNAME (AT_PACKAGE_NAME AT_PACKAGE_VERSION) started
wydawca: [[DEBUG]] @WY_SRC@/ok -> @WY_DST@

Return to:

Send suggestions and report system problems to the System administrator.