aboutsummaryrefslogtreecommitdiff
path: root/src/diskio.c
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-08-21 19:01:41 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-08-21 19:01:41 +0000
commit708a28a2f5bd2384e4c254a47d069ec4d9ef697e (patch)
tree72a6e227fbbf75cc04d5b4e5c560cb58964761b3 /src/diskio.c
parent5d2f6b08d164d0106ef2377ceb01393226eeafef (diff)
downloadwydawca-708a28a2f5bd2384e4c254a47d069ec4d9ef697e.tar.gz
wydawca-708a28a2f5bd2384e4c254a47d069ec4d9ef697e.tar.bz2
Implement archiving and backups
git-svn-id: file:///svnroot/wydawca/trunk@282 6bb4bd81-ecc2-4fd4-a2d4-9571d19c0d33
Diffstat (limited to 'src/diskio.c')
-rw-r--r--src/diskio.c198
1 files changed, 194 insertions, 4 deletions
diff --git a/src/diskio.c b/src/diskio.c
index 13694da..333c07e 100644
--- a/src/diskio.c
+++ b/src/diskio.c
@@ -15,6 +15,8 @@
with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "wydawca.h"
+#include <sys/types.h>
+#include <sys/wait.h>
#if defined USE_SENDFILE
# if defined __linux__ && defined HAVE_SYS_SENDFILE_H
# include <sys/sendfile.h>
@@ -251,16 +253,204 @@ do_move_file (const char *file, const char *dst_file, uid_t uid, gid_t gid)
}
int
-move_file (const char *file, const char *dst_dir, uid_t uid, gid_t gid)
+tar_append_file (const char *archive, const char *file)
{
- char *dst_file = concat_dir (dst_dir, file, NULL);
+ FILE *fp;
+ pid_t pid, npid;
+ int i, status;
+ int rc;
+ const char *argv[6];
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "tarring %s to %s", file, archive);
+ if (dry_run_mode)
+ return 0;
+
+ argv[0] = tar_command_name;
+ argv[1] = "-f";
+ argv[2] = archive;
+ 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)
+ {
+ case -1:
+ logmsg (LOG_CRIT,
+ "cannot execute archiver program `%s'; waitpid failed: %s",
+ tar_command_name, strerror (errno));
+ fclose (fp);
+ return 1;
+
+ 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:
+ 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;
+}
+
+int
+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;
+ char *adir;
+ char *file_name;
+
+ if (archive->name[0] == '/')
+ adir = create_directory (archive->name, reldir, uid, gid);
+ else
+ adir = create_directory (dst_dir, archive->name, uid, gid);
+ if (!adir)
+ return 1;
+
+ file_name = concat_dir (adir, file, NULL);
+ if (access (file_name, F_OK) == 0)
+ {
+ if (archive->backup_type == no_backups)
+ {
+ if (debug_level)
+ logmsg (LOG_DEBUG, "removing previous archive file `%s'",
+ file_name);
+ if (!dry_run_mode && unlink (file_name))
+ {
+ logmsg (LOG_ERR, "cannot unlink previous archive file `%s': %s",
+ file_name, strerror (errno));
+ free (file_name);
+ free (adir);
+ return 1;
+ }
+ }
+ else
+ {
+ char *archive_file_name =
+ find_backup_file_name (file_name, archive->backup_type);
+ if (debug_level)
+ logmsg (LOG_DEBUG, "backing up previous archive file `%s' to `%s'",
+ file_name, archive_file_name);
+ if (!dry_run_mode)
+ {
+ rc = do_move_file (file_name, archive_file_name, uid, gid);
+ if (rc)
+ {
+ logmsg (LOG_ERR, "backing `%s' up as `%s' failed: %s",
+ file_name, archive_file_name, strerror (errno));
+ free (archive_file_name);
+ free (file_name);
+ free (adir);
+ return 1;
+ }
+ }
+ free (archive_file_name);
+ }
+ }
+
+ if (debug_level)
+ logmsg (LOG_DEBUG, "archiving `%s' to `%s'", dst_file, file_name);
+ if (!dry_run_mode)
+ {
+ rc = do_move_file (dst_file, file_name, uid, gid);
+ if (rc)
+ logmsg (LOG_ERR, "archiving `%s' as `%s' failed: %s",
+ dst_file, file_name, strerror (errno));
+ }
+ free (file_name);
+ free (adir);
+ return rc;
+}
+
+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)
+{
+ switch (archive->type)
+ {
+ case archive_none:
+ break;
+
+ case archive_directory:
+ return backup_file (dst_file, dst_dir, file, archive, uid, gid, reldir);
+
+ case archive_tar:
+ return tar_append_file (archive->name, dst_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)
+{
+ char *dst_file = concat_dir (dst_dir, reg->file[file_id].name, NULL);
int rc = 0;
if (debug_level)
- logmsg (LOG_DEBUG, "installing %s to %s", file, dst_dir);
+ logmsg (LOG_DEBUG, "installing %s to %s", reg->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);
+
if (!dry_run_mode)
- rc = do_move_file (file, dst_file, uid, gid);
+ rc = do_move_file (reg->file[file_id].name, dst_file,
+ reg->file[file_id].uid, reg->gid);
free (dst_file);
return rc;

Return to:

Send suggestions and report system problems to the System administrator.