Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
config: add automatic backup at upgrade using 'tar cvjf' to <CFG>/bac…
…kup directory
  • Loading branch information
perexg committed Sep 8, 2014
1 parent fe47889 commit 95c4abe
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 49 deletions.
93 changes: 86 additions & 7 deletions src/config.c
Expand Up @@ -16,13 +16,15 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include <string.h>
#include <sys/stat.h>

#include "tvheadend.h"
#include "settings.h"
#include "config.h"
#include "uuid.h"

#include <string.h>
#include <sys/stat.h>
#include "htsbuf.h"
#include "spawn.h"

/* *************************************************************************
* Global data
Expand Down Expand Up @@ -956,6 +958,70 @@ config_migrate_v11 ( void )
htsmsg_destroy(dvr_config);
}

/*
* Perform backup
*/
static void
dobackup(const char *oldver)
{
char outfile[PATH_MAX], cwd[PATH_MAX];
const char *argv[] = {
"/usr/bin/tar", "cjf", outfile, "--exclude", "backup", ".", NULL
};
const char *root = hts_settings_get_root();
char errtxt[128];
const char **arg;
int code;

tvhinfo("config", "backup: migrating config from %s (running %s)",
oldver, tvheadend_version);

getcwd(cwd, sizeof(cwd));

snprintf(outfile, sizeof(outfile), "%s/backup", root);
if (makedirs(outfile, 0700))
goto fatal;
if (chdir(root)) {
tvherror("config", "unable to find directory '%s'", root);
goto fatal;
}

snprintf(outfile, sizeof(outfile), "%s/backup/%s.tar.bz2",
root, oldver);
tvhinfo("config", "backup: running, output file %s", outfile);

spawnv(argv[0], (void *)argv);

while ((code = spawn_reap(errtxt, sizeof(errtxt))) == -EAGAIN)
usleep(20000);

if (code) {
htsbuf_queue_t q;
char *s;
htsbuf_queue_init(&q, 0);
for (arg = argv; *arg; arg++) {
htsbuf_append(&q, *arg, strlen(*arg));
if (arg[1])
htsbuf_append(&q, " ", 1);
}
s = htsbuf_to_string(&q);
tvherror("config", "command '%s' returned error code %d", s, code);
free(s);
htsbuf_queue_flush(&q);
goto fatal;
}

if (chdir(cwd)) {
tvherror("config", "unable to change directory to '%s'", cwd);
goto fatal;
}
return;

fatal:
tvherror("config", "backup: fatal error");
exit(EXIT_FAILURE);
}

