/* wydawca - automatic release submission daemon
Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 3 of the License, or (at your
option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see . */
#ifdef HAVE_CONFIG_H
# include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include "obstack.h"
#include "error.h"
#include "xalloc.h"
#include "progname.h"
#include "backupfile.h"
#include "inttostr.h"
#include "grecs.h"
#include "gl_list.h"
#include "wordsplit.h"
#define gettext(s) s
#define _(s) s
#define N_(s) s
#define SP(s) ((s) ? (s) : "NONE")
#define WYDAWCA_EX_AGAIN 1
/* The range of directive versions we accept (major * 100 + minor) */
#define MIN_DIRECTIVE_VERSION 101
#define MAX_DIRECTIVE_VERSION 101
/* Default modes for mkdir and creat commands: rely on the umask value */
#define MKDIR_PERMISSIONS 0777
#define CREAT_PERMISSIONS 0666
#define SUF_SIG ".sig"
#define SUF_SIG_LEN (sizeof (SUF_SIG) - 1)
#define SUF_DIR ".directive.asc"
#define SUF_DIR_LEN (sizeof (SUF_DIR) - 1)
#define __cat2__(a,b) a ## b
#define __cat3__(a,b,c) a ## b ## c
#define NITEMS(a) (sizeof(a)/sizeof((a)[0]))
enum access_method_id {
project_uploader_method, /* Retrieves names, gpg-keys, emails and
real names of the project uploaders */
project_owner_method, /* Retrieves names and emails of the project
owners */
access_method_count
};
enum access_method_type
{
method_none, /* Undefined or no method */
method_sql, /* Use SQL database */
method_builtin, /* Use built-in facilities */
method_external /* Invoke an external program */
};
struct access_method
{
enum access_method_id id;
enum access_method_type type; /* Access method type */
char *query; /* Query template */
int parmc; /* Number of entries in paramv */
char **parmv; /* Parameters. The semantics differs
depending on type. For SQL:
0 - Identifier of the SQL struct
to use; */
int init_passed; /* Initialization count */
char *result; /* Result storage */
size_t result_size; /* Size of result */
unsigned ncol; /* Number of columns per row */
unsigned nrow; /* Number of rows */
void *storage;
};
/* Archive types */
enum archive_type
{
archive_none, /* No archivation requested */
archive_directory, /* Archive by moving files to a separate directory
hierarchy */
archive_tar /* Archive by appending to a tar file (tar -r) */
};
struct archive_descr
{
enum archive_type type; /* Archivation type */
char *name; /* Directory name if type==archive_directory,
archive file name if type==archive_tar */
enum backup_type backup_type; /* Requested backup type if
type == archive_directory */
};
/* Type of file in a triplet */
enum file_type
{
file_dist, /* Something to be distributed */
file_signature, /* Detached signature (.sig) */
file_directive, /* Directive (.directive.asc) */
};
#define FILE_TYPE_COUNT (file_directive+1)
/* Part of a triplet */
struct file_info
{
enum file_type type; /* Part type */
char *name; /* File name */
unsigned root_len; /* Length of root part in name */
struct stat sb;
};
struct uploader_info
{
struct uploader_info *next;
char *name;
char *realname;
char *email;
char *gpg_key;
char *fpr;
};
/* File triplet */
struct file_triplet
{
char *name; /* Triplet base name */
struct file_info file[FILE_TYPE_COUNT]; /* Components */
const struct spool *spool; /* Owning spool */
char **directive; /* Decoded directive pairs (key: value\0) */
char *blurb; /* Block of directives: directive[i] points here */
char *tmp; /* Temporary storage */
size_t tmpsize; /* Size of memory allocated in tmp */
/* User data */
size_t uploader_count;
struct uploader_info *uploader_list;
struct uploader_info *uploader;
/* Special data for template formatting */
char *project; /* Triplet project name (if known) */
};
/* Macros to access owner UID and GID. */
/* The directive file is always present in the triplet */
#define TRIPLET_UID(t) ((t)->file[file_directive].sb.st_uid)
/* GID is filled in after the triplet is finalized and verified */
#define TRIPLET_GID(t) ((t)->file[file_directive].sb.st_gid)
struct virt_tab
{
int (*test_url) (mu_url_t url, grecs_locus_t *loc);
int (*move_file) (struct file_triplet *trp,
const struct spool *spool,
enum file_type file_id,
const char *reldir);
int (*archive_file) (struct file_triplet *trp,
const struct spool *spool,
const char *reldir,
const char *file_name);
int (*symlink_file) (struct file_triplet *trp,
const struct spool *spool,
const char *reldir,
const char *wanted_src,
const char *wanted_dst);
int (*rmsymlink_file)(struct file_triplet *trp,
const struct spool *spool,
const char *reldir,
const char *file_name);
};
/* An upload spool. This structure contains all data necessary for releasing
files from source to destination */
struct spool
{
char *tag;
gl_list_t aliases;
char *url; /* Download URL */
char *source_dir; /* Source directory */
mu_url_t dest_url; /* Destination URL */
const char *dest_dir; /* Directory part of the above */
struct virt_tab vtab; /* Virtual method table */
time_t file_sweep_time; /* Remove invalid/unprocessed files
after this amount of time */
struct access_method *access_method[access_method_count];
struct archive_descr archive; /* Archivation data */
struct notification *notification;
};
enum wydawca_stat
{
STAT_ERRORS,
STAT_WARNINGS,
STAT_BAD_SIGNATURE,
STAT_ACCESS_VIOLATIONS,
STAT_COMPLETE_TRIPLETS,
STAT_INCOMPLETE_TRIPLETS,
STAT_BAD_TRIPLETS,
STAT_EXPIRED_TRIPLETS,
STAT_TRIPLET_SUCCESS,
STAT_UPLOADS,
STAT_ARCHIVES,
STAT_SYMLINKS,
STAT_RMSYMLINKS,
MAX_STAT
};
#define STAT_MASK(c) (1<<(c))
#define STAT_MASK_NONE 0
#define STAT_MASK_ALL (STAT_MASK(MAX_STAT) - 1)
enum notification_event
{
ev_success,
ev_bad_ownership,
ev_bad_directive_signature,
ev_bad_detached_signature,
MAX_EVENT
};
enum notification_target
{
notify_read, /* Read recipients from the message headers */
notify_admin, /* System administrator */
notify_owner, /* Project admin */
notify_user /* User (uploader) */
};
struct notification
{
struct notification *next;
enum notification_event ev;
enum notification_target tgt;
const char *msg;
};
void register_message_template (const char *name, const char *text);
void notify (struct notification *,
struct file_triplet *, enum notification_event);
const char *notification_event_str (enum notification_event evt);
const char *notification_target_str (enum notification_target tgt);
struct metadef
{
char *kw;
char *value;
const char *(*expand) (struct metadef *, void *);
char *storage;
void *data;
};
char *meta_expand_string (const char *string, struct metadef *def, void *data,
struct access_method *method, void *handle);
void meta_free (struct metadef *def);
/* Global variables */
extern uid_t wydawca_uid;
extern gid_t wydawca_gid;
extern size_t wydawca_supp_groupc;
extern gid_t *wydawca_supp_groups;
extern char *conffile; /* Configuration file name */
extern int debug_level; /* Debugging level */
extern int dry_run_mode; /* Dry run indicator */
extern int log_to_stderr; /* Log to stderr instead of the syslog */
extern int log_facility; /* Syslog facility to use if !log_to_stderr */
extern char *syslog_tag; /* Syslog tag */
extern int syslog_include_prio;/* Syslog priority indication */
extern time_t file_sweep_time; /* Unlink stale file after this amount of time
*/
extern char *tar_command_name; /* Name of the tar command */
extern unsigned wydawca_stat[MAX_STAT];
extern unsigned long print_stats;
extern int archive_signatures;
extern char *admin_stat_message;
extern char *pidfile;
extern int force_startup;
extern char *lockdir;
extern time_t lock_expire_time;
extern time_t lock_timeout;
extern int enable_locking;
extern int daemon_mode;
extern time_t wakeup_interval;
extern int foreground;
extern int single_process;
extern struct grecs_sockaddr listen_sockaddr;
extern gl_list_t all_spool_aliases;
#define UPDATE_STATS(what) \
do \
{ \
if (what >= MAX_STAT) abort(); \
wydawca_stat[what]++; \
} \
while (0)
int stat_mask_p (unsigned long mask);
struct metadef *make_stat_expansion (size_t count);
void initstats (void);
void logstats (void);
/* Utility functions */
char *safe_file_name (char *file_name);
char *safe_file_name_alloc (const char *file_name);
size_t trim_length (const char *str);
size_t trim (char *str);
void logmsg (int prio, char *fmt, ...) GSC_PRINTFLIKE(2,3);
int test_dir (const char *name, int *ec);
char *create_directory (const char *base, const char *name);
int create_hierarchy (char *dir, size_t baselen);
void parse_config (void);
void log_output (int prio, const char *prog, FILE *fp);
enum exec_result
{
exec_success, /* Command executed and returned 0 */
exec_fail, /* Command executed and returned not 0 */
exec_error /* Command failed to execute */
};
enum exec_result wydawca_exec (int argc, const char **argv, int *retcode);
/* Directory scanning and registering */
int scan_spool (const struct spool *spool, int uc, uid_t *uv);
int scan_all_spools (int, uid_t *);
void spool_create_timers (void);
void register_spool (struct spool *spool);
struct spool *wydawca_find_spool (const char *name);
void register_file (struct file_info *finfo);
void enumerate_triplets (const struct spool *);
size_t count_collected_triplets (void);
char *triplet_expand_param (const char *tmpl, struct file_triplet *trp);
char *triplet_expand_method_query (struct access_method *method, void *handle,
struct file_triplet *trp);
/* General-purpose method support */
struct access_method *method_new (enum access_method_id id,
enum access_method_type type);
int method_init (struct access_method *method);
int method_done (struct access_method *method);
void *method_open (struct access_method *method);
int method_close (struct access_method *method, void *handle);
int method_run (struct access_method *method, void *handle, const char *cmd);
void method_copy_result (struct access_method *method, const char *res,
size_t size);
const char *method_result (struct access_method *method, void *handle,
unsigned nrow,
unsigned ncol);
int method_quote_string (struct access_method *method, void *handle,
const char *input, char **poutput, size_t *psize);
unsigned method_num_rows (struct access_method *method);
unsigned method_num_cols (struct access_method *method);
/* Verification functions */
int verify_directive_file (struct file_triplet *trp,
const struct spool *spool);
int verify_directive_signature (struct file_triplet *trp,
const struct spool *spool);
int verify_detached_signature (struct file_triplet *trp,
const struct spool *spool);
int fill_project_name (struct file_triplet *trp);
struct uploader_info *uploader_find_frp (struct uploader_info *list,
const char *frp);
/* Directive file support */
int directive_parse (struct file_triplet *trp);
int directive_get_value (struct file_triplet *trp, const char *key,
const char **pval);
int directive_pack_version (const char *val, unsigned *pversion);
int directive_version_in_range_p (struct file_triplet *trp,
unsigned from, unsigned to);
int verify_directive_format (struct file_triplet *trp);
int directive_first (struct file_triplet *trp,
const char **pkey, const char **pval);
int directive_next (struct file_triplet *trp, int n,
const char **pkey, const char **pval);
int process_directives (struct file_triplet *trp,
const struct spool *spool);
int enabled_spool_p (const struct spool *spool);
int parse_time_interval (const char *str, time_t *pint, const char **endp);
/* config.c */
void config_init (void);
void config_help (void);
int assert_string_arg (grecs_locus_t *, enum grecs_callback_command,
const grecs_value_t *);
/* vtab.c */
int url_to_vtab (mu_url_t url, struct virt_tab *vtab);
int
move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
int
archive_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
int
symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst);
int
rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
/* diskio.c */
int dir_test_url (mu_url_t url, grecs_locus_t *locus);
int dir_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
int dir_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir);
int dir_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst);
int dir_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
/* null.c */
int null_move_file (struct file_triplet *trp, const struct spool *spool,
enum file_type file_id, const char *reldir);
int null_archive_file (struct file_triplet *trp, const struct spool *spool,
const char *file_name, const char *reldir);
int null_symlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir,
const char *wanted_src, const char *wanted_dst);
int null_rmsymlink_file (struct file_triplet *trp, const struct spool *spool,
const char *reldir, const char *file_name);
/* timer.c */
typedef struct timer_slot *wydawca_timer_t;
wydawca_timer_t timer_get (const char *name);
wydawca_timer_t timer_start (const char *name);
wydawca_timer_t timer_stop (const char *name);
wydawca_timer_t timer_reset (const char *name);
double timer_get_real (wydawca_timer_t t);
double timer_get_user (wydawca_timer_t t);
double timer_get_system (wydawca_timer_t t);
char *timer_format_time (double t);
size_t timer_get_count (void);
void timer_fill_meta (struct metadef *def, size_t num);
void timer_free_meta (struct metadef *def, size_t num);
void report_init (void);
void report_add (const char *fmt, ...);
void report_finish (void);
extern char *report_string;
/* job.c */
void schedule_job (const struct spool *spool, uid_t uid);
void job_init (void);
void job_queue_runner (void);
/* profile.c */
void check_pidfile (void);
void remove_pidfile (void);
/* net.c */
void wydawca_listener (void);
#define LOCK_OK 0
#define LOCK_CONFLICT 1
#define LOCK_RETRY 2
#define LOCK_INVALID 3
#define LOCK_FAILURE 4
char *wydawca_lockname (const char *tag);
int wydawca_lock (const char *lockname);
void wydawca_unlock (const char *lockname);
void wydawca_lock_init (void);
/* tcpwrap.h */
extern struct grecs_keyword tcpwrapper_kw[];
int tcpwrap_access(int fd);
/* userprivs.c */
int wydawca_userprivs (uid_t uid, gid_t gid, gid_t *grplist, size_t ngrp);