aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-08-22 13:23:03 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-08-22 13:23:03 +0000
commit180ca1d87d2bf69d9dbb0acb76422e9ae15f930c (patch)
treeb14651206aaec8e03fdfdce9e04433068fa62648
parent708a28a2f5bd2384e4c254a47d069ec4d9ef697e (diff)
downloadwydawca-180ca1d87d2bf69d9dbb0acb76422e9ae15f930c.tar.gz
wydawca-180ca1d87d2bf69d9dbb0acb76422e9ae15f930c.tar.bz2
Implement all directives
git-svn-id: file:///svnroot/wydawca/trunk@284 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
-rw-r--r--src/Makefile.am4
-rw-r--r--src/config.c62
-rw-r--r--src/directive.c162
-rw-r--r--src/diskio.c305
-rw-r--r--src/exec.c155
-rw-r--r--src/gpg.c159
-rw-r--r--src/register.c152
-rw-r--r--src/triplet.c108
-rw-r--r--src/verify.c34
-rw-r--r--src/wydawca.c2
-rw-r--r--src/wydawca.h206
-rw-r--r--src/wydawca.rc1
12 files changed, 753 insertions, 597 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c93b9bd..f421330 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -19,8 +19,9 @@ EXTRA_PROGRAMS=wydawca
wydawca_SOURCES=\
config.c\
directive.c\
- gpg.c\
diskio.c\
+ exec.c\
+ gpg.c\
method.c\
process.c\
sql.c\
@@ -29,6 +30,7 @@ wydawca_SOURCES=\
verify.c\
wydawca.c\
wydawca.h
+
LDADD=../lib/libgsc.a ../gnu/libgnu.a @SQLLIB@ @GPGMELIB@
INCLUDES = -I../lib -I../gnu
AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\" \ No newline at end of file
diff --git a/src/config.c b/src/config.c
index 94dbde5..ae7c974 100644
--- a/src/config.c
+++ b/src/config.c
@@ -134,6 +134,12 @@ safe_file_name (char *file_name)
return file_name;
}
+char *
+safe_file_name_alloc (const char *file_name)
+{
+ return safe_file_name (xstrdup (file_name));
+}
+
static void
cfg_syslog_tag (gsc_config_file_t *file, char *kw, char *val, void *unused)
@@ -146,8 +152,11 @@ cfg_syslog_facility (gsc_config_file_t *file, char *kw, char *val,
void *unused)
{
if (gsc_str_to_syslog_facility (val, &log_facility))
- file->error_msg (file->file_name, file->line, "Unknown facility `%s'",
- val);
+ {
+ file->error_msg (file->file_name, file->line, "Unknown facility `%s'",
+ val);
+ file->error_count++;
+ }
}
static void
@@ -171,10 +180,14 @@ cfg_file_sweep_time (gsc_config_file_t *file, char *kw, char *val, void *data)
time_t interval;
const char *endp;
- if (parse_time_interval (val, &interval, &endp))
- file->error_msg (file->file_name, file->line,
- "unrecognized time format (near `%s')",
- endp);
+ if (parse_time_interval (val, &interval, &endp))
+ {
+ file->error_msg (file->file_name, file->line,
+ "unrecognized time format (near `%s')",
+ endp);
+ file->error_count++;
+ }
+
if (data)
dp->file_sweep_time = interval;
else
@@ -204,6 +217,7 @@ _cfg_access_method (gsc_config_file_t *file, char *kw, char *val, void *data)
{
file->error_msg (file->file_name, file->line,
"access method not specified");
+ file->error_count++;
return;
}
ap->type = str_to_access_method (word);
@@ -212,6 +226,7 @@ _cfg_access_method (gsc_config_file_t *file, char *kw, char *val, void *data)
case method_none:
file->error_msg (file->file_name, file->line,
"unknown access method: %s", word);
+ file->error_count++;
return;
case method_sql:
@@ -292,6 +307,7 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data)
if (*type == 0)
{
file->error_msg (file->file_name, file->line, "missing archive type");
+ file->error_count++;
return;
}
@@ -308,6 +324,7 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data)
if (*word == 0)
{
file->error_msg (file->file_name, file->line, "missing file name");
+ file->error_count++;
dp->archive.type = archive_none;
return;
}
@@ -332,6 +349,7 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data)
{
file->error_msg (file->file_name, file->line,
"invalid backup type `%s'", word);
+ file->error_count++;
dp->archive.backup_type = no_backups;
}
if (*val)
@@ -348,12 +366,16 @@ cfg_archive (gsc_config_file_t *file, char *kw, char *val, void *data)
"ignoring VERSION_CONTROL environment variable: "
"invalid value");
dp->archive.backup_type = no_backups;
+ file->error_count++;
}
}
}
else
- file->error_msg (file->file_name, file->line,
- "unknown archive type: %s", word);
+ {
+ file->error_msg (file->file_name, file->line,
+ "unknown archive type: %s", word);
+ file->error_count++;
+ }
}
}
@@ -373,7 +395,8 @@ cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused)
};
if (val)
- file->error_msg (file->file_name, file->line, "junk in line ignored");
+ file->error_msg (file->file_name, file->line,
+ "warning: junk in line ignored");
memset (&dpair, 0, sizeof dpair);
dpair.file_sweep_time = file_sweep_time;
@@ -394,6 +417,7 @@ cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused)
file->error_msg (file->file_name, file->line,
"%s is not a directory",
dpair.source_dir);
+ file->error_count++;
}
else if (test_dir (dpair.dest_dir, &ec))
{
@@ -405,6 +429,7 @@ cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused)
file->error_msg (file->file_name, file->line,
"%s is not a directory",
dpair.dest_dir);
+ file->error_count++;
}
else if (dpair.verify_method.type != method_none
&& dpair.gpg_key_method.type != method_none)
@@ -412,14 +437,6 @@ cfg_directory (gsc_config_file_t *file, char *kw, char *val, void *unused)
}
static void
-cfg_unlink_invalid_files (gsc_config_file_t *file, char *kw, char *val,
- void *unused)
-{
- if (get_bool (val, &unlink_invalid_files))
- file->error_msg (file->file_name, file->line, "invalid boolean value");
-}
-
-static void
cfg_sql_host (gsc_config_file_t *file, char *kw, char *val, void *data)
{
struct sqlconn *pconn = data;
@@ -440,12 +457,14 @@ cfg_sql_host (gsc_config_file_t *file, char *kw, char *val, void *data)
{
file->error_msg (file->file_name, file->line,
"invalid port number (near %s)", end);
+ file->error_count++;
return;
}
if (n == 0 || n > USHRT_MAX)
{
file->error_msg (file->file_name, file->line,
"port number out of range 1..%d", USHRT_MAX);
+ file->error_count++;
return;
}
pconn->port = n;
@@ -492,7 +511,11 @@ cfg_sql (gsc_config_file_t *file, char *kw, char *val, void *unused)
memset (&sql, 0, sizeof sql);
if (!val)
- file->error_msg (file->file_name, file->line, "missing block identifier");
+ {
+ file->error_msg (file->file_name, file->line,
+ "missing block identifier");
+ file->error_count++;
+ }
else
sql.ident = xstrdup (val);
@@ -510,6 +533,7 @@ cfg_umask (gsc_config_file_t *file, char *kw, char *val, void *unused)
{
file->error_msg (file->file_name, file->line, "invalid umask (near %s)",
p);
+ file->error_count++;
return;
}
umask (m);
@@ -524,6 +548,7 @@ cfg_tar_program (gsc_config_file_t *file, char *kw, char *val, void *unused)
{
file->error_msg (file->file_name, file->line,
"must be an absolute file name");
+ file->error_count++;
return;
}
@@ -537,7 +562,6 @@ static struct gsc_config_keyword kw_handler[] = {
{ "syslog-tag", cfg_syslog_tag },
{ "syslog-facility", cfg_syslog_facility },
{ "directory", cfg_directory },
- { "unlink-invalid-files", cfg_unlink_invalid_files },
{ "file-sweep-time", cfg_file_sweep_time },
{ "sql", cfg_sql },
{ "verify-user", cfg_verify_user },
diff --git a/src/directive.c b/src/directive.c
index 0e06502..ee52dd7 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -19,56 +19,56 @@
/* Directive file support */
int
-directive_parse (struct file_register *reg)
+directive_parse (struct file_triplet *trp)
{
size_t dcount, i;
char *p;
if (debug_level > 2)
logmsg (LOG_DEBUG, "%s: parsing directive blurb: %s",
- reg->file[file_directive].name, reg->blurb);
+ trp->file[file_directive].name, trp->blurb);
dcount = 0;
- for (p = reg->blurb; *p; p++)
+ for (p = trp->blurb; *p; p++)
if (*p == '\n')
dcount++;
- reg->directive = xcalloc (dcount + 1, sizeof reg->directive[0]);
- p = reg->blurb;
+ trp->directive = xcalloc (dcount + 1, sizeof trp->directive[0]);
+ p = trp->blurb;
for (i = 0; i < dcount; )
{
- reg->directive[i] = p;
+ trp->directive[i] = p;
p = strchr (p, '\n');
if (p)
*p++ = 0;
- if (trim (reg->directive[i]) == 0) /* ignore empty lines */
+ if (trim (trp->directive[i]) == 0) /* ignore empty lines */
continue;
- if (strchr (reg->directive[i], ':') == NULL)
+ if (strchr (trp->directive[i], ':') == NULL)
{
logmsg (LOG_ERR, "%s: invalid line: %s",
- reg->file[file_directive].name, reg->directive[i]);
- free (reg->directive);
- reg->directive = NULL;
+ trp->file[file_directive].name, trp->directive[i]);
+ free (trp->directive);
+ trp->directive = NULL;
return 1;
}
i++;
if (!p)
break;
}
- reg->directive[i] = NULL;
+ trp->directive[i] = NULL;
return 0;
}
int
-directive_get_value (struct file_register *reg, const char *key,
+directive_get_value (struct file_triplet *trp, const char *key,
const char **pval)
{
int keylen = strlen (key);
int i;
- for (i = 0; reg->directive[i]; i++)
+ for (i = 0; trp->directive[i]; i++)
{
- char *str = reg->directive[i];
+ char *str = trp->directive[i];
int len = strlen (str);
if (len > keylen && memcmp (str, key, keylen) == 0 && str[keylen] == ':')
{
@@ -84,25 +84,25 @@ directive_get_value (struct file_register *reg, const char *key,
}
static int
-_directive_seq_get (int n, struct file_register *reg,
+_directive_seq_get (int n, struct file_triplet *trp,
const char **pkey, const char **pval)
{
char *p;
size_t len;
- if (reg->directive[n] == NULL)
+ if (trp->directive[n] == NULL)
return 0;
- p = strchr (reg->directive[n], ':');
- len = p - reg->directive[n];
- if (len + 1 > reg->tmpsize)
+ p = strchr (trp->directive[n], ':');
+ len = p - trp->directive[n];
+ if (len + 1 > trp->tmpsize)
{
- reg->tmpsize = len + 1;
- reg->tmp = x2realloc (reg->tmp, &reg->tmpsize);
+ trp->tmpsize = len + 1;
+ trp->tmp = x2realloc (trp->tmp, &trp->tmpsize);
}
- memcpy (reg->tmp, reg->directive[n], len);
- reg->tmp[len] = 0;
- *pkey = reg->tmp;
+ memcpy (trp->tmp, trp->directive[n], len);
+ trp->tmp[len] = 0;
+ *pkey = trp->tmp;
for (p++; *p && isspace (*p); p++)
;
if (pval)
@@ -111,18 +111,18 @@ _directive_seq_get (int n, struct file_register *reg,
}
int
-directive_first (struct file_register *reg,
+directive_first (struct file_triplet *trp,
const char **pkey, const char **pval)
{
int n = 0;
- return _directive_seq_get (n, reg, pkey, pval);
+ return _directive_seq_get (n, trp, pkey, pval);
}
int
-directive_next (struct file_register *reg, int n,
+directive_next (struct file_triplet *trp, int n,
const char **pkey, const char **pval)
{
- return _directive_seq_get (n, reg, pkey, pval);
+ return _directive_seq_get (n, trp, pkey, pval);
}
int
@@ -144,23 +144,23 @@ directive_pack_version (const char *val, unsigned *pversion)
}
int
-directive_version_in_range_p (struct file_register *reg,
+directive_version_in_range_p (struct file_triplet *trp,
unsigned from, unsigned to)
{
const char *val;
int version;
- if (directive_get_value (reg, "version", &val))
+ if (directive_get_value (trp, "version", &val))
{
logmsg (LOG_ERR, "%s: missing `version' directive",
- reg->file[file_directive].name);
+ trp->file[file_directive].name);
return 0;
}
if (directive_pack_version (val, &version))
{
logmsg (LOG_ERR, "%s: unparsable version: %s",
- reg->file[file_directive].name, val);
+ trp->file[file_directive].name, val);
return 0;
}
@@ -168,7 +168,7 @@ directive_version_in_range_p (struct file_register *reg,
return 1;
logmsg (LOG_ERR, "%s: version %s is not in the allowed range",
- reg->file[file_directive].name, val);
+ trp->file[file_directive].name, val);
return 0;
}
@@ -213,18 +213,18 @@ find_directive (const char *key)
}
int
-verify_directive_format (struct file_register *reg)
+verify_directive_format (struct file_triplet *trp)
{
int n, dnum;
const char *key;
- if (!directive_version_in_range_p (reg, MIN_DIRECTIVE_VERSION,
+ if (!directive_version_in_range_p (trp, MIN_DIRECTIVE_VERSION,
MAX_DIRECTIVE_VERSION))
return 1;
dnum = 0;
- for (n = directive_first (reg, &key, NULL); n;
- n = directive_next (reg, n, &key, NULL))
+ for (n = directive_first (trp, &key, NULL); n;
+ n = directive_next (trp, n, &key, NULL))
{
if (strcmp (key, "comment") == 0)
continue;
@@ -235,7 +235,7 @@ verify_directive_format (struct file_register *reg)
if (strcmp (key, "version"))
{
logmsg (LOG_ERR, "%s:%d: expected `%s' but found `%s'",
- reg->file[file_directive].name, n, "version", key);
+ trp->file[file_directive].name, n, "version", key);
return 1;
}
break;
@@ -244,7 +244,7 @@ verify_directive_format (struct file_register *reg)
if (strcmp (key, "directory"))
{
logmsg (LOG_ERR, "%s:%d: expected `%s' but found `%s'",
- reg->file[file_directive].name, n, "directory", key);
+ trp->file[file_directive].name, n, "directory", key);
return 1;
}
break;
@@ -253,25 +253,25 @@ verify_directive_format (struct file_register *reg)
if (find_directive (key) == unknown_dir)
{
logmsg (LOG_ERR, "%s:%d: unknown directive `%s'",
- reg->file[file_directive].name, n, key);
+ trp->file[file_directive].name, n, key);
return 1;
}
}
}
- if (reg->file[file_dist].name && reg->file[file_signature].name)
+ if (trp->file[file_dist].name && trp->file[file_signature].name)
{
const char *filename;
- if (directive_get_value (reg, "filename", &filename))
+ if (directive_get_value (trp, "filename", &filename))
{
logmsg (LOG_ERR, "%s: missing `filename' directive",
- reg->file[file_directive].name);
+ trp->file[file_directive].name);
return 1;
}
- if (strcmp (filename, reg->file[file_dist].name))
+ if (strcmp (filename, trp->file[file_dist].name))
{
logmsg (LOG_ERR, "%s: filename %s does not match actual name",
- reg->file[file_dist].name, filename);
+ trp->file[file_dist].name, filename);
return 1;
}
}
@@ -279,15 +279,14 @@ verify_directive_format (struct file_register *reg)
}
int
-process_directives (struct file_register *reg, struct directory_pair *dpair)
+process_directives (struct file_triplet *trp, struct directory_pair *dpair)
{
int n;
const char *key, *val;
- char *directory = NULL;
- const char *relative_dir;
+ char *relative_dir;
- for (n = directive_first (reg, &key, &val); n;
- n = directive_next (reg, n, &key, &val))
+ for (n = directive_first (trp, &key, &val); n;
+ n = directive_next (trp, n, &key, &val))
{
enum directive d = find_directive (key);
switch (d)
@@ -298,23 +297,16 @@ process_directives (struct file_register *reg, struct directory_pair *dpair)
case comment_dir:
logmsg (LOG_NOTICE, "%s: COMMENT: %s",
- reg->file[file_directive].name, val);
+ trp->file[file_directive].name, val);
break;
case directory_dir:
- directory = create_directory (dpair->dest_dir, val,
- reg->file[file_dist].uid,
- reg->gid);
- if (!directory)
- return 1;
- relative_dir = val;
+ relative_dir = safe_file_name_alloc (val);
break;
case filename_dir:
- if (move_file (reg, file_dist, directory,
- relative_dir, &dpair->archive)
- || move_file (reg, file_signature, directory,
- relative_dir, &dpair->archive))
+ if (move_file (trp, dpair, file_dist, relative_dir)
+ || move_file (trp, dpair, file_signature, relative_dir))
return 1;
break;
@@ -322,21 +314,53 @@ process_directives (struct file_register *reg, struct directory_pair *dpair)
/* Already processed */
break;
- case rmsymlink_dir:
case archive_dir:
+ if (archive_file (trp, dpair, val, relative_dir))
+ return 1;
+ break;
+
case symlink_dir:
+ {
+ int argc;
+ char **argv;
+ int rc = 0;
+
+ if (rc = argcv_get (val, NULL, NULL, &argc, &argv))
+ {
+ logmsg (LOG_ERR, "cannot parse symlink value `%s': %s",
+ val, strerror (rc));
+ return 1;
+ }
+
+ if (argc != 2)
+ {
+ rc = 1;
+ logmsg (LOG_ERR,
+ "wrong number of arguments to %s directive: `%s'",
+ key, val);
+ }
+ else
+ rc = symlink_file (trp, dpair, relative_dir, argv[0], argv[1]);
+
+ argcv_free (argc, argv);
+ if (rc)
+ return 1;
+ }
+ break;
+
+ case rmsymlink_dir:
logmsg (LOG_CRIT, "%s: %s directive is not supported yet",
- reg->file[file_directive].name, key);
+ trp->file[file_directive].name, key);
}
}
- free (directory);
-
- if (!dry_run_mode && unlink (reg->file[file_directive].name))
+ if (!dry_run_mode && unlink (trp->file[file_directive].name))
{
logmsg (LOG_CRIT, "%s: cannot unlink directive file: %s",
- reg->file[file_directive].name, strerror (errno));
+ trp->file[file_directive].name, strerror (errno));
}
-
+
+ free (relative_dir);
+
return 0;
}
diff --git a/src/diskio.c b/src/diskio.c
index 333c07e..6eaffa0 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -15,8 +15,7 @@
with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "wydawca.h"
-#include <sys/types.h>
-#include <sys/wait.h>
+#include "save-cwd.h"
#if defined USE_SENDFILE
# if defined __linux__ && defined HAVE_SYS_SENDFILE_H
# include <sys/sendfile.h>
@@ -25,6 +24,16 @@
# endif
#endif
+int
+sub_dir_p (char *arg, char *dir)
+{
+ int dlen = strlen (dir);
+
+ return strlen (arg) > dlen
+ && memcmp (dir, arg, dlen) == 0
+ && arg[dlen] == '/';
+}
+
char *
concat_dir (const char *base, const char *name, size_t *pbaselen)
{
@@ -255,9 +264,6 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid)
int
tar_append_file (const char *archive, const char *file)
{
- FILE *fp;
- pid_t pid, npid;
- int i, status;
int rc;
const char *argv[6];
@@ -272,73 +278,19 @@ tar_append_file (const char *archive, const char *file)
argv[3] = "-r";
argv[4] = file;
argv[5] = NULL;
-
- fp = start_prog (6, argv, &pid);
- if (!fp)
- {
- logmsg (LOG_CRIT,
- "cannot start archiver program `%s'", tar_command_name);
- return 1;
- }
-
- for (i = 0; i < 5 && (npid = waitpid (pid, &status, WNOHANG)) == 0; i++)
- sleep (1);
- switch (npid)
+ switch (wydawca_exec (6, argv, NULL))
{
- case -1:
- logmsg (LOG_CRIT,
- "cannot execute archiver program `%s'; waitpid failed: %s",
- tar_command_name, strerror (errno));
- fclose (fp);
- return 1;
+ case exec_success:
+ return 0;
- case 0:
- logmsg (LOG_CRIT,
- "cannot execute archiver program `%s': "
- "program did not respond within 5 seconds: %s",
- tar_command_name, strerror (errno));
- kill (pid, SIGKILL);
- fclose (fp);
- return 1;
-
- default:
+ case exec_fail:
+ case exec_error:
+ logmsg (LOG_ERR, "cannot archive %s", file);
break;
}
- if (WIFEXITED (status))
- {
- rc = WEXITSTATUS (status);
- if (rc)
- {
- logmsg (LOG_ERR, "cannot archive %s: %s finished with code %d",
- file, tar_command_name, rc);
- log_output (LOG_ERR, argv[0], fp);
- }
- else if (debug_level > 1)
- log_output (LOG_DEBUG, argv[0], fp);
- }
- else
- {
- rc = 1;
- if (WIFSIGNALED (status))
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s terminated on signal %d",
- file, tar_command_name, WTERMSIG (status));
- else if (WIFSTOPPED (status))
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s stopped on signal %d",
- file, tar_command_name, WTERMSIG (status));
- else
- logmsg (LOG_ERR,
- "cannot archive %s: "
- "%s terminated with unrecognized status",
- file, tar_command_name);
- }
- fclose (fp);
- return rc;
+ return 1;
}
int
@@ -346,7 +298,7 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
struct archive_descr *archive, uid_t uid, gid_t gid,
const char *reldir)
{
- int rc;
+ int rc = 0;
char *adir;
char *file_name;
@@ -413,9 +365,9 @@ backup_file (const char *dst_file, const char *dst_dir, const char *file,
}
int
-archive_file (const char *dst_file, const char *dst_dir, const char *file,
- struct archive_descr *archive, uid_t uid, gid_t gid,
- const char *reldir)
+do_archive_file (const char *dst_file, const char *dst_dir, const char *file,
+ struct archive_descr *archive, uid_t uid, gid_t gid,
+ const char *reldir)
{
switch (archive->type)
{
@@ -431,28 +383,219 @@ archive_file (const char *dst_file, const char *dst_dir, const char *file,
return 0;
}
-
int
-move_file (struct file_register *reg, enum file_type file_id,
- const char *dst_dir, const char *reldir,
- struct archive_descr *archive)
+move_file (struct file_triplet *trp, struct directory_pair *dpair,
+ enum file_type file_id, const char *reldir)
{
- char *dst_file = concat_dir (dst_dir, reg->file[file_id].name, NULL);
+ char *dst_file;
int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+ dst_file = concat_dir (dst_dir, trp->file[file_id].name, NULL);
if (debug_level)
- logmsg (LOG_DEBUG, "installing %s to %s", reg->file[file_id].name,
+ logmsg (LOG_DEBUG, "installing %s to %s", trp->file[file_id].name,
dst_dir);
if (access (dst_file, F_OK) == 0)
- archive_file (dst_file, dst_dir, reg->file[file_id].name,
- archive, reg->file[file_id].uid, reg->gid, reldir);
+ rc = do_archive_file (dst_file, dst_dir, trp->file[file_id].name,
+ &dpair->archive,
+ TRIPLET_UID (trp), TRIPLET_GID (trp), reldir);
- if (!dry_run_mode)
- rc = do_move_file (reg->file[file_id].name, dst_file,
- reg->file[file_id].uid, reg->gid);
+ if (!dry_run_mode && rc == 0)
+ rc = do_move_file (trp->file[file_id].name, dst_file,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
free (dst_file);
+ free (dst_dir);
return rc;
}
+int
+archive_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *file_name, const char *reldir)
+{
+ char *dst_file;
+ int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+
+ dst_file = safe_file_name (concat_dir (dst_dir, file_name, NULL));
+ if (!sub_dir_p (dst_file, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "file to be archived `%s' does not lie under `%s'",
+ dst_file, dpair->dest_dir);
+ free (dst_file);
+ free (dst_dir);
+ return 1;
+ }
+
+ if (access (dst_file, F_OK) == 0)
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG, "Archiving file `%s'", dst_file);
+ rc = do_archive_file (dst_file, dst_dir, file_name, &dpair->archive,
+ TRIPLET_UID (trp), TRIPLET_GID (trp), reldir);
+ }
+ else
+ logmsg (LOG_NOTICE, "Nothing to archive: file `%s' does not exist",
+ dst_file);
+
+ free (dst_file);
+ free (dst_dir);
+ return rc;
+}
+
+int
+symlink_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *reldir,
+ const char *wanted_src, const char *wanted_dst)
+{
+ char *dst_file;
+ int rc = 0;
+ struct saved_cwd cwd;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+ char *src, *dst;
+
+ if (!dst_dir)
+ return 1;
+
+ if (save_cwd (&cwd))
+ {
+ logmsg (LOG_ERR, "cannot save current directory: %s",
+ strerror (errno));
+ return 1;
+ }
+
+ src = safe_file_name_alloc (wanted_src);
+ if (!sub_dir_p (src, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "symlink source `%s' does not lie under `%s'",
+ src, dpair->dest_dir);
+ free (src);
+ return 1;
+ }
+
+ dst = safe_file_name_alloc (wanted_dst);
+ if (!sub_dir_p (dst, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "symlink destination `%s' does not lie under `%s'",
+ dst, dpair->dest_dir);
+ free (src);
+ free (dst);
+ return 1;
+ }
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "symlinking %s to %s in directory %s",
+ src, dst, dst_dir);
+
+ if (!dry_run_mode)
+ {
+ char *p = strrchr (dst, '/');
+ if (p > dst)
+ {
+ char *dir;
+
+ *p = 0;
+ dir = create_directory (dpair->dest_dir, dst,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+ if (!dir)
+ rc = 1;
+ else
+ free (dir);
+ *p = '/';
+ }
+
+ if (rc == 0)
+ {
+ rc = link (src, dst);
+ if (rc)
+ logmsg (LOG_ERR,
+ "symlinking %s to %s in directory %s failed: %s",
+ src, dst, dst_dir, strerror (errno));
+ }
+ }
+
+ if (restore_cwd (&cwd))
+ {
+ logmsg (LOG_EMERG, "cannot restore current directory: %s",
+ strerror (errno));
+ exit (1);
+ }
+
+ free (src);
+ free (dst);
+ free (dst_dir);
+ return rc;
+}
+
+static int
+do_rmsymlink_file (const char *dst_file)
+{
+ struct stat st;
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "Removing symbolic link %s", dst_file);
+
+ if (stat (dst_file, &st))
+ {
+ if (errno == ENOENT)
+ {
+ logmsg (LOG_NOTICE, "Symlink `%s' does not exist", dst_file);
+ return 0;
+ }
+ if (!S_ISLNK (st.st_mode))
+ {
+ logmsg (LOG_ERR, "Refusing to unlink %s: is not a symlink",
+ dst_file);
+ return 1;
+ }
+ }
+ if (dry_run_mode)
+ return 0;
+ if (unlink (dst_file))
+ {
+ logmsg (LOG_ERR, "Cannot unlink %s: %s", dst_file, strerror (errno));
+ return 1;
+ }
+ return 0;
+}
+
+int
+rmsymlink_file (struct file_triplet *trp, struct directory_pair *dpair,
+ const char *reldir, const char *file_name)
+{
+ char *dst_file;
+ int rc = 0;
+ char *dst_dir = create_directory (dpair->dest_dir, reldir,
+ TRIPLET_UID (trp), TRIPLET_GID (trp));
+
+ if (!dst_dir)
+ return 1;
+
+ dst_file = safe_file_name (concat_dir (dst_dir, file_name, NULL));
+ if (!sub_dir_p (dst_file, dpair->dest_dir))
+ {
+ logmsg (LOG_ERR, "refusing to remove a symlink `%s' that is not "
+ "located under `%s'",
+ dst_file, dpair->dest_dir);
+ free (dst_file);
+ free (dst_dir);
+ return 1;
+ }
+
+ rc = do_rmsymlink_file (dst_file);
+
+ free (dst_file);
+ free (dst_dir);
+ return rc;
+}
+
diff --git a/src/exec.c b/src/exec.c
new file mode 100644
index 0000000..1f9e27a
--- /dev/null
+++ b/src/exec.c
@@ -0,0 +1,155 @@
+/* wydawca - FTP release synchronisation daemon
+ Copyright (C) 2007 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 <http://www.gnu.org/licenses/>. */
+
+#include "wydawca.h"
+#include "save-cwd.h"
+#include <gpgme.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+static FILE *
+start_prog (int argc, const char **argv, pid_t *ppid)
+{
+ int p[2];
+ FILE *fp;
+ pid_t pid;
+ int i;
+
+ pipe (p);
+ switch (pid = fork ())
+ {
+ case 0:
+ /* Child process */
+
+ if (p[1] != 1)
+ dup2 (p[1], 1);
+ if (p[1] != 1)
+ dup2 (p[1], 2);
+ close (p[0]);
+
+ /* Close unneded descripitors */
+ for (i = getmaxfd (); i > 2; i--)
+ close (i);
+
+ execvp (argv[0], (char**) argv);
+ logmsg (LOG_CRIT, "cannot run %s: %s", argv[0], strerror (errno));
+ exit (1);
+
+ case -1:
+ logmsg (LOG_CRIT, "cannot run `%s': fork failed: %s",
+ argv[0], strerror (errno));
+ return NULL;
+
+ default:
+ /* Master process */
+ close (p[1]);
+ fp = fdopen (p[0], "r");
+ if (!fp)
+ logmsg (LOG_ERR, "cannot fdopen: %s", strerror (errno));
+ *ppid = pid;
+ }
+ return fp;
+}
+
+void
+log_output (int prio, const char *prog, FILE *fp)
+{
+ size_t size = 0;
+ char *buf = NULL;
+
+ logmsg (prio, "%s output follows:", prog);
+ while (getline (&buf, &size, fp) > 0)
+ logmsg (prio, "%s", buf);
+ logmsg (prio, "end of %s output", prog);
+ free (buf);
+}
+
+enum exec_result
+wydawca_exec (int argc, const char **argv, int *retcode)
+{
+ FILE *fp;
+ pid_t pid, npid;
+ int status;
+ int i;
+ enum exec_result res;
+
+ fp = start_prog (5, argv, &pid);
+ if (!fp)
+ {
+ logmsg (LOG_CRIT, "cannot start %s", argv[0]);
+ return exec_error;
+ }
+
+ for (i = 0; i < 5 && (npid = waitpid (pid, &status, WNOHANG)) == 0; i++)
+ sleep (1);
+
+ switch (npid)
+ {
+ case -1:
+ logmsg (LOG_CRIT, "cannot execute %s: waitpid failed: %s",
+ argv[0], strerror (errno));
+ fclose (fp);
+ return exec_error;
+
+ case 0:
+ logmsg (LOG_CRIT,
+ "cannot execute %s: the process did not respond "
+ "within 5 seconds: %s",
+ argv[0], strerror (errno));
+ kill (pid, SIGKILL);
+ fclose (fp);
+ return exec_error;
+
+ default:
+ break;
+ }
+
+ if (WIFEXITED (status))
+ {
+ int rc = WEXITSTATUS (status);