summaryrefslogtreecommitdiffabout
path: root/src
authorSergey Poznyakoff <gray@gnu.org.ua>2010-01-02 11:15:46 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2010-01-02 11:15:46 (GMT)
commitc8b326ef70fbfc06483ae249219a1d4ab09c8bfe (patch) (side-by-side diff)
treea2d9e70949e357426e7c3088e1aa258b3a5dc45a /src
parente9ac07640150f7aac1805d1447e6b712464d1b48 (diff)
downloadwydawca-c8b326ef70fbfc06483ae249219a1d4ab09c8bfe.tar.gz
wydawca-c8b326ef70fbfc06483ae249219a1d4ab09c8bfe.tar.bz2
Implement distribution tarball checking.
* src/config.c (event_args): New event "check-failure" (event_types): New event type ev_check_fail. (spool_kw,wydawca_kw): New keyword check-script. * src/directive.c (save_script) (stderr_redirector,run_check_script): New functions. (external_check): New function. (process_directives): Call external_check before actually moving the files. * src/gpg.c (homedir): Rename to temp_homedir, now global. * src/net.c (trim_crlf): Remove static qualifier. * src/triplet.c (hash_triplet_free): Free check_diag. (expand_triplet_full,expand_triplet_upload) (expand_triplet_sig,expand_triplet_directive): Rename to expand_triplet_ls_full,expand_triplet_ls_upload, expand_triplet_ls_sig,expand_triplet_ls_directive, correspondigly. (expand_check_diagn,expand_check_result) (expand_triplet_dist,expand_triplet_sig) (expand_triplet_dir): New functions. (triplet_meta): Renames: triplet:full => triplet:ls:full triplet:upload => triplet:ls:upload triplet:dist => triplet:ls:dist triplet:sig => triplet:ls:sig triplet:dir => triplet:ls:dir New keywords: triplet:dist, triplet:sig, triplet:dir, check:result, check:diagn. * src/wydawca.c (default_check_script): New global. (stat_name): New statistics counter "check failures". * src/wydawca.h (struct file_triplet): New members check_result, check_diag. (struct spool): New member check_script. (wydawca_stat): New value STAT_CHECK_FAIL. (notification_event): New value ev_check_fail. (default_check_script, temp_homedir): New externs. (concat_dir, copy_file, trim_crlf): New protos. * doc/wydawca.texi: Update. * configure.ac, NEWS: Version 2.0.90
Diffstat (limited to 'src') (more/less context) (ignore whitespace changes)
-rw-r--r--src/config.c11
-rw-r--r--src/directive.c290
-rw-r--r--src/gpg.c20
-rw-r--r--src/net.c2
-rw-r--r--src/triplet.c100
-rw-r--r--src/wydawca.c3
-rw-r--r--src/wydawca.h10
7 files changed, 401 insertions, 35 deletions
diff --git a/src/config.c b/src/config.c
index 51f2865..28734d0 100644
--- a/src/config.c
+++ b/src/config.c
@@ -150,6 +150,7 @@ static const char *event_args[] = {
"bad-ownership",
"bad-directive-signature",
"bad-detached-signature",
+ "check-failure",
NULL
};
@@ -157,7 +158,8 @@ static int event_types[] = {
ev_success,
ev_bad_ownership,
ev_bad_directive_signature,
- ev_bad_detached_signature
+ ev_bad_detached_signature,
+ ev_check_fail
};
ARGMATCH_VERIFY (event_args, event_types);
@@ -1180,7 +1182,9 @@ static struct grecs_keyword spool_kw[] = {
{ "notify-event", NULL, N_("Configure notification"),
grecs_type_section, NULL, offsetof(struct spool, notification),
cb_notify_event, NULL, notify_event_kw },
-
+ { "check-script", NULL, N_("A /bin/sh script to verify the tarball"),
+ grecs_type_string, NULL, offsetof(struct spool, check_script) },
+
{ NULL }
};
@@ -1457,6 +1461,9 @@ static struct grecs_keyword wydawca_kw[] = {
grecs_type_section, default_dictionary, 0,
cb_dictionary, NULL, dictionary_kw },
+ { "check-script", NULL, N_("A /bin/sh script to verify tarballs"),
+ grecs_type_string, &default_check_script },
+
{ "spool", N_("tag: string"), N_("Define distribution spool"),
grecs_type_section, NULL, 0,
cb_spool, NULL, spool_kw },
diff --git a/src/directive.c b/src/directive.c
index b52c18d..f648e07 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -300,6 +300,293 @@ verify_directive_format (struct file_triplet *trp)
return 0;
}
+
+
+static char *
+save_script (const char *script)
+{
+ char *file_name;
+ mode_t old_mask;
+ int fd;
+ size_t length;
+
+ file_name = concat_dir (temp_homedir, "chkXXXXXX", NULL);
+ old_mask = umask (0077);
+ fd = mkstemp (file_name);
+ umask (old_mask);
+ if (fd == -1)
+ {
+ logmsg (LOG_CRIT, _("cannot create temporary script file %s: %s"),
+ file_name, strerror (errno));
+ free (file_name);
+ return NULL;
+ }
+
+ length = strlen (script);
+ while (length)
+ {
+ ssize_t wrb = write (fd, script, length);
+ if (wrb == -1)
+ {
+ logmsg (LOG_CRIT, _("error writing to temporary script file %s: %s"),
+ file_name, strerror (errno));
+ break;
+ }
+ if (wrb == 0)
+ {
+ logmsg (LOG_CRIT, _("short write to temporary script file %s"),
+ file_name);
+ break;
+ }
+
+ length -= wrb;
+ script += wrb;
+ }
+ close (fd);
+ if (length)
+ {
+ free (file_name);
+ return NULL;
+ }
+ return file_name;
+}
+
+static int
+stderr_redirector (const char *tag)
+{
+ int p[2];
+ pid_t pid;
+
+ if (pipe (p))
+ {
+ logmsg (LOG_CRIT, "redirector pipe: %s", strerror (errno));
+ return -1;
+ }
+
+ pid = fork ();
+ if (pid == -1)
+ {
+ logmsg (LOG_CRIT, "redirector fork: %s", strerror (errno));
+ return -1;
+ }
+
+ if (pid == 0)
+ {
+ FILE *fp;
+ size_t size = 0;
+ char *buf = NULL;
+
+ close (p[1]);
+ fp = fdopen (p[0], "r");
+ if (!fp)
+ _exit (127);
+ while (getline (&buf, &size, fp) >= 0)
+ {
+ trim_crlf (buf);
+ logmsg (LOG_NOTICE, "%s: %s", tag, buf);
+ }
+ _exit (0);
+ }
+
+ close (p[0]);
+ return p[1];
+}
+
+static int
+run_check_script (const char *script, struct file_triplet *trp,
+ const char *descr)
+{
+ static char *script_file;
+ pid_t pid;
+ int status;
+ int p[2];
+ RETSIGTYPE (*oldsig)();
+ FILE *fp;
+ char *buf;
+ size_t size, total;
+ struct obstack stk;
+
+ if (debug_level > 1)
+ logmsg (LOG_DEBUG, _("prep script: %20.20s%s"),
+ script, strlen (script) > 20 ? "..." : "");
+ script_file = save_script (script);
+ if (!script_file)
+ return 1;
+ if (debug_level > 1)
+ logmsg (LOG_DEBUG, _("script file: %s"), script_file);
+
+ if (pipe (p))
+ {
+ logmsg (LOG_CRIT, "pipe: %s", strerror (errno));
+ return 1;
+ }
+ oldsig = signal (SIGCHLD, SIG_DFL);
+ pid = fork ();
+ if (pid == -1)
+ {
+ logmsg (LOG_CRIT, "fork: %s", strerror (errno));
+ free (script_file);
+ close (p[0]);
+ close (p[1]);
+ signal (SIGCHLD, oldsig);
+ return 1;
+ }
+ if (pid == 0)
+ {
+ int i;
+ int efd;
+ char *argv[4];
+ const struct spool *spool = trp->spool;
+
+ signal (SIGHUP, SIG_DFL);
+ signal (SIGTERM, SIG_DFL);
+ signal (SIGQUIT, SIG_DFL);
+ signal (SIGINT, SIG_DFL);
+ signal (SIGCHLD, SIG_DFL);
+ signal (SIGALRM, SIG_DFL);
+
+ efd = stderr_redirector (script_file);
+ if (efd == -1)
+ _exit (127);
+
+ for (i = getdtablesize (); i > 0; i--)
+ {
+ if (i != p[1] && i != efd)
+ close (i);
+ }
+
+ if (p[1] != 1 && dup2 (p[1], 1) != 1)
+ {
+ logmsg (LOG_CRIT, "cannot duplicate script's stdout: %s",
+ strerror (errno));
+ _exit (127);
+ }
+
+ if (efd != 2 && dup2 (efd, 2) != 2)
+ {
+ logmsg (LOG_CRIT, "cannot duplicate script's stderr: %s",
+ strerror (errno));
+ _exit (127);
+ }
+
+ setenv ("WYDAWCA_SPOOL", spool->tag, 1);
+ setenv ("WYDAWCA_SOURCE", spool->source_dir, 1);
+ setenv ("WYDAWCA_DEST", spool->dest_dir, 1);
+ setenv ("WYDAWCA_URL", spool->url, 1);
+ setenv ("WYDAWCA_TRIPLET_BASE", trp->name, 1);
+ setenv ("WYDAWCA_DIST_FILE", trp->file[file_dist].name, 1);
+
+ chdir (temp_homedir);
+
+ argv[0] = "-sh";
+ argv[1] = script_file;
+ argv[2] = NULL;
+
+ execv ("/bin/sh", argv);
+ _exit (127);
+ }
+
+ /* Master */
+ free (script_file);
+ close (p[1]);
+ fp = fdopen (p[0], "r");
+ buf = NULL;
+ size = total = 0;
+ obstack_init (&stk);
+ if (debug_level > 2)
+ logmsg (LOG_DEBUG, _("reading script output..."));
+ while (getline (&buf, &size, fp) > 0)
+ {
+ size_t len = strlen (buf);
+ if (debug_level > 2)
+ logmsg (LOG_DEBUG, _("read: %s"), buf);
+ obstack_grow (&stk, buf, len);
+ total += size;
+ }
+ obstack_1grow (&stk, 0);
+ if (debug_level > 2)
+ logmsg (LOG_DEBUG, _("bytes read: %lu"), (unsigned long)total);
+
+ fclose (fp);
+
+ waitpid (pid, &status, 0);
+ signal (SIGCHLD, oldsig);
+
+ if (total)
+ trp->check_diag = xstrdup (obstack_finish (&stk));
+ obstack_free (&stk, NULL);
+
+ trp->check_result = status;
+ if (WIFEXITED (status))
+ {
+ status = WEXITSTATUS (status);
+ if (status)
+ {
+ logmsg (LOG_ERR, "%s for triplet %s, spool %s returned %d",
+ descr, trp->name, trp->spool->tag, status);
+ return 1;
+ }
+ else if (debug_level > 2)
+ logmsg (LOG_DEBUG, "%s for triplet %s, spool %s returned %d",
+ descr, trp->name, trp->spool->tag, status);
+ }
+ else if (WIFSIGNALED (status))
+ {
+ int sig = WTERMSIG (status);
+ logmsg (LOG_NOTICE,
+ "%s for triplet %s, spool %s terminated on signal %d",
+ descr, trp->name, trp->spool->tag, sig);
+ return 1;
+ }
+ else
+ {
+ logmsg (LOG_NOTICE,
+ "%s for triplet %s, spool %s terminated with unhandled status",
+ descr, trp->name, trp->spool->tag);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+external_check (struct file_triplet *trp)
+{
+ int rc;
+ const struct spool *spool = trp->spool;
+ char *file;
+
+ if (!trp->file[file_dist].name)
+ return 0;
+ if (!spool->check_script && !default_check_script)
+ return 0;
+
+ file = concat_dir (temp_homedir, trp->file[file_dist].name, NULL);
+ if (copy_file (trp->file[file_dist].name, file))
+ {
+ free (file);
+ return 1;
+ }
+
+ rc = 0;
+ if (spool->check_script)
+ rc |= run_check_script (spool->check_script, trp,
+ _("spool check script"));
+
+ if (rc == 0 && default_check_script)
+ rc |= run_check_script (default_check_script, trp,
+ _("default check script"));
+
+ free (file);
+
+ if (rc)
+ {
+ UPDATE_STATS (STAT_CHECK_FAIL);
+ notify (spool->notification, trp, ev_check_fail);
+ }
+
+ return rc;
+}
+
/* Process the directives from TRP, using given SPOOL */
int
process_directives (struct file_triplet *trp, const struct spool *spool)
@@ -327,6 +614,7 @@ process_directives (struct file_triplet *trp, const struct spool *spool)
break;
case directory_dir:
+ /* FIXME: Alloc it in triplet */
relative_dir = safe_file_name_alloc (val);
if (!relative_dir || relative_dir[0] == '/')
{
@@ -340,6 +628,8 @@ process_directives (struct file_triplet *trp, const struct spool *spool)
rc = verify_detached_signature (trp, spool);
if (rc == 0)
{
+ if (external_check (trp))
+ return 1;
if (move_file (trp, spool, file_dist, relative_dir)
|| move_file (trp, spool, file_signature, relative_dir))
return 1;
diff --git a/src/gpg.c b/src/gpg.c
index f833142..cca5048 100644
--- a/src/gpg.c
+++ b/src/gpg.c
@@ -33,7 +33,7 @@
} \
while (0)
-static char *homedir;
+char *temp_homedir;
static int rmdir_r (const char *name);
@@ -122,29 +122,29 @@ static void
remove_homedir ()
{
if (debug_level > 1)
- logmsg (LOG_DEBUG, _("removing GNUPG home directory: %s"), homedir);
- if (rmdir_r (homedir))
- logmsg (LOG_CRIT, _("failed to remove GPG directory %s"), homedir);
+ logmsg (LOG_DEBUG, _("removing GNUPG home directory: %s"), temp_homedir);
+ if (rmdir_r (temp_homedir))
+ logmsg (LOG_CRIT, _("failed to remove GPG directory %s"), temp_homedir);
}
/* Create a temporary GPG home directory */
static int
create_gpg_homedir ()
{
- if (homedir)
+ if (temp_homedir)
return 0;
- homedir = xstrdup ("/tmp/wydawca-XXXXXX");
- if (!mkdtemp (homedir))
+ temp_homedir = xstrdup ("/tmp/wydawca-XXXXXX");
+ if (!mkdtemp (temp_homedir))
{
logmsg (LOG_CRIT, _("cannot create GPG home directory (%s): %s"),
- homedir, strerror (errno));
+ temp_homedir, strerror (errno));
return 1;
}
atexit (remove_homedir);
if (debug_level > 1)
- logmsg (LOG_DEBUG, _("GNUPG home directory: %s"), homedir);
- setenv ("GNUPGHOME", homedir, 1);
+ logmsg (LOG_DEBUG, _("GNUPG home directory: %s"), temp_homedir);
+ setenv ("GNUPGHOME", temp_homedir, 1);
return 0;
}
diff --git a/src/net.c b/src/net.c
index 2379cb3..e6bb4ab 100644
--- a/src/net.c
+++ b/src/net.c
@@ -82,7 +82,7 @@ open_listener ()
return fd;
}
-static void
+void
trim_crlf (char *s)
{
size_t len = strlen (s);
diff --git a/src/triplet.c b/src/triplet.c
index dbba486..f18f573 100644
--- a/src/triplet.c
+++ b/src/triplet.c
@@ -52,6 +52,7 @@ hash_triplet_free (void *data)
free (tp->directive);
free (tp->blurb);
free (tp->tmp);
+ free (tp->check_diag);
/* FIXME: free uploader list */
free (tp);
@@ -368,7 +369,7 @@ format_file_data (struct file_triplet *trp, enum file_type type, char **pret)
}
static const char *
-expand_triplet_full (struct metadef *def, void *data)
+expand_triplet_ls_full (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
char *buf[FILE_TYPE_COUNT] = { NULL, NULL, NULL };
@@ -406,7 +407,7 @@ expand_triplet_full (struct metadef *def, void *data)
}
static const char *
-expand_triplet_upload (struct metadef *def, void *data)
+expand_triplet_ls_upload (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
char *buf[2] = { NULL, NULL };
@@ -441,13 +442,34 @@ static const char *
expand_triplet_dist (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
+ return trp->file[file_dist].name;
+}
+
+static const char *
+expand_triplet_sig (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
+ return trp->file[file_signature].name;
+}
+
+static const char *
+expand_triplet_dir (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
+ return trp->file[file_directive].name;
+}
+
+static const char *
+expand_triplet_ls_dist (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
format_file_data (trp, file_dist, &def->storage);
def->value = def->storage;
return def->value;
}
static const char *
-expand_triplet_sig (struct metadef *def, void *data)
+expand_triplet_ls_sig (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
format_file_data (trp, file_signature, &def->storage);
@@ -456,7 +478,7 @@ expand_triplet_sig (struct metadef *def, void *data)
}
static const char *
-expand_triplet_directive (struct metadef *def, void *data)
+expand_triplet_ls_directive (struct metadef *def, void *data)
{
struct file_triplet *trp = data;
format_file_data (trp, file_directive, &def->storage);
@@ -509,6 +531,37 @@ expand_comment (struct metadef *def, void *data)
return def->value;
}
+static const char *
+expand_check_diagn (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
+ return trp->check_diag;
+}
+
+static const char *
+expand_check_result (struct metadef *def, void *data)
+{
+ struct file_triplet *trp = data;
+ int status = trp->check_result;
+ char sbuf[INT_BUFSIZE_BOUND (uintmax_t)];
+
+ if (status == 0)
+ return def->value = "0";
+ else if (WIFEXITED (status))
+ {
+ char *p = umaxtostr (WEXITSTATUS (status), sbuf);
+ def->storage = xstrdup (p);
+ }
+ else if (WIFSIGNALED (status))
+ {
+ char *p = umaxtostr (WTERMSIG (status), sbuf);
+ asprintf (&def->storage, "SIG+%s", p);
+ }
+ else
+ def->storage = "[unrecognized return code]";
+ return def->value = def->storage;
+}
+
#define DECL_EXPAND_TIMER(what) \
static const char * \
__cat2__(expand_timer_,what) (struct metadef *def, void *data) \
@@ -555,23 +608,28 @@ triplet_expand_dictionary_query (struct dictionary *dict, void *handle,
}
struct metadef triplet_meta[] = {
- { "project", NULL, expand_project_base, NULL },
- { "url", NULL, expand_url, NULL },
- { "spool", NULL, expand_tag, NULL },
- { "dir", NULL, expand_relative_dir, NULL },
- { "dest-dir", NULL, expand_dest_dir, NULL },
- { "source-dir", NULL, expand_source_dir, NULL },
- { "triplet:full", NULL, expand_triplet_full, NULL },
- { "triplet:upload", NULL, expand_triplet_upload, NULL },
- { "triplet:dist", NULL, expand_triplet_dist, NULL },
- { "triplet:sig", NULL, expand_triplet_sig, NULL },
- { "triplet:dir", NULL, expand_triplet_directive, NULL },
- { "user", NULL, expand_user_name, NULL },
- { "user:name", NULL, expand_user_name, NULL },
- { "user:real-name", NULL, expand_user_real_name, NULL },
- { "user:email", NULL, expand_user_email, NULL },
- { "report", NULL, expand_report, NULL },
- { "comment", NULL, expand_comment, NULL },
+ { "project", NULL, expand_project_base, NULL },
+ { "url", NULL, expand_url, NULL },
+ { "spool", NULL, expand_tag, NULL },
+ { "dir", NULL, expand_relative_dir, NULL },
+ { "dest-dir", NULL, expand_dest_dir, NULL },
+ { "source-dir", NULL, expand_source_dir, NULL },
+ { "triplet:dist", NULL, expand_triplet_dist, NULL },
+ { "triplet:sig", NULL, expand_triplet_sig, NULL },
+ { "triplet:dir", NULL, expand_triplet_dir, NULL },
+ { "triplet:ls:full", NULL, expand_triplet_ls_full, NULL },
+ { "triplet:ls:upload", NULL, expand_triplet_ls_upload, NULL },
+ { "triplet:ls:dist", NULL, expand_triplet_ls_dist, NULL },
+ { "triplet:ls:sig", NULL, expand_triplet_ls_sig, NULL },
+ { "triplet:ls:dir", NULL, expand_triplet_ls_directive, NULL },
+ { "check:result", NULL, expand_check_result, NULL },
+ { "check:diagn", NULL, expand_check_diagn, NULL },
+ { "user", NULL, expand_user_name, NULL },
+ { "user:name", NULL, expand_user_name, NULL },
+ { "user:real-name", NULL, expand_user_real_name, NULL },
+ { "user:email", NULL, expand_user_email, NULL },
+ { "report", NULL, expand_report, NULL },
+ { "comment", NULL, expand_comment, NULL },
DECL_FULL_TIMER(wydawca),
DECL_FULL_TIMER(triplet),
DECL_FULL_TIMER(spool),
diff --git a/src/wydawca.c b/src/wydawca.c
index 5dc73e7..fc1dea2 100644
--- a/src/wydawca.c
+++ b/src/wydawca.c
@@ -46,7 +46,7 @@ int single_process;
time_t wakeup_interval;
gl_list_t all_spool_aliases;
char *wydawca_gpg_homedir;
-
+char *default_check_script;
struct grecs_sockaddr listen_sockaddr;
unsigned wydawca_stat[MAX_STAT];
@@ -142,6 +142,7 @@ static char *stat_name[MAX_STAT] = {
N_("files archived"),
N_("symlinks created"),
N_("symlinks removed"),
+ N_("check failures"),
};
static char *stat_kwname[MAX_STAT] = {
diff --git a/src/wydawca.h b/src/wydawca.h
index b2e79d4..af24e47 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -184,6 +184,8 @@ struct file_triplet
struct uploader_info *uploader;
/* Special data for template formatting */
char *project; /* Triplet project name (if known) */
+ int check_result; /* Result of external check */
+ char *check_diag; /* External check diagnostics */
};
/* Macros to access owner UID and GID. */
@@ -233,6 +235,7 @@ struct spool
struct dictionary *dictionary[dictionary_count];
struct archive_descr archive; /* Archivation data */
struct notification *notification;
+ char *check_script;
};
@@ -251,6 +254,7 @@ enum wydawca_stat
STAT_ARCHIVES,
STAT_SYMLINKS,
STAT_RMSYMLINKS,
+ STAT_CHECK_FAIL,
MAX_STAT
};
@@ -265,6 +269,7 @@ enum notification_event
ev_bad_ownership,
ev_bad_directive_signature,
ev_bad_detached_signature,
+ ev_check_fail,
MAX_EVENT
};
@@ -347,6 +352,8 @@ extern struct grecs_sockaddr listen_sockaddr;
extern gl_list_t all_spool_aliases;
extern char *wydawca_gpg_homedir;
+extern char *default_check_script;
+extern char *temp_homedir;
#define UPDATE_STATS(what) \
do \
@@ -477,6 +484,8 @@ rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
/* diskio.c */
+char *concat_dir (const char *base, const char *name, size_t *pbaselen);
+int copy_file (const char *file, const char *dst_file);
int dir_test_url (mu_url_t url, grecs_locus_t *locus);
int dir_move_file (struct file_triplet *trp, const struct spool *spool,
@@ -536,6 +545,7 @@ void remove_pidfile (void);
/* net.c */
void wydawca_listener (void);
+void trim_crlf (char *s);
#define LOCK_OK 0

Return to:

Send suggestions and report system problems to the System administrator.