diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2019-07-19 14:39:55 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-07-19 14:48:24 +0300 |
commit | af538cc27228edf816edea1bf52c84b5bb4f8720 (patch) | |
tree | 070e83b5149a53b84b63e707c6b2f108d911223e | |
parent | f6657a46e2422d903d62565868f77c430a612a42 (diff) | |
download | wydawca-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.c | 220 | ||||
-rw-r--r-- | src/wydawca.h | 12 |
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 | |||
981 | static int | ||
982 | cb_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 | |||
1009 | static int | ||
1010 | arg_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 | |||
1052 | static int | ||
1053 | arg_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 | |||
1095 | static int | ||
1096 | cb_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 | ||
982 | static struct grecs_keyword spool_kw[] = { | 1115 | static 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 | ||
1554 | static int | ||
1555 | create_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 |