linux下c實現的數據庫備份

er74 9年前發布 | 19K 次閱讀 Linux

 

該版本算是比較成熟的啦,歡迎大伙拿來試用!!!

1.新增數據庫連接和備份時間配置文件conf

2.新增日志文件,程序運行的一些異常會記錄在log文件下

</div>

后續的工作:

1.將代碼切割為多個文件,分類存放代碼

2.加入自動后臺運行的支持

3.加入開機自動運行的支持

完成上面3個之后,我的linux c數據庫備份程序就暫時靠一段落了。

</div>

使用提醒:

編譯:gcc -o main main.c

后臺啟動:./main &

停止程序:./main stop

</div>

#include<sys/types.h>
#include<sys/wait.h>
#include<ctype.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<signal.h>
#include<time.h>
#include<stdio.h>
//程序運行的pid信息
#define PID_FILE "./pid.db"
//記錄待備份的數據庫信息文件
#define DB_FILE "./db_list"
//配置文件信息
#define CONF_FILE "./conf"
//日志文件
#define LOG_FILE "./log"
//最大備份的數據庫數量
#define NUM 20
//數據庫名字長度的限制
#define LEN 128
//程序輪詢時間間隔
#define ALARM_TIME 10
//從文件讀取到的數據庫信息保存至該數組中
char *db_list[NUM];
//當前待備份的數據庫數量
int read_num;
//是否用戶終止備份
int isbreak = 0;
//數據庫連接信息
typedef struct db_conf {
  char *host;
  char *user;
  char *pass;
}CONF;
//數據庫備份時間
typedef struct bat_t {
  int hour;
  int min;
}BAT_T;
//malloc
void malloc_dblist();
//free
void free_dblist();
//讀取待備份的數據庫信息
int readDbFile();
//讀取配置文件信息(數據庫連接信息,備份時間等)
CONF readConfFile();
//讀取備份的時間信息
BAT_T readBatTFile();
//記錄日志信息
void recordLog(char *);
//信號處理函數
void signHandler(int sig);
//記錄程序運行的pid信息
int recordPid(int pid);
//獲取程序運行時的pid信息
int readPid(void);
//移除程序運行時的pid信息
void delPid(void);
int main(int argc, char *argv[]) 
{
  CONF conf;
  BAT_T bt;
  pid_t pid, old_pid;
  int i, prs;
  char buf[LEN];
  time_t t;
  struct tm *tm_ptr;
  struct sigaction act, oldact;
  sigset_t newmask, suspmask, oldmask;
  if (argc >= 2) {
    old_pid = (pid_t)readPid();
    //停止掉備份程序
    if (strcmp(argv[1], "stop") == 0) {
      kill(old_pid, SIGINT);
      return 0;
    }
    else if (strcmp(argv[1], "restart") == 0) {
      kill(old_pid, SIGINT);
      sleep(5);
    }
  }
  old_pid = (pid_t)readPid();
  //檢測程序是否已經在運行
  if (old_pid > 0) {
    fprintf(stderr, "Progress is running.\n");
    return -1;
  }
  //記錄程序運行的pid信息
  prs = recordPid((int)getpid());
  if (prs == -1) {
    fprintf(stderr, "Open pid.db file error.\n");
    return -1;
  }
  //讀取待備份的數據庫
  int rs = readDbFile();
  if (rs) {
    delPid();
    return rs;
  }
  //讀取數據配置信息
  conf = readConfFile();
  //讀取備份時間
  bt = readBatTFile();
  //信號接管
  act.sa_handler = signHandler;
  sigemptyset(&act.sa_mask);
  act.sa_flags = 0;
  sigaction(SIGALRM, &act, 0);
  sigaction(SIGINT, &act, 0);
  while (1) {
    time(&t);
    tm_ptr = localtime(&t);
    //備份時間內進行備份
    if (bt.hour == (int)tm_ptr->tm_hour && bt.min == (int)tm_ptr->tm_min) {
      for (i = 0; i < read_num; i++) {
        memset(buf, '\0', LEN);
        //密碼為空
        if (!strlen(conf.pass)) {
          sprintf(buf, "mysqldump -h%s -u%s %s > %s_%02d%02d%02d.sql", 
            conf.host, conf.user, db_list[i], db_list[i], 
            tm_ptr->tm_year+1900, tm_ptr->tm_mon+1, tm_ptr->tm_mday);
        }
        else {
          sprintf(buf, "mysqldump -h%s -u%s -p%s %s > %s_%02d%02d%02d.sql", 
            conf.host, conf.user, conf.pass, db_list[i], db_list[i], 
            tm_ptr->tm_year+1900, tm_ptr->tm_mon+1, tm_ptr->tm_mday);
        }
        system(buf);
      }
    }
    alarm(ALARM_TIME);
    pause();
    if (isbreak) {
      recordLog("User break progress.");
      break;
    }
  }
  free_dblist();
  delPid();
  exit(0);
}
void malloc_dblist()
{
  int i = 0;
  //malloc for db_list
  for (i = 0; i < NUM; i++) {
    db_list[i] = malloc(LEN);
    memset(db_list[i], '\0', LEN);
  }
}
void free_dblist()
{
  int i;
  //free db_list's memory
  for (i = 0; i < NUM; i++) {
    free(db_list[i]);
  }
}
int readDbFile()
{
  FILE *fp;
  fp = fopen(DB_FILE, "r");
  if (!fp) {
    char buf[128];
    sprintf(buf, "%s not found\n", DB_FILE);
    recordLog(buf);
    fprintf(stderr, "%s not found\n", DB_FILE);
    return 1;
  }
  else {
    malloc_dblist();
    read_num = 0;
    while (fscanf(fp, "%127[^\r\n]\n", db_list[read_num]) == 1) {
      read_num++;
    }
    fclose(fp); 
    return 0;
  }
}
CONF readConfFile()
{
  FILE *fp;
  CONF conf;
  if (!(fp = fopen(CONF_FILE, "r"))) {
    conf.host = "localhost";
    conf.user = "root";
    conf.pass = "";
    return conf;
  }
  char buf[128];
  while ((fscanf(fp, "%127[^\r\n]\n", buf)) == 1) {
    char *tmp1 = strtok(buf, "=");
    char *tmp2 = strtok(NULL, "=");
    if (strstr(tmp1, "HOST")) {
      if (tmp2) {
        conf.host = strdup(tmp2);
      }
      else {
        conf.host = "localhost";
      }
    }
    else if (strstr(tmp1, "USER")) {
      if (tmp2) {
        conf.user = strdup(tmp2);
      }
      else {
        conf.host = "root";
      }
    }
    else if (strstr(tmp1, "PASS")) {
      if (tmp2) {
        conf.pass = strdup(tmp2);
      }
      else {
        conf.pass = "";
      }
    }
  }
  return conf;
}
BAT_T readBatTFile()
{
  FILE *fp;
  BAT_T bat_time;
  if (!(fp = fopen(CONF_FILE, "r"))) {
    bat_time.hour = 02;
    bat_time.min = 00;
    return bat_time;
  }
  char buf[128];
  while ((fscanf(fp, "%127[^\r\n]\n", buf)) == 1) {
    if (!strstr(buf, "BAT_TIME"))
      continue;
    //獲取到備份數據數據
    char *tmp1 = strtok(buf, "=");
    char *tmp2 = strtok(NULL, "=");
    //對備份時間數據進行分割
    char *hour = strtok(tmp2, " ");
    char *min = strtok(NULL, " ");
    if (hour) {
      bat_time.hour = atoi(hour);
    }
    else {
      bat_time.hour = 02;
    }
    if (min) {
      bat_time.min = atoi(min);
    }
    else {
      bat_time.min = 02;
    }
  }
  return bat_time;
}
void recordLog(char *msg)
{
  FILE *fp;
  fp = fopen(LOG_FILE, "a");
  if (fp) {
    time_t t;
    struct tm *tm_ptr;
    time(&t);
    tm_ptr = localtime(&t);
    fprintf(fp, "%d-%d-%d %d:%d:%d: %s\n", (tm_ptr->tm_year+1900), tm_ptr->tm_mon, tm_ptr->tm_mday,
      tm_ptr->tm_hour, tm_ptr->tm_min, tm_ptr->tm_sec, msg);
    fclose(fp);
  }
}
void signHandler(int sig)
{
  char buf[128];
  switch (sig) {
    case SIGALRM:
      //fprintf(stdout, "alarm signal comming:%d.\n", sig);
      break;
    case SIGINT:
      //fprintf(stdout, "sigint signal comming:%d.\n", sig);
      isbreak = 1;
      break;
    default:
      //fprintf(stdout, "uncatched signal comming:%d.\n", sig);
      sprintf(buf, "uncatched signal comming:%d.\n", sig);
      recordLog(buf);
  }
}
int recordPid(int pid)
{
  FILE *fp = NULL;
  if (!(fp = fopen(PID_FILE, "w")))
    return -1;
  pid = getpid();
  fprintf(fp, "%d", (int)pid);
  fclose(fp);
  return 0;
}
int readPid(void)
{
  FILE *fp = NULL;
  if (!(fp = fopen(PID_FILE, "r")))
    return -1;
  int pid;
  if (fscanf(fp, "%d", &pid) != 1) {
    fclose(fp);
    return -2;
  }
  fclose(fp);
  return pid;
}
void delPid(void)
{
  unlink(PID_FILE);
}

mian.c

conf

#數據庫服務器地址
HOST=localhost
#數據庫賬號
USER=root
#數據庫密碼
PASS=
#備份時間 :小時 分鐘
BAT_TIME=17 25

db_list

mkbl
ck_book
 本文由用戶 er74 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!