Commit 025efe13 authored by Per Cederqvist's avatar Per Cederqvist

This should be a working first try.

parent 7c353460
/*
* splitkomdb -- Split the database for efficient incremental backups
* Copyright (C) 1999 Lysator Academic Computer Association.
*
* This file is part of the LysKOM server.
*
* LysKOM 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 1, or (at your option)
* any later version.
*
* LysKOM 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 LysKOM; see the file COPYING. If not, write to
* Lysator, c/o ISY, Linkoping University, S-581 83 Linkoping, SWEDEN,
* or the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
* Please mail bug reports to bug-lyskom@lysator.liu.se.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include "kom-types.h"
#include "s-string.h"
#include "string-malloc.h"
#include "server/smalloc.h"
#include "kom-config.h"
#include "server-config.h"
#include "param.h"
/* The current version of splitkomdb uses three files to store all state.
You can restore the database with commands similar to these:
cat $text_base $text_tail > lyskomd-texts
cp $data_copy lyskomd-data
Future versions of this program may use a more elaborate layout of
the contents of the backup directory. That is why you can
configure the location of the directory, but not the file names
used within that directory. */
static const char *text_base = NULL;
static const char *text_tail = NULL;
static const char *data_copy = NULL;
static const char *argv0;
static char *
create_filename(const char *suffix)
{
char *res = smalloc(strlen(param.backup_dir) + 1 + strlen(suffix) + 1);
sprintf(res, "%s/%s", param.backup_dir, suffix);
return res;
}
static void
compute_filenames(void)
{
text_base = create_filename("lyskomd-texts-base.backup");
text_tail = create_filename("lyskomd-texts-tail.backup");
data_copy = create_filename("lyskomd-data.backup");
}
static void
safe_remove(const char *filename)
{
errno = 0;
if (remove(filename) != 0 && errno != ENOENT)
{
perror(filename);
exit(1);
}
}
static void
usage(const char *arg0)
{
fprintf(stderr, "usage: %s [-c config-file] [ -v ] [ -V ]\n",
arg0);
exit(1);
}
static int
is_clean(FILE *fp)
{
return (getc(fp) == 'C' &&
getc(fp) == 'L' &&
getc(fp) == 'E' &&
getc(fp) == 'A' &&
getc(fp) == 'N');
}
static void
copy_file(const char *from,
FILE *fromfp,
const char *to)
{
char buf[BUFSIZ];
FILE *tofp;
int sz;
if ((tofp = fopen(to, "w")) == NULL)
{
fprintf(stderr, "%s: opening ", argv0);
perror(to);
exit(1);
}
if (setvbuf(tofp, NULL, _IONBF, 0) != 0)
{
perror("setvbuf");
exit(1);
}
while (1)
{
sz = fread(buf, 1, BUFSIZ, fromfp);
if (ferror(fromfp))
{
fprintf(stderr, "%s: error reading from ", argv0);
perror(from);
exit(1);
}
if (sz == 0)
break;
if (fwrite(buf, 1, sz, tofp) != sz)
{
fprintf(stderr, "%s: writing to ", argv0);
perror(to);
exit(1);
}
}
if (ferror(tofp))
{
fprintf(stderr, "%s: writing to ", argv0);
perror(to);
exit(1);
}
if (fclose(tofp) != 0)
{
fprintf(stderr, "%s: closing ", argv0);
perror(to);
exit(1);
}
}
static void
copy_db_file(void)
{
FILE *fp;
const char *from;
fp = fopen((from = param.datafile_name), "r");
if (fp == NULL || !is_clean(fp))
{
if (fp != NULL)
fclose(fp);
fp = fopen((from = param.backupfile_name), "r");
assert(is_clean(fp));
}
if (fseek(fp, 0, SEEK_SET) != 0)
{
perror("fseek");
exit(1);
}
copy_file(from, fp, data_copy);
fclose(fp);
}
static int
file_equal(const char *from,
FILE *fromfp,
const char *assumed_copy)
{
FILE *copyfp;
int c1;
int c2;
if ((copyfp = fopen(assumed_copy, "r")) == NULL)
{
if (errno == ENOENT)
return 0;
fprintf(stderr, "%s: opening ", argv0);
perror(assumed_copy);
exit(1);
}
while (1)
{
if ((c1 = getc(copyfp)) == EOF)
{
if (ferror(copyfp))
{
fclose(copyfp);
return 0;
}
else
{
fclose(copyfp);
return 1;
}
}
if ((c2 = getc(fromfp)) == EOF || c1 != c2)
{
if (ferror(fromfp))
{
fprintf(stderr, "%s: reading ", argv0);
perror(from);
exit(1);
}
fclose(copyfp);
return 0;
}
}
}
static void
copy_text_file(void)
{
FILE *fromfp;
if ((fromfp = fopen(param.textfile_name, "r")) == NULL)
{
fprintf(stderr, "%s: opening ", argv0);
perror(param.textfile_name);
exit(1);
}
if (file_equal(param.textfile_name, fromfp, text_base))
{
copy_file(param.textfile_name, fromfp, text_tail);
fclose(fromfp);
}
else
{
safe_remove(text_base);
safe_remove(text_tail);
if (fseek(fromfp, 0, SEEK_SET) != 0)
{
perror("fseek");
exit(1);
}
copy_file(param.textfile_name, fromfp, text_base);
}
}
int
main (int argc,
char **argv)
{
int i;
char *default_config_file = NULL;
char *config_file = NULL;
int fulldump = 0;
if (getuid() == 0 || geteuid() == 0)
{
fprintf(stderr, "%s: this program should run as lyskom, not root\n",
argv[0]);
exit(1);
}
argv0 = argv[0];
/* Initialize the string handling package. */
s_set_storage_management(string_malloc, string_realloc, string_free);
/* Parse command line arguments. */
for (i = 1; i < argc && argv[i][0] == '-'; i++)
{
if (argv[i][1] == '\0' || argv[i][2] != '\0')
usage(argv[0]);
switch (argv[i][1])
{
case 'c':
if (config_file != NULL)
{
fprintf(stderr, "%s: -c may only be used once\n", argv[0]);
exit(1);
}
if (++i >= argc)
usage(argv[0]);
config_file = argv[i];
break;
case 'f':
if (fulldump != 0)
{
fprintf(stderr, "%s: -f may only be used once\n", argv[0]);
exit(1);
}
fulldump = 1;
break;
case 'V':
case 'v':
fprintf(stderr, "splitkomdb from %s-%s\n", PACKAGE, VERSION);
exit(0);
default:
usage(argv[0]);
}
}
if (i < argc)
usage(argv[0]);
/* Read in the configuration file. */
if (config_file == NULL)
{
default_config_file = smalloc(strlen(DEFAULT_DBASE_DIR) +
strlen(CONFIG_FILE) + 2);
sprintf(default_config_file, "%s/%s", DEFAULT_DBASE_DIR, CONFIG_FILE);
config_file = default_config_file;
}
read_configuration(config_file);
compute_filenames();
if (fulldump)
{
safe_remove(text_base);
safe_remove(text_tail);
safe_remove(data_copy);
}
copy_db_file();
copy_text_file();
exit(0);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment