aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2019-07-19 14:39:55 +0300
committerSergey Poznyakoff <gray@gnu.org>2019-07-19 14:48:24 +0300
commitaf538cc27228edf816edea1bf52c84b5bb4f8720 (patch)
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.
-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 @@
1/* wydawca - automatic release submission daemon 1/* wydawca - automatic release submission daemon
2 Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2017, 2019 2 Copyright (C) 2007-2019 Sergey Poznyakoff
3 Sergey Poznyakoff
4 3
5 Wydawca is free software; you can redistribute it and/or modify it 4 Wydawca is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the 5 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,
978 *purl = url; 977 *purl = url;
979 return 0; 978 return 0;
980} 979}
980
981static int
982cb_metadata_mode(enum grecs_callback_command cmd, grecs_node_t *node,
983 void *varptr, void *cb_data)
984{
985 grecs_locus_t *locus = &node->locus;
986 grecs_value_t *value = node->v.value;
987 unsigned long m;
988 char *p;
989 struct directory_metadata *mp = varptr;
990
991 if (wy_assert_string_arg(locus, cmd, value))
992 return 1;
993 m = strtoul(value->v.string, &p, 8);
994 if (*p) {
995 grecs_error(&value->locus, 0, _("invalid file mode (near %s)"),
996 p);
997 return 1;
998 }
999 if (m & ~07777) {
1000 grecs_error(&value->locus, 0, "%s",
1001 _("file mode out of range"));
1002 return 1;
1003 }
1004 mp->flags |= METADATA_MODE;
1005 mp->mode = m;
1006 return 0;
1007}
1008
1009static int
1010arg_to_uid(grecs_value_t *value, uid_t *uid)
1011{
1012 char const *user = value->v.string;
1013 unsigned long n;
1014 char *p;
1015 struct passwd *pw;
1016
1017 if (user[0] == '+') {
1018 user++;
1019
1020 errno = 0;
1021 n = strtoul(user, &p, 10);
1022 if (errno || *p) {
1023 grecs_error(&value->locus, 0,
1024 _("invalid user ID: %s"), user);
1025 return 1;
1026 }
1027 *uid = n;
1028 return 0;
1029 } else if (isdigit(user[0])) {
1030 errno = 0;
1031 n = strtoul(user, &p, 10);
1032 if (errno) {
1033 grecs_error(&value->locus, 0,
1034 _("invalid user ID: %s"), user);
1035 return 1;
1036 }
1037 if (*p == 0) {
1038 *uid = 0;
1039 return 0;
1040 }
1041 }
1042 pw = getpwnam(user);
1043 if (!pw) {
1044 grecs_error(&value->locus, 0,
1045 _("no such user: %s"), user);
1046 return 1;
1047 }
1048 *uid = pw->pw_uid;
1049 return 0;
1050}
1051
1052static int
1053arg_to_gid(grecs_value_t *value, gid_t *gid)
1054{
1055 char const *group = value->v.string;
1056 unsigned long n;
1057 char *p;
1058 struct group *grp;
1059
1060 if (group[0] == '+') {
1061 group++;
1062
1063 errno = 0;
1064 n = strtoul(group, &p, 10);
1065 if (errno || *p) {
1066 grecs_error(&value->locus, 0,
1067 _("invalid GID: %s"), group);
1068 return 1;
1069 }
1070 *gid = n;
1071 return 0;
1072 } else if (isdigit(group[0])) {
1073 errno = 0;
1074 n = strtoul(group, &p, 10);
1075 if (errno) {
1076 grecs_error(&value->locus, 0,
1077 _("invalid GID: %s"), group);
1078 return 1;
1079 }
1080 if (*p == 0) {
1081 *gid = 0;
1082 return 0;
1083 }
1084 }
1085 grp = getgrnam(group);
1086 if (!grp) {
1087 grecs_error(&value->locus, 0,
1088 _("no such group: %s"), group);
1089 return 1;
1090 }
1091 *gid = grp->gr_gid;
1092 return 0;
1093}
1094
1095static int
1096cb_metadata_owner(enum grecs_callback_command cmd, grecs_node_t *node,
1097 void *varptr, void *cb_data)
1098{
1099 grecs_locus_t *locus = &node->locus;
1100 grecs_value_t *value = node->v.value, *uval, *gval;
1101 struct directory_metadata *mp = varptr;
1102
1103 if (!(uval = get_arg(value, 0, GRECS_TYPE_STRING)))
1104 return 1;
1105 if (!(gval = get_arg(value, 1, GRECS_TYPE_STRING)))
1106 return 1;
1107 if (arg_to_uid(uval, &mp->uid))
1108 return 1;
1109 if (arg_to_gid(gval, &mp->gid))
1110 return 1;
1111 mp->flags |= METADATA_OWNER;
1112 return 0;
1113}
981 1114
982static struct grecs_keyword spool_kw[] = { 1115static struct grecs_keyword spool_kw[] = {
983 { "url", N_("arg"), N_("URL corresponding to this spool"), 1116 { "url", N_("arg"), N_("URL corresponding to this spool"),
@@ -989,6 +1122,18 @@ static struct grecs_keyword spool_kw[] = {
989 { "source", N_("dir"), N_("Source directory"), 1122 { "source", N_("dir"), N_("Source directory"),
990 grecs_type_string, GRECS_CONST, 1123 grecs_type_string, GRECS_CONST,
991 NULL, offsetof(struct spool, source_dir) }, 1124 NULL, offsetof(struct spool, source_dir) },
1125 { "source-mode",
1126 N_("mode: octal"),
1127 N_("mode for the source directory"),
1128 grecs_type_string, GRECS_CONST,
1129 NULL, offsetof(struct spool, source_metadata),
1130 cb_metadata_mode },
1131 { "source-owner",
1132 N_("uid: name-or-uid> <gid: name-or-gid"),
1133 N_("owner user and group for the source directory"),
1134 grecs_type_string, GRECS_CONST,
1135 NULL, offsetof(struct spool, source_metadata),
1136 cb_metadata_owner },
992 { "destination", N_("dir"), N_("Destination directory"), 1137 { "destination", N_("dir"), N_("Destination directory"),
993 grecs_type_string, GRECS_CONST, 1138 grecs_type_string, GRECS_CONST,
994 NULL, offsetof(struct spool, dest_url), 1139 NULL, offsetof(struct spool, dest_url),
@@ -1043,6 +1188,7 @@ cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
1043 for (i = 0; i < NITEMS(spool->dictionary); i++) 1188 for (i = 0; i < NITEMS(spool->dictionary); i++)
1044 spool->dictionary[i] = default_dictionary[i]; 1189 spool->dictionary[i] = default_dictionary[i];
1045 spool->archive = default_archive_descr; 1190 spool->archive = default_archive_descr;
1191 spool->source_metadata.flags = METADATA_NONE;
1046 *pdata = spool; 1192 *pdata = spool;
1047 break; 1193 break;
1048 1194
@@ -1052,17 +1198,8 @@ cb_spool(enum grecs_callback_command cmd, grecs_node_t *node,
1052 if (!spool->source_dir) { 1198 if (!spool->source_dir) {
1053 grecs_error(locus, 0, _("source is not given")); 1199 grecs_error(locus, 0, _("source is not given"));
1054 rc = 1; 1200 rc = 1;
1055 } else if (test_dir(spool->source_dir, &ec)) {
1056 if (ec)
1057 grecs_error(locus, ec, _("cannot access %s"),
1058 spool->source_dir);
1059 else
1060 grecs_error(locus, 0,
1061 _("%s is not a directory"),
1062 spool->source_dir);
1063 rc = 1;
1064 } 1201 }
1065 1202
1066 if (!spool->dest_url) { 1203 if (!spool->dest_url) {
1067 grecs_error(locus, 0, _("destination is not given")); 1204 grecs_error(locus, 0, _("destination is not given"));
1068 rc = 1; 1205 rc = 1;
@@ -1414,11 +1551,62 @@ config_init()
1414 default_dictionary[i] = dictionary_new(i, dictionary_builtin); 1551 default_dictionary[i] = dictionary_new(i, dictionary_builtin);
1415} 1552}
1416 1553
1554static int
1555create_source(struct spool *spool, void *data)
1556{
1557 struct stat st;
1558 int rc;
1559
1560 if ((rc = stat(spool->source_dir, &st)) != 0) {
1561 if (errno != ENOENT) {
1562 grecs_error(NULL, errno, _("%s: cannot stat %s"),
1563 spool->tag, spool->source_dir);
1564 *(int*)data = 1;
1565 return 0;
1566 } else {
1567 wy_debug(1, (_("creating spool source directory %s"),
1568 spool->source_dir));
1569 if (create_hierarchy(spool->source_dir, 0)) {
1570 *(int*)data = 1;
1571 return 0;
1572 }
1573