Logo Search packages:      
Sourcecode: gadmin-rsync version File versions

save_backup_settings.c

/* GAdmin-Rsync - An easy to use GTK+ frontend for the rsync backup client and server.
 * Copyright (C) 2007 Magnus Loef <magnus-swe@telia.com> 
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
*/



#include "../config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <gtk/gtk.h>
#include "gettext.h"
#include "widgets.h"
#include "show_info.h"
#include "allocate.h"
#include "save_backup_settings.h"
#include "cron_functions.h"
#include "commands.h"


extern gchar *global_settings_dir;
extern gchar *global_scripts_dir;
extern gchar *global_backup_name;

/* Error info flags */
int error_src_dst_info = 1;
int error_server_server_info = 1;


int has_value(gchar *input)
{
    int ret = 0;

    if( input!=NULL && strlen(input) > 0 )
      ret = 1;
      
    return ret;
}


void free_values(gchar *a1, gchar *a2, gchar *a3, 
             gchar *a4, gchar *a5, gchar *a6,
             gchar *a7, gchar *a8, gchar *a9)
{
    if( a1!=NULL ) g_free(a1);
    if( a2!=NULL ) g_free(a2);
    if( a3!=NULL ) g_free(a3);
    if( a4!=NULL ) g_free(a4);
    if( a5!=NULL ) g_free(a5);
    if( a6!=NULL ) g_free(a6);
    if( a7!=NULL ) g_free(a7);
    if( a8!=NULL ) g_free(a8);
}


/* For each in the rsync treeview, save backup settings and scripts */
gboolean save_foreach(GtkTreeModel *model, GtkTreePath *path,
                      GtkTreeIter *iter, struct w *widgets)
{
    FILE *fp;
    gchar *settings_file, *setting=NULL, *script_file, *script, *log_file, *info;
    gchar *src_server=NULL, *src_path=NULL, *dst_server=NULL, *dst_path=NULL;
    gchar *include_files=NULL, *exclude_files=NULL;
    gint include_in_backup_script = 0;
    gint del_dst_not_in_src = 0;
    gchar *user=NULL, *port=NULL, *priv_key_path;

    gchar *source=NULL, *destination=NULL;

    /* Get source server */
    gtk_tree_model_get(model, iter, 0, &src_server, -1);

    /* Get source path */
    gtk_tree_model_get(model, iter, 1, &src_path, -1);

    /* Get destination server */
    gtk_tree_model_get(model, iter, 2, &dst_server, -1);

    /* Get destination path */
    gtk_tree_model_get(model, iter, 3, &dst_path, -1);

    /* Get include files */
    gtk_tree_model_get(model, iter, 4, &include_files, -1);

    /* Get exclude files */
    gtk_tree_model_get(model, iter, 5, &exclude_files, -1);

    /* Get include in backup checkbox value */
    gtk_tree_model_get(model, iter, 6, &include_in_backup_script, -1);

    /* Get include in backup checkbox value */
    gtk_tree_model_get(model, iter, 7, &del_dst_not_in_src, -1);

    /* Get user */
    gtk_tree_model_get(model, iter, 8, &user, -1);
    /* Get port */
    gtk_tree_model_get(model, iter, 9, &port, -1);
    /* Get priv key path */
    gtk_tree_model_get(model, iter, 10, &priv_key_path, -1);


    /* There must always be a source and a destination directory */
    if( ! has_value(src_path) || ! has_value(dst_path) )
    {
      if( error_src_dst_info )
      {
          error_src_dst_info = 0; /* Dont show this again */
          info = g_strdup_printf(_("Error: This backup is missing a required source or destination path.\n"));
          show_info(info);
          g_free(info);
      }
    }

    /* Rsync cant do server to server backups */
    if( has_value(src_server) && has_value(dst_server) )
    {
      if( error_server_server_info )
      {
          error_server_server_info = 0;
          info = g_strdup_printf(_("Error: Server to server backups are not supported by rsync.\n"));
          show_info(info);
          g_free(info);
      }
    }

    /* Open the settings file for appending */
    settings_file = g_strdup_printf("%s/%s", global_settings_dir, global_backup_name);
    if((fp=fopen(settings_file, "a"))==NULL)
    {
      info = g_strdup_printf(_("Error: Can not write settings here:\n%s\n"), settings_file);
        show_info(info);
        g_free(info);

      free_values(src_server, src_path, dst_server, 
                 dst_path, user, port, priv_key_path, 
                         include_files, exclude_files);

      if( priv_key_path!=NULL )
          g_free(priv_key_path);

      if( settings_file!=NULL )
          g_free(settings_file);

        return TRUE; /* Stop iterating on write failure */
    }

    /* Append settings to the settings file */
    if( has_value(src_server) )
    {
      setting = g_strdup_printf("src_server %s\n", src_server);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(src_path) )
    {
      setting = g_strdup_printf("src_path %s\n", src_path);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(dst_server) )
    {
      setting = g_strdup_printf("dst_server %s\n", dst_server);
      fputs(setting, fp);
      g_free(setting);
    }    
    if( has_value(dst_path) )
    {
      setting = g_strdup_printf("dst_path %s\n", dst_path);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(user) )
    {
      setting = g_strdup_printf("server_user %s\n", user);
      fputs(setting, fp);
      g_free(setting);
    }    
    if( has_value(port) )
    {
      setting = g_strdup_printf("server_port %s\n", port);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(priv_key_path) )
    {
      setting = g_strdup_printf("priv_key_path %s\n", priv_key_path);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(include_files) )
    {
      setting = g_strdup_printf("include_files %s\n", include_files);
      fputs(setting, fp);
      g_free(setting);
    }
    if( has_value(exclude_files) )
    {
      setting = g_strdup_printf("exclude_files %s\n", exclude_files);
      fputs(setting, fp);
      g_free(setting);
    }
    setting = g_strdup_printf("include_value %d\n", include_in_backup_script);
    fputs(setting, fp);
    g_free(setting);

    setting = g_strdup_printf("del_dst_files_value %d\n\n", del_dst_not_in_src);
    fputs(setting, fp);
    g_free(setting);
    
    /* Close the settings file */
    fclose(fp);

    if( settings_file!=NULL )
      g_free(settings_file);


    /* Return false if this backup should not be written
       to the backup script. Iteration will continue. */
    if( ! include_in_backup_script )
    {
      free_values(src_server, src_path, dst_server, 
                 dst_path, user, port, priv_key_path, 
                         include_files, exclude_files);
      return FALSE;
    }


    /* Open the backup script file for appending */
    script_file = mk_script_path(global_backup_name);
    if((fp=fopen(script_file, "a"))==NULL)
    {
      info = g_strdup_printf(_("Error: Can not write backup script here:\n%s\n"), script_file);
        show_info(info);
        g_free(info);

        if( script_file!=NULL )
        g_free(script_file);

      free_values(src_server, src_path, dst_server, 
                 dst_path, user, port, priv_key_path, 
                         include_files, exclude_files);
        return TRUE; /* Stop iterating on write failure */
    }



    /* Create the log file path */
    log_file = mk_log_path(global_backup_name);



/* --- Local to Local backup --- */
    if( ! has_value(src_server) && ! has_value(dst_server) )
    {
      /* rsync -av -e /src /dst */

      /* Start timestamp */
      fputs("START_TIME=`date +%Y-%m-%d_%H:%M:%S`;\n", fp);

      /* Only log if theres no destination path.
         USB-disks with sleep-modes can loose contact and dismount or not mount etc */
      setting = g_strconcat("if [ ! -e '", dst_path, "' ]; then\n",
      "     MISSING_PATH=1\n",
      "     echo -n Missing_destination_path:_ >> ", log_file,"\n",
      "else\n",
      "     MISSING_PATH=0\n",
      NULL);
      fputs(setting, fp);
      g_free(setting);

      if( del_dst_not_in_src )
        fputs("rsync --archive --human-readable --verbose --stats --delete --force", fp);
      else
        fputs("rsync --archive --human-readable --verbose --stats", fp);

      /* Add a detailed log for each backup */
      setting = g_strdup_printf(" --log-file=%s.details", log_file);
      fputs(setting, fp);
      g_free(setting);

      if( has_value(include_files) )
      {
          fputs(" --include=\"", fp);
          fputs(include_files, fp);
          fputs("\"", fp);
      }

      if( has_value(exclude_files) )
      {
          fputs(" --exclude=\"", fp);
          fputs(exclude_files, fp);
          fputs("\"", fp);
      }

      fputs(" '", fp);
      fputs(src_path, fp);
      fputs("' '", fp);
      fputs(dst_path, fp);
      fputs("'", fp);
      fputs("\nfi\n\n", fp);

      /* Save source and destination */
      source = g_strdup_printf("%s", src_path);
      destination = g_strdup_printf("%s", dst_path);
    }
/* --- Local to Local backup end --- */



/* --- Remote to Local backup --- */
    if( has_value(src_server) )
    {
      /* rsync -av -e "ssh -l root -p 30000 -i /path/keys/root.192.168.0.100.key" root@192.168.0.100:/src /dest */

      /* Start timestamp */
      fputs("START_TIME=`date +%Y-%m-%d_%H:%M:%S`;\n", fp);

      setting = g_strconcat("if [ ! -e '", dst_path, "' ]; then\n",
      "     MISSING_PATH=1\n",
      "     echo -n Missing_destination_path:_ >> ", log_file,"\n",
      "else\n",
      "     MISSING_PATH=0\n",
      NULL);
      fputs(setting, fp);
      g_free(setting);

      if( del_dst_not_in_src )
        fputs("rsync --archive --progress --human-readable --verbose --stats --delete --force", fp);
      else
        fputs("rsync --archive --progress --human-readable --verbose --stats", fp);

      /* Add a detailed log for each backup */
      setting = g_strdup_printf(" --log-file=%s.details", log_file);
      fputs(setting, fp);
      g_free(setting);

      
      if( has_value(include_files) )
      {
          fputs(" --include=\"", fp);
          fputs(include_files, fp);
          fputs("\"", fp);
      }

      if( has_value(exclude_files) )
      {
          fputs(" --exclude=\"", fp);
          fputs(exclude_files, fp);
          fputs("\"", fp);
      }

      fputs(" -e \"", fp);
      fputs(SSH_BINARY, fp);
      fputs(" -l ", fp);
      fputs(user, fp);
      fputs(" -p ", fp);
      fputs(port, fp);
      fputs(" -i ", fp);
      fputs(priv_key_path, fp);
      fputs("\" ", fp);
      fputs(user, fp);
      fputs("@", fp);
      fputs(src_server, fp);
      fputs(":'", fp);
      fputs(src_path, fp);
      fputs("' '",fp);
      fputs(dst_path, fp);
      fputs("'",fp);
      fputs("\nfi\n\n", fp);

      /* For the log function */
      source = g_strdup_printf("%s%s", src_server, src_path);
      destination = g_strdup_printf("%s", dst_path);
    }
/* --- Remote to Local backup and --- */



/* --- Local to Remote backup --- */
    if( has_value(dst_server) )
    {
      /* rsync -av -e "ssh -l root -p 30000 -i /path/keys/root.192.168.0.100.key" /src root@192.168.0.100:/dst */

      /* Start timestamp */
      fputs("START_TIME=`date +%Y-%m-%d_%H:%M:%S`;\n", fp);

      setting = g_strconcat("if [ ! -e '", src_path, "' ]; then\n",
      "     MISSING_PATH=1\n",
      "     echo -n Missing_source_path:_ >> ", log_file,"\n",
      "else\n",
      "     MISSING_PATH=0\n",
      NULL);
      fputs(setting, fp);
      g_free(setting);

      if( del_dst_not_in_src )
        fputs("rsync --archive --progress --human-readable --verbose --stats --delete --force", fp);
      else
        fputs("rsync --archive --progress --human-readable --verbose --stats", fp);

      /* Add a detailed log for each backup */
      setting = g_strdup_printf(" --log-file=%s.details", log_file);
      fputs(setting, fp);
      g_free(setting);

      if( has_value(include_files) )
      {
          fputs(" --include=\"", fp);
          fputs(include_files, fp);
          fputs("\"", fp);
      }

      if( has_value(exclude_files) )
      {
          fputs(" --exclude=\"", fp);
          fputs(exclude_files, fp);
          fputs("\"", fp);
      }

      fputs(" -e \"", fp);
      fputs(SSH_BINARY, fp);
      fputs(" -l ", fp);
      fputs(user, fp);
      fputs(" -p ", fp);
      fputs(port, fp);
      fputs(" -i ", fp);
      fputs(priv_key_path, fp);
      fputs("\" '", fp);
      fputs(src_path, fp);
      fputs("' ", fp);
      fputs(user, fp);
      fputs("@", fp);
      fputs(dst_server, fp);
      fputs(":'", fp);
      fputs(dst_path, fp);
      fputs("'",fp);
      fputs("\nfi\n\n", fp);

      /* For the script file */
      source = g_strdup_printf("%s", src_path);
      destination = g_strdup_printf("%s%s", dst_server, dst_path);
    }
/* --- Local to Remote backup and --- */



    /* Append a log function in the backup script after each
       rsync line that appends to the current backups logfile */
    script = g_strconcat("\nif [ $? -eq 0 ] && [ $MISSING_PATH -eq 0 ]; then\n",
    "   STOP_TIME=`date +%Y-%m-%d_%H:%M:%S`;\n",
    "   echo \"$START_TIME $STOP_TIME Backup successful: Source: [", source, "] Destination: [", destination, "]\" >> ", log_file,
    "\nelse\n"
    "   STOP_TIME=`date +%Y-%m-%d_%H:%M:%S`;\n",
    "   echo \"$START_TIME $STOP_TIME Backup failure:    Source: [", source, "] Destination: [", destination, "]\" >> ", log_file,
    "\nfi\n\n",
    NULL);

    fputs(script, fp);
    /* Close the script file */
    fclose(fp);

    if( script_file!=NULL )
      g_free(script_file);

    if( script!=NULL )
      g_free(script);

    if( log_file!=NULL )
      g_free(log_file);

    if( source!=NULL )
      g_free(source);

    if( destination!=NULL )
      g_free(destination);

    free_values(src_server, src_path, dst_server, 
             dst_path, user, port, priv_key_path, 
                     include_files, exclude_files);

    /* Return false to keep the foreach func going */
    return FALSE;
}


void save_backup_settings(struct w *widgets)
{
    /* Saves the backup settings, backup script and
       schedules the backup via cron/crontab if specified. */
    FILE *fp;
    int i = 0;
    gchar *cmd, *info, *settings_file, *script_path, *script, *cron_line;
    char *script_days = NULL;
    G_CONST_RETURN gchar *script_hour = NULL, *script_minute = NULL;
    
    /* Only show one error popup per error type */
    error_src_dst_info       = 1;
    error_server_server_info = 1;

    /* Get the backup name and use it as the filename */
    global_backup_name = gtk_combo_box_get_active_text(GTK_COMBO_BOX(widgets->rsync_set_combo[0]));

    if( global_backup_name == NULL || strlen(global_backup_name) < 3 )
    {
      info = g_strdup_printf(_("Error: The backup name is too short or missing.\n"));
        show_info(info);
        g_free(info);
      return;
    }


    
    /* Remove cron lines matching this backup from crontab */
    script_path = mk_script_path(global_backup_name);
    if( script_path == NULL || strlen(script_path) < 3 )
    {
      info = g_strdup_printf(_("Error: script path too short.\n"));
        show_info(info);
        g_free(info);

        g_free(script_path);
        return;
    }
    /* Remove the cron lines */
    del_cron(script_path);


    /* Make sure we have a script file before we begin appending to it */
    if((fp=fopen(script_path, "w+"))==NULL)
    {
      info = g_strdup_printf(_("Error: Can not write backup script here:\n%s\n"), script_path);
        show_info(info);
        g_free(info);

        g_free(script_path);
        return;
    }
    script = g_strconcat("#!/bin/sh\n\n", NULL);
    fputs(script, fp);
    if( script!=NULL )
      g_free(script);

    fclose(fp);


    /* Chmod the script file to 755 so cron can run it. */
    cmd = g_strdup_printf("chmod 755 \"%s\"", script_path);
    if( ! run_command(cmd) )
    {
      info = g_strdup_printf(_("Error: Can not make the backup script executable.\n"));
      show_info(info);
      g_free(info);
      /* Dont return */
    }
    if( cmd!=NULL )
      g_free(cmd);
    if( script_path!=NULL )
      g_free(script_path);


    /* Create an an empty settings file before we begin appending to it */
    settings_file = g_strdup_printf("%s/%s", global_settings_dir, global_backup_name);
    if((fp=fopen(settings_file, "w+"))==NULL)
    {
      info = g_strdup_printf(_("Error: Can not write backup settings here:\n%s\n"), settings_file);
        show_info(info);
        g_free(info);

        g_free(settings_file);
        return;
    }
    fclose(fp);



    /* Iterate the treeview and write the settings and script files */
    gtk_tree_model_foreach(GTK_TREE_MODEL(widgets->backup_store), (GtkTreeModelForeachFunc) save_foreach, widgets);



    /* Return if schedule time or days via cron isnt enabled */
    if( ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->schedule_check_button[0]))
    &&  ! gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->schedule_check_button[8])) )
    {
      /* The cron line has already been removed */
      g_free(settings_file);
      return;
    }

    /* Append schedule_days and schedule_time values last in the settings file */
    if((fp=fopen(settings_file, "a"))==NULL)
    {
      info = g_strdup_printf(_("Error: Can not write backup schedule here:\n%s\n"), settings_file);
        show_info(info);
        g_free(info);

        g_free(settings_file);
        return;
    }

    script_days = allocate(1024);

    /* Schedule days */
    if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->schedule_check_button[0])) )
    {
      fputs("schedule_days ", fp);
      for(i=1; i<8; i++)
      {
          if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->schedule_check_button[i])) )
          {    
              fputs("1", fp);
              if( i == 1 )
                strcat(script_days, "1,");
              if( i == 2 )
                strcat(script_days, "2,");
              if( i == 3 )
                strcat(script_days, "3,");
              if( i == 4 )
                strcat(script_days, "4,");
              if( i == 5 )
                strcat(script_days, "5,");
              if( i == 6 )
                strcat(script_days, "6,");
              if( i == 7 )
                strcat(script_days, "7");
          }
          else
            fputs("0", fp);
      }
      fputs("\n", fp);
    }

    /* If there are no script days, add a single '*' for any day */
    if( script_days == NULL || strlen(script_days) < 1 )
      snprintf(script_days, 2, "%s", "*");

    /* Remove single commas ',' at the end of script days */
    if( script_days[strlen(script_days)-1]==',' )
      script_days[strlen(script_days)-1]='\0';

    /* Append schedule hour and minute in the settings file */
    if( gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widgets->schedule_check_button[8])) )
    {
      script_hour   = gtk_entry_get_text(GTK_ENTRY(widgets->schedule_spin_button[0]));
      script_minute = gtk_entry_get_text(GTK_ENTRY(widgets->schedule_spin_button[1]));

      fputs("schedule_time ", fp);
      fputs(script_hour, fp);
      fputs(":", fp);
      fputs(script_minute, fp);
      fputs("\n", fp);
    }
    /* Close the settings file */
    fclose(fp);
    g_free(settings_file);

    /* If script_hour is zero or nothing, write it as any. '*' */
    if( script_hour == NULL || script_hour[0]=='0' )
      script_hour = g_strdup_printf("%s", "*");

    /* If script_minute is zero or nothing, write it as any. '*' */
    if( script_minute == NULL || script_minute[0]=='0' )
      script_minute = g_strdup_printf("%s", "*");

    /* Schedule this backup in crontab */
    cron_line = g_strdup_printf("%s %s * * %s root", script_minute, script_hour, script_days);
    free(script_days);

    /* Removes the old cron line, adds a new one and HUP's crond */
    schedule_cron(cron_line, global_backup_name);

    g_free(cron_line);
}

Generated by  Doxygen 1.6.0   Back to index