/*
* Migration table
*/
Expand All @@ -977,12 +1043,19 @@ static const config_migrate_t config_migrate_table[] = {
* Perform migrations (if required)
*/
static int
config_migrate ( void )
config_migrate ( int backup )
{
uint32_t v;
const char *s;

/* Get the current version */
v = htsmsg_get_u32_or_default(config, "version", 0);
s = htsmsg_get_str(config, "fullversion") ?: "unknown";

if (backup && strcmp(s, tvheadend_version))
dobackup(s);
else
backup = 0;

/* Attempt to auto-detect versions prior to v2 */
if (!v) {
Expand All @@ -993,8 +1066,11 @@ config_migrate ( void )
}

/* No changes required */
if (v == ARRAY_SIZE(config_migrate_table))
if (v == ARRAY_SIZE(config_migrate_table)) {
if (backup)
goto update;
return 0;
}

/* Run migrations */
for ( ; v < ARRAY_SIZE(config_migrate_table); v++) {
Expand All @@ -1003,7 +1079,9 @@ config_migrate ( void )
}

/* Update */
update:
htsmsg_set_u32(config, "version", v);
htsmsg_set_str(config, "fullversion", tvheadend_version);
config_save();
return 1;
}
Expand Down Expand Up @@ -1050,7 +1128,7 @@ config_check ( void )
* *************************************************************************/

void
config_init ( const char *path )
config_init ( const char *path, int backup )
{
struct stat st;
char buf[1024];
Expand Down Expand Up @@ -1095,11 +1173,12 @@ config_init ( const char *path )
/* Store version number */
if (new) {
htsmsg_set_u32(config, "version", ARRAY_SIZE(config_migrate_table));
htsmsg_set_str(config, "fullversion", tvheadend_version);
config_save();

/* Perform migrations */
} else {
if (config_migrate())
if (config_migrate(backup))
config_check();
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/config.h
Expand Up @@ -23,7 +23,7 @@

#include "htsmsg.h"

void config_init ( const char *path );
void config_init ( const char *path, int backup );
void config_done ( void );
void config_save ( void );

Expand Down
6 changes: 4 additions & 2 deletions src/main.c
Expand Up @@ -484,7 +484,8 @@ main(int argc, char **argv)
opt_dump = 0,
opt_xspf = 0,
opt_dbus = 0,
opt_dbus_session = 0;
opt_dbus_session = 0,
opt_nobackup = 0;
const char *opt_config = NULL,
*opt_user = NULL,
*opt_group = NULL,
Expand All @@ -507,6 +508,7 @@ main(int argc, char **argv)

{ 0, NULL, "Service Configuration", OPT_BOOL, NULL },
{ 'c', "config", "Alternate config path", OPT_STR, &opt_config },
{ 'B', "nobackup", "Do not backup config tree at upgrade", OPT_BOOL, &opt_nobackup },
{ 'f', "fork", "Fork and run as daemon", OPT_BOOL, &opt_fork },
{ 'u', "user", "Run as user", OPT_STR, &opt_user },
{ 'g', "group", "Run as group", OPT_STR, &opt_group },
Expand Down Expand Up @@ -787,7 +789,7 @@ main(int argc, char **argv)
/* Initialise configuration */
uuid_init();
idnode_init();
config_init(opt_config);
config_init(opt_config, opt_nobackup == 0);

/**
* Initialize subsystems
Expand Down
9 changes: 5 additions & 4 deletions src/settings.c
Expand Up @@ -184,21 +184,22 @@ hts_settings_save(htsmsg_t *record, const char *pathfmt, ...)
static htsmsg_t *
hts_settings_load_one(const char *filename)
{
ssize_t n;
ssize_t n, size;
char *mem;
fb_file *fp;
htsmsg_t *r = NULL;

/* Open */
if (!(fp = fb_open(filename, 1, 0))) return NULL;
size = fb_size(fp);

/* Load data */
mem = malloc(fb_size(fp)+1);
n = fb_read(fp, mem, fb_size(fp));
mem = malloc(size+1);
n = fb_read(fp, mem, size);
if (n >= 0) mem[n] = 0;

/* Decode */
if(n == fb_size(fp))
if(n == size)
r = htsmsg_json_deserialize(mem);

/* Close */
Expand Down
76 changes: 41 additions & 35 deletions src/spawn.c
Expand Up @@ -84,50 +84,56 @@ find_exec ( const char *name, char *out, size_t len )
}

/**
* The reaper is called once a second to finish of any pending spawns
* Reap one child
*/
void
spawn_reaper(void)
int
spawn_reap(char *stxt, size_t stxtlen)
{
pid_t pid;
int status;
char txt[100];
int status, res;
spawn_t *s;

while(1) {
pid = waitpid(-1, &status, WNOHANG);
if(pid < 1)
pid = waitpid(-1, &status, WNOHANG);
if(pid < 1)
return -EAGAIN;

pthread_mutex_lock(&spawn_mutex);
LIST_FOREACH(s, &spawns, link)
if(s->pid == pid)
break;

pthread_mutex_lock(&spawn_mutex);
LIST_FOREACH(s, &spawns, link)
if(s->pid == pid)
break;

if (WIFEXITED(status)) {
snprintf(txt, sizeof(txt),
"exited, status=%d", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
snprintf(txt, sizeof(txt),
"killed by signal %d", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
snprintf(txt, sizeof(txt),
"stopped by signal %d", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
snprintf(txt, sizeof(txt),
"continued");
} else {
snprintf(txt, sizeof(txt),
"unknown status");
}
res = -EIO;
if (WIFEXITED(status)) {
res = WEXITSTATUS(status);
if (stxt)
snprintf(stxt, stxtlen, "exited, status=%d", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
snprintf(stxt, stxtlen, "killed by signal %d, "
"stopped by signal %d",
WTERMSIG(status),
WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
snprintf(stxt, stxtlen, "continued");
} else {
snprintf(stxt, stxtlen, "unknown status");
}

if(s != NULL) {
LIST_REMOVE(s, link);
free((void *)s->name);
free(s);
}
pthread_mutex_unlock(&spawn_mutex);
if(s != NULL) {
LIST_REMOVE(s, link);
free((void *)s->name);
free(s);
}
pthread_mutex_unlock(&spawn_mutex);
return res;
}

/**
* The reaper is called once a second to finish of any pending spawns
*/
void
spawn_reaper(void)
{
while (spawn_reap(NULL, 0) != -EAGAIN) ;
}


Expand Down
2 changes: 2 additions & 0 deletions src/spawn.h
Expand Up @@ -25,6 +25,8 @@ int spawn_and_store_stdout(const char *prog, char *argv[], char **outp);

int spawnv(const char *prog, char *argv[]);

int spawn_reap(char *stxt, size_t stxtlen);

void spawn_reaper(void);

#endif /* SPAWN_H */

0 comments on commit 95c4abe

Please sign in to comment.