diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-21 19:01:41 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2007-08-21 19:01:41 +0000 |
commit | 708a28a2f5bd2384e4c254a47d069ec4d9ef697e (patch) | |
tree | 72a6e227fbbf75cc04d5b4e5c560cb58964761b3 /src/diskio.c | |
parent | 5d2f6b08d164d0106ef2377ceb01393226eeafef (diff) | |
download | wydawca-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.c | 198 |
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; |