Annotation of embedaddon/rsync/db.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Routines to access extended file info via DB.
                      3:  *
                      4:  * Copyright (C) 2008-2013 Wayne Davison
                      5:  *
                      6:  * This program is free software; you can redistribute it and/or modify
                      7:  * it under the terms of the GNU General Public License as published by
                      8:  * the Free Software Foundation; either version 3 of the License, or
                      9:  * (at your option) any later version.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful,
                     12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14:  * GNU General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU General Public License along
                     17:  * with this program; if not, visit the http://fsf.org website.
                     18:  */
                     19: 
                     20: #include "rsync.h"
                     21: #include "ifuncs.h"
                     22: #include "itypes.h"
                     23: #include "inums.h"
                     24: #ifdef USE_OPENSSL
                     25: #include "openssl/md4.h"
                     26: #include "openssl/md5.h"
                     27: #endif
                     28: 
                     29: extern int recurse;
                     30: extern int same_db;
                     31: extern int am_receiver;
                     32: extern int am_generator;
                     33: extern int checksum_type;
                     34: extern int db_clean, db_check, db_do_md4, db_do_md5, db_update, db_lax, db_init, db_mounts;
                     35: extern int db_output_name, db_output_sum, db_output_info, db_output_unchanged, db_output_dirs, db_output_msgs;
                     36: extern int saw_db_output_opt, saw_db_sum_opt;
                     37: extern char *db_config;
                     38: 
                     39: #define MOUNT_HELPER_SCRIPT "/usr/sbin/rsyncdb-mountinfo"
                     40: 
                     41: #if defined HAVE_MYSQL_MYSQL_H && defined HAVE_LIBMYSQLCLIENT
                     42: #define USE_MYSQL
                     43: #include <mysql/mysql.h>
                     44: #include <mysql/errmsg.h>
                     45: #endif
                     46: 
                     47: #if defined HAVE_SQLITE3_H && defined HAVE_LIBSQLITE3
                     48: #define USE_SQLITE
                     49: #include <sqlite3.h>
                     50: #ifndef HAVE_SQLITE3_OPEN_V2
                     51: #define sqlite3_open_v2(dbname, dbhptr, flags, vfs) \
                     52:        sqlite3_open(dbname, dbhptr)
                     53: #endif
                     54: #ifndef HAVE_SQLITE3_PREPARE_V2
                     55: #define sqlite3_prepare_v2 sqlite3_prepare
                     56: #endif
                     57: #define MAX_LOCK_FAILURES 10
                     58: #define LOCK_FAIL_MSLEEP 100
                     59: #endif
                     60: 
                     61: #ifndef USE_OPENSSL
                     62: #define MD5_CTX md_context
                     63: #define MD5_Init md5_begin
                     64: #define MD5_Update md5_update
                     65: #define MD5_Final(digest, cptr) md5_result(cptr, digest)
                     66: #endif
                     67: 
                     68: #define DB_TYPE_NONE 0
                     69: #define DB_TYPE_MYSQL 1
                     70: #define DB_TYPE_SQLITE 2
                     71: 
                     72: int use_db = DB_TYPE_NONE;
                     73: int select_many_sums = 0;
                     74: 
                     75: #define PREP_NORM 0
                     76: #define PREP_MOUNT 1
                     77: 
                     78: static const char *dbhost = NULL, *dbuser = NULL, *dbpass = NULL, *dbname = NULL;
                     79: static unsigned int dbport = 0;
                     80: static int transaction_state = -1;
                     81: 
                     82: static union {
                     83: #ifdef USE_MYSQL
                     84:     MYSQL *mysql;
                     85: #endif
                     86: #ifdef USE_SQLITE
                     87:     sqlite3 *sqlite;
                     88: #endif
                     89:     void *all;
                     90: } dbh;
                     91: 
                     92: #define SEL_DEV 0
                     93: #define SEL_SUM 1
                     94: #define REP_SUM 2
                     95: #define UPD_CTIME 3
                     96: #define INS_MOUNT 4
                     97: #define UPD_MOUNT 5 /* SQLite only */
                     98: #define SEL_MOUNT 6
                     99: #define UN_MOUNT 7
                    100: #define DEL_SUMS 8
                    101: #define INS_PRESENT 9
                    102: #define MAX_PREP_CNT 10
                    103: 
                    104: #define MAX_BIND_CNT 7
                    105: #define MAX_RESULT_BINDS 32
                    106: 
                    107: static union {
                    108: #ifdef USE_MYSQL
                    109:     MYSQL_STMT *mysql;
                    110: #endif
                    111: #ifdef USE_SQLITE
                    112:     sqlite3_stmt *sqlite;
                    113: #endif
                    114:     void *all;
                    115: } statements[MAX_PREP_CNT];
                    116: 
                    117: static int md_num;
                    118: static enum logcode log_code;
                    119: 
                    120: #ifdef USE_MYSQL
                    121: static unsigned int bind_disk_id, bind_mdnum;
                    122: static int64 bind_devno, bind_ino, bind_size, bind_mtime, bind_ctime;
                    123: static char bind_sum[MAX_DIGEST_LEN];
                    124: static unsigned long result_length[MAX_RESULT_BINDS];
                    125: static bool result_is_null[MAX_RESULT_BINDS], result_error[MAX_RESULT_BINDS];
                    126: #elif defined USE_SQLITE
                    127: static int64 bind_mtime;
                    128: #endif
                    129: static char bind_thishost[128+1];
                    130: static unsigned long bind_thishost_len;
                    131: static char *mount_helper_script = NULL;
                    132: 
                    133: static char *error_log;
                    134: #if defined USE_SQLITE && defined SQLITE_CONFIG_LOG
                    135: static char bind_mount_uniq[128+1];
                    136: static unsigned long bind_mount_uniq_len;
                    137: static FILE *error_log_fp;
                    138: #endif
                    139: 
                    140: #define PTR_SIZE (sizeof (struct file_struct *))
                    141: 
                    142: #if defined USE_MYSQL || defined USE_SQLITE
                    143: static void update_mounts(void);
                    144: #endif
                    145: 
                    146: struct name_list {
                    147:        struct name_list *next;
                    148:        char name[1];
                    149: } *dirs_list;
                    150: 
                    151: int db_read_config(enum logcode code, const char *config_file)
                    152: {
                    153:        char buf[2048], *cp;
                    154:        FILE *fp;
                    155:        int lineno = 0;
                    156: 
                    157:        log_code = code;
                    158: 
                    159:        bind_thishost_len = strlcpy(bind_thishost, "localhost", sizeof bind_thishost);
                    160: 
                    161:        if (!(fp = fopen(config_file, "r"))) {
                    162:                rsyserr(log_code, errno, "unable to open %s", config_file);
                    163:                return 0;
                    164:        }
                    165:        if (DEBUG_GTE(DB, 1))
                    166:                rprintf(FCLIENT, "[%s] Reading DB config from %s\n", who_am_i(), config_file);
                    167:        while (fgets(buf, sizeof buf, fp)) {
                    168:                lineno++;
                    169:                if ((cp = strchr(buf, '#')) == NULL
                    170:                 && (cp = strchr(buf, '\r')) == NULL
                    171:                 && (cp = strchr(buf, '\n')) == NULL)
                    172:                        cp = buf + strlen(buf);
                    173:                while (cp != buf && isSpace(cp-1)) cp--;
                    174:                *cp = '\0';
                    175: 
                    176:                if (!*buf)
                    177:                        continue;
                    178: 
                    179:                if (!(cp = strchr(buf, ':')))
                    180:                        goto invalid_line;
                    181:                *cp++ = '\0';
                    182: 
                    183:                while (isSpace(cp)) cp++;
                    184:                if (strcasecmp(buf, "dbhost") == 0)
                    185:                        dbhost = strdup(cp);
                    186:                else if (strcasecmp(buf, "dbuser") == 0)
                    187:                        dbuser = strdup(cp);
                    188:                else if (strcasecmp(buf, "dbpass") == 0)
                    189:                        dbpass = strdup(cp);
                    190:                else if (strcasecmp(buf, "dbname") == 0)
                    191:                        dbname = strdup(cp);
                    192:                else if (strcasecmp(buf, "dbport") == 0)
                    193:                        dbport = atoi(cp);
                    194:                else if (strcasecmp(buf, "transaction") == 0)
                    195:                        transaction_state = atoi(cp) ? 0 : -1;
                    196:                else if (strcasecmp(buf, "mountHelper") == 0)
                    197:                        mount_helper_script = strdup(cp);
                    198:                else if (strcasecmp(buf, "errlog") == 0)
                    199:                        error_log = strdup(cp);
                    200:                else if (strcasecmp(buf, "thishost") == 0)
                    201:                        bind_thishost_len = strlcpy(bind_thishost, cp, sizeof bind_thishost);
                    202:                else if (strcasecmp(buf, "dbtype") == 0) {
                    203: #ifdef USE_MYSQL
                    204:                        if (strcasecmp(cp, "mysql") == 0) {
                    205:                                use_db = DB_TYPE_MYSQL;
                    206:                                continue;
                    207:                        }
                    208: #endif
                    209: #ifdef USE_SQLITE
                    210:                        if (strcasecmp(cp, "sqlite") == 0) {
                    211:                                use_db = DB_TYPE_SQLITE;
                    212:                                continue;
                    213:                        }
                    214: #endif
                    215:                        rprintf(log_code,
                    216:                            "Unsupported dbtype on line #%d in %s.\n",
                    217:                            lineno, config_file);
                    218:                        use_db = DB_TYPE_NONE;
                    219:                        return 0;
                    220:                } else {
                    221:                  invalid_line:
                    222:                        rprintf(log_code, "Invalid line #%d in %s\n",
                    223:                                lineno, config_file);
                    224:                        use_db = DB_TYPE_NONE;
                    225:                        return 0;
                    226:                }
                    227:        }
                    228:        fclose(fp);
                    229: 
                    230:        if (bind_thishost_len >= (int)sizeof bind_thishost)
                    231:                bind_thishost_len = sizeof bind_thishost - 1;
                    232: 
                    233:        if (!use_db || !dbname) {
                    234:                rprintf(log_code, "Please specify at least dbtype and dbname in %s.\n", config_file);
                    235:                use_db = DB_TYPE_NONE;
                    236:                return 0;
                    237:        }
                    238: 
                    239:        md_num = checksum_type == 5 ? 5 : 4;
                    240: 
                    241:        if (error_log) {
                    242:                if (use_db != DB_TYPE_SQLITE)
                    243:                        rprintf(log_code, "Ignoring errlog setting for non-SQLite DB.\n");
                    244: #ifndef SQLITE_CONFIG_LOG
                    245:                else
                    246:                        rprintf(log_code, "Your sqlite doesn't support SQLITE_CONFIG_LOG.\n");
                    247: #endif
                    248:        }
                    249: 
                    250:        if (!mount_helper_script)
                    251:                mount_helper_script = MOUNT_HELPER_SCRIPT;
                    252: 
                    253:        return 1;
                    254: }
                    255: 
                    256: #if defined USE_SQLITE && defined SQLITE_CONFIG_LOG
                    257: static void errorLogCallback(UNUSED(void *pArg), int iErrCode, const char *zMsg)
                    258: {
                    259:        fprintf(error_log_fp, "[%d] %s (%d)\n", (int)getpid(), zMsg, iErrCode);
                    260: }
                    261: #endif
                    262: 
                    263: static int run_sql(const char *fmt, ...)
                    264: {
                    265:        va_list ap;
                    266:        char *query;
                    267:        int ok = 0, qlen;
                    268: 
                    269:        va_start(ap, fmt);
                    270:        qlen = vasprintf(&query, fmt, ap);
                    271:        va_end(ap);
                    272:        if (qlen < 0)
                    273:                out_of_memory("run_sql");
                    274:        if (DEBUG_GTE(DB, 3))
                    275:                rprintf(FCLIENT, "[%s] SQL being run: %s\n", who_am_i(), query);
                    276: 
                    277:        switch (use_db) {
                    278: #ifdef USE_MYSQL
                    279:        case DB_TYPE_MYSQL:
                    280:                if (mysql_query(dbh.mysql, query) < 0) {
                    281:                        rprintf(FERROR, "Failed to run sql: %s\n", mysql_error(dbh.mysql));
                    282:                        rprintf(FERROR, "%s\n", query);
                    283:                } else
                    284:                        ok = 1;
                    285:                break;
                    286: #endif
                    287: #ifdef USE_SQLITE
                    288:        case DB_TYPE_SQLITE: {
                    289:                int rc, lock_failures = 0;
                    290:                while (1) {
                    291:                        if ((rc = sqlite3_exec(dbh.sqlite, query, NULL, NULL, NULL)) == 0)
                    292:                                break;
                    293:                        if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED)
                    294:                                break;
                    295:                        if (++lock_failures > MAX_LOCK_FAILURES)
                    296:                                break;
                    297:                        msleep(LOCK_FAIL_MSLEEP);
                    298:                }
                    299:                if (rc) {
                    300:                        rprintf(FERROR, "[%s] Failed to run sql: %s\n", who_am_i(), sqlite3_errmsg(dbh.sqlite));
                    301:                        rprintf(FERROR, "%s\n", query);
                    302:                } else
                    303:                        ok = 1;
                    304:                break;
                    305:            }
                    306: #endif
                    307:        }
                    308: 
                    309:        free(query);
                    310: 
                    311:        return ok;
                    312: }
                    313: 
                    314: #ifdef USE_MYSQL
                    315: static int prepare_mysql(int ndx, MYSQL_BIND *binds, int bind_cnt, const char *fmt, ...)
                    316: {
                    317:        va_list ap;
                    318:        char *query;
                    319:        int qlen, param_cnt;
                    320:        MYSQL_STMT *stmt = mysql_stmt_init(dbh.mysql);
                    321: 
                    322:        if (stmt == NULL)
                    323:                out_of_memory("prepare_mysql");
                    324: 
                    325:        va_start(ap, fmt);
                    326:        qlen = vasprintf(&query, fmt, ap);
                    327:        va_end(ap);
                    328:        if (qlen < 0)
                    329:                out_of_memory("prepare_mysql");
                    330:        if (DEBUG_GTE(DB, 3))
                    331:                rprintf(FCLIENT, "[%s] SQL being prepared: %s\n", who_am_i(), query);
                    332: 
                    333:        if (mysql_stmt_prepare(stmt, query, qlen) != 0) {
                    334:                rprintf(log_code, "[%s] Prepare failed: %s\n", who_am_i(), mysql_stmt_error(stmt));
                    335:                rprintf(log_code, "%s\n", query);
                    336:                free(query);
                    337:                return 0;
                    338:        }
                    339: 
                    340:        if ((param_cnt = mysql_stmt_param_count(stmt)) != bind_cnt) {
                    341:                rprintf(log_code, "[%s] Parameters in statement = %d, bind vars = %d\n",
                    342:                        who_am_i(), param_cnt, bind_cnt);
                    343:                rprintf(log_code, "%s\n", query);
                    344:                free(query);
                    345:                return 0;
                    346:        }
                    347:        if (bind_cnt)
                    348:                mysql_stmt_bind_param(stmt, binds);
                    349: 
                    350:        statements[ndx].mysql = stmt;
                    351:        free(query);
                    352: 
                    353:        return 1;
                    354: }
                    355: #endif
                    356: 
                    357: #ifdef USE_MYSQL
                    358: static int prepare_mysql_queries(int type)
                    359: {
                    360:        MYSQL_BIND binds[MAX_BIND_CNT];
                    361:        char *sql;
                    362: 
                    363:        switch (type) {
                    364:        case PREP_NORM:
                    365:                sql="SELECT disk_id"
                    366:                    " FROM disk"
                    367:                    " WHERE host = ? AND devno = ?";
                    368:                memset(binds, 0, sizeof binds);
                    369:                binds[0].buffer_type = MYSQL_TYPE_STRING;
                    370:                binds[0].buffer = &bind_thishost;
                    371:                binds[0].buffer_length = bind_thishost_len;
                    372:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                    373:                binds[1].buffer = &bind_devno;
                    374:                if (!prepare_mysql(SEL_DEV, binds, 2, sql))
                    375:                        return 0;
                    376: 
                    377:                memset(binds, 0, sizeof binds);
                    378:                binds[0].buffer_type = MYSQL_TYPE_LONG;
                    379:                binds[0].buffer = &bind_disk_id;
                    380:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                    381:                binds[1].buffer = &bind_ino;
                    382:                if (select_many_sums) {
                    383:                        sql="SELECT checksum, sum_type, size, mtime, ctime"
                    384:                            " FROM inode_map"
                    385:                            " WHERE disk_id = ? AND ino = ?";
                    386:                        if (!prepare_mysql(SEL_SUM, binds, 2, sql))
                    387:                                return 0;
                    388:                } else {
                    389:                        sql="SELECT checksum"
                    390:                            " FROM inode_map"
                    391:                            " WHERE disk_id = ? AND ino = ? AND sum_type = %d"
                    392:                            "   AND size = ? AND mtime = ? %s"; /* optional: AND ctime = ? */
                    393:                        binds[2].buffer_type = MYSQL_TYPE_LONGLONG;
                    394:                        binds[2].buffer = &bind_size;
                    395:                        binds[3].buffer_type = MYSQL_TYPE_LONGLONG;
                    396:                        binds[3].buffer = &bind_mtime;
                    397:                        if (!db_lax) {
                    398:                                binds[4].buffer_type = MYSQL_TYPE_LONGLONG;
                    399:                                binds[4].buffer = &bind_ctime;
                    400:                        }
                    401:                        if (!prepare_mysql(SEL_SUM, binds, 4 + !db_lax, sql, md_num, db_lax ? "" : "AND ctime = ?"))
                    402:                                return 0;
                    403:                }
                    404: 
                    405:                sql="INSERT INTO inode_map"
                    406:                    " SET disk_id = ?, ino = ?, sum_type = ?,"
                    407:                    "     size = ?, mtime = ?, ctime = ?, checksum = ?"
                    408:                    " ON DUPLICATE KEY"
                    409:                    " UPDATE size = VALUES(size), mtime = VALUES(mtime),"
                    410:                    "        ctime = VALUES(ctime), checksum = VALUES(checksum)";
                    411:                memset(binds, 0, sizeof binds);
                    412:                binds[0].buffer_type = MYSQL_TYPE_LONG;
                    413:                binds[0].buffer = &bind_disk_id;
                    414:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                    415:                binds[1].buffer = &bind_ino;
                    416:                binds[2].buffer_type = MYSQL_TYPE_LONG;
                    417:                binds[2].buffer = &bind_mdnum;
                    418:                binds[3].buffer_type = MYSQL_TYPE_LONGLONG;
                    419:                binds[3].buffer = &bind_size;
                    420:                binds[4].buffer_type = MYSQL_TYPE_LONGLONG;
                    421:                binds[4].buffer = &bind_mtime;
                    422:                binds[5].buffer_type = MYSQL_TYPE_LONGLONG;
                    423:                binds[5].buffer = &bind_ctime;
                    424:                binds[6].buffer_type = MYSQL_TYPE_BLOB;
                    425:                binds[6].buffer = &bind_sum;
                    426:                binds[6].buffer_length = MD5_DIGEST_LEN; /* Same as MD4_DIGEST_LEN */
                    427:                if (!prepare_mysql(REP_SUM, binds, 7, sql))
                    428:                        return 0;
                    429: 
                    430:                sql="UPDATE inode_map"
                    431:                    " SET ctime = ?"
                    432:                    " WHERE disk_id = ? AND ino = ? AND sum_type = ? AND size = ? AND mtime = ?";
                    433:                memset(binds, 0, sizeof binds);
                    434:                binds[0].buffer_type = MYSQL_TYPE_LONGLONG;
                    435:                binds[0].buffer = &bind_ctime;
                    436:                binds[1].buffer_type = MYSQL_TYPE_LONG;
                    437:                binds[1].buffer = &bind_disk_id;
                    438:                binds[2].buffer_type = MYSQL_TYPE_LONGLONG;
                    439:                binds[2].buffer = &bind_ino;
                    440:                binds[3].buffer_type = MYSQL_TYPE_LONG;
                    441:                binds[3].buffer = &bind_mdnum;
                    442:                binds[4].buffer_type = MYSQL_TYPE_LONGLONG;
                    443:                binds[4].buffer = &bind_size;
                    444:                binds[5].buffer_type = MYSQL_TYPE_LONGLONG;
                    445:                binds[5].buffer = &bind_mtime;
                    446:                if (!prepare_mysql(UPD_CTIME, binds, 6, sql))
                    447:                        return 0;
                    448:                break;
                    449: 
                    450:        case PREP_MOUNT:
                    451:                sql="INSERT INTO disk"
                    452:                    " SET host = ?, last_seen = ?, mount_uniq = ?, devno = ?"
                    453:                    " ON DUPLICATE KEY"
                    454:                    " UPDATE last_seen = VALUES(last_seen), devno = VALUES(devno)";
                    455:                memset(binds, 0, sizeof binds);
                    456:                binds[0].buffer_type = MYSQL_TYPE_STRING;
                    457:                binds[0].buffer = &bind_thishost;
                    458:                binds[0].buffer_length = bind_thishost_len;
                    459:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                    460:                binds[1].buffer = &bind_mtime; /* we abuse mtime to hold the last_seen value */
                    461:                binds[2].buffer_type = MYSQL_TYPE_STRING;
                    462:                binds[2].buffer = &bind_mount_uniq;
                    463:                binds[2].buffer_length = sizeof bind_mount_uniq;
                    464:                binds[2].length = &bind_mount_uniq_len;
                    465:                binds[3].buffer_type = MYSQL_TYPE_LONGLONG;
                    466:                binds[3].buffer = &bind_devno;
                    467:                if (!prepare_mysql(INS_MOUNT, binds, 4, sql))
                    468:                        return 0;
                    469: 
                    470:                sql="SELECT mount_uniq"
                    471:                    " FROM disk"
                    472:                    " WHERE host = ? AND last_seen < ? AND devno != 0";
                    473:                /* Reusing first 2 binds from INS_MOUNT */
                    474:                if (!prepare_mysql(SEL_MOUNT, binds, 2, sql))
                    475:                        return 0;
                    476: 
                    477:                sql="UPDATE disk"
                    478:                    " SET devno = 0"
                    479:                    " WHERE host = ? AND last_seen < ? AND devno != 0";
                    480:                /* Reusing binds from SEL_MOUNT */
                    481:                if (!prepare_mysql(UN_MOUNT, binds, 2, sql))
                    482:                        return 0;
                    483:                break;
                    484:        }
                    485: 
                    486:        return 1;
                    487: }
                    488: #endif
                    489: 
                    490: #ifdef USE_MYSQL
                    491: static int db_connect_mysql(void)
                    492: {
                    493:        const char *open_dbname = db_init ? "mysql" : dbname;
                    494: 
                    495:        if (!(dbh.mysql = mysql_init(NULL)))
                    496:                out_of_memory("db_read_config");
                    497: 
                    498:        if (DEBUG_GTE(DB, 1)) {
                    499:                rprintf(FCLIENT, "[%s] connecting: host=%s user=%s db=%s port=%d\n",
                    500:                        who_am_i(), dbhost, dbuser, open_dbname, dbport);
                    501:        }
                    502:        if (!mysql_real_connect(dbh.mysql, dbhost, dbuser, dbpass, open_dbname, dbport, NULL, 0)) {
                    503:                rprintf(log_code, "[%s] Unable to connect to DB: %s\n", who_am_i(), mysql_error(dbh.mysql));
                    504:                return 0;
                    505:        }
                    506: 
                    507:        if (db_init) {
                    508:                if (db_output_msgs)
                    509:                        rprintf(FCLIENT, "Creating DB %s (if it does not exist)\n", dbname);
                    510:                if (!run_sql("CREATE DATABASE IF NOT EXISTS `%s`", dbname)
                    511:                 || !run_sql("USE `%s`", dbname))
                    512:                        exit_cleanup(RERR_IPC);
                    513: 
                    514:                if (db_output_msgs)
                    515:                        rprintf(FCLIENT, "Dropping old tables (if they exist))\n");
                    516:                if (!run_sql("DROP TABLE IF EXISTS disk")
                    517:                 || !run_sql("DROP TABLE IF EXISTS inode_map"))
                    518:                        exit_cleanup(RERR_IPC);
                    519: 
                    520:                if (db_output_msgs)
                    521:                        rprintf(FCLIENT, "Creating empty tables ...\n");
                    522:                if (!run_sql(
                    523:                    "CREATE TABLE disk (\n"
                    524:                    "  disk_id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,\n"
                    525:                    "  host varchar(128) NOT NULL default 'localhost',\n"
                    526:                    "  mount_uniq varchar(128) default NULL,\n"
                    527:                    "  devno bigint unsigned NOT NULL,\n" /* This is 0 when not mounted */
                    528:                    "  last_seen bigint NOT NULL,\n"
                    529:                    "  UNIQUE KEY mount_lookup (host, mount_uniq),\n"
                    530:                    "  KEY dev_lookup (devno, host)\n"
                    531:                    ")"))
                    532:                        exit_cleanup(RERR_IPC);
                    533: 
                    534:                if (!run_sql(
                    535:                    "CREATE TABLE inode_map (\n"
                    536:                    "  disk_id integer unsigned NOT NULL,\n"
                    537:                    "  ino bigint unsigned NOT NULL,\n"
                    538:                    "  sum_type tinyint NOT NULL default '0',\n"
                    539:                    "  size bigint unsigned NOT NULL,\n"
                    540:                    "  mtime bigint NOT NULL,\n"
                    541:                    "  ctime bigint NOT NULL,\n"
                    542:                    "  checksum binary(16) NOT NULL,\n"
                    543:                    "  PRIMARY KEY (disk_id,ino,sum_type)\n"
                    544:                    ")"))
                    545:                        exit_cleanup(RERR_IPC);
                    546: 
                    547:                if (!db_mounts)
                    548:                        exit_cleanup(0);
                    549:        }
                    550: 
                    551:        if (db_mounts) {
                    552:                if (!prepare_mysql_queries(PREP_MOUNT))
                    553:                        exit_cleanup(RERR_IPC);
                    554:                update_mounts();
                    555:                exit_cleanup(0);
                    556:        }
                    557: 
                    558:        if (!prepare_mysql_queries(PREP_NORM))
                    559:                return 0;
                    560: 
                    561:        return 1;
                    562: }
                    563: #endif
                    564: 
                    565: #ifdef USE_SQLITE
                    566: static int prepare_sqlite(int ndx, const char *fmt, ...)
                    567: {
                    568:        va_list ap;
                    569:        char *query;
                    570:        int rc, qlen, lock_failures = 0;
                    571: 
                    572:        va_start(ap, fmt);
                    573:        qlen = vasprintf(&query, fmt, ap);
                    574:        va_end(ap);
                    575:        if (qlen < 0)
                    576:                out_of_memory("prepare_sqlite");
                    577:        if (DEBUG_GTE(DB, 3))
                    578:                rprintf(FCLIENT, "[%s] SQL being prepared: %s\n", who_am_i(), query);
                    579: 
                    580:        while ((rc = sqlite3_prepare_v2(dbh.sqlite, query, -1, &statements[ndx].sqlite, NULL)) != 0) {
                    581:                if (DEBUG_GTE(DB, 4)) {
                    582:                        rprintf(FCLIENT, "[%s] sqlite3_prepare_v2(,%s,,) returned %d\n",
                    583:                                who_am_i(), query, rc);
                    584:                }
                    585:                if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED)
                    586:                        break;
                    587:                if (++lock_failures > MAX_LOCK_FAILURES)
                    588:                        break;
                    589:                msleep(LOCK_FAIL_MSLEEP);
                    590:        }
                    591:        if (rc) {
                    592:                rprintf(log_code, "[%s] Failed to prepare SQL: %s (%d)\n", who_am_i(), sqlite3_errmsg(dbh.sqlite), rc);
                    593:                rprintf(log_code, "%s\n", query);
                    594:                free(query);
                    595:                return 0;
                    596:        }
                    597:        free(query);
                    598: 
                    599:        return 1;
                    600: }
                    601: #endif
                    602: 
                    603: #ifdef USE_SQLITE
                    604: static int prepare_sqlite_queries(int type)
                    605: {
                    606:        char *sql;
                    607: 
                    608:        switch (type) {
                    609:        case PREP_NORM:
                    610:                sql="SELECT disk_id"
                    611:                    " FROM disk"
                    612:                    " WHERE host = ? AND devno = ?";
                    613:                if (!prepare_sqlite(SEL_DEV, sql))
                    614:                        return 0;
                    615: 
                    616:                if (select_many_sums) {
                    617:                        sql="SELECT checksum, sum_type, size, mtime, ctime"
                    618:                            " FROM inode_map"
                    619:                            " WHERE disk_id = ? AND ino = ?";
                    620:                        if (!prepare_sqlite(SEL_SUM, sql))
                    621:                                return 0;
                    622:                } else {
                    623:                        sql="SELECT checksum"
                    624:                            " FROM inode_map"
                    625:                            " WHERE disk_id = ? AND ino = ? AND sum_type = %d"
                    626:                            "   AND size = ? AND mtime = ? %s";
                    627:                        if (!prepare_sqlite(SEL_SUM, sql, md_num, db_lax ? "" : "AND ctime = ?"))
                    628:                                return 0;
                    629:                }
                    630: 
                    631:                sql="INSERT OR REPLACE INTO inode_map"
                    632:                    " (disk_id, ino, sum_type, size, mtime, ctime, checksum)"
                    633:                    " VALUES (?, ?, ?, ?, ?, ?, ?)";
                    634:                if (!prepare_sqlite(REP_SUM, sql))
                    635:                        return 0;
                    636: 
                    637:                sql="UPDATE inode_map"
                    638:                    " SET ctime = ?"
                    639:                    " WHERE disk_id = ? AND ino = ? AND sum_type = ? AND size = ? AND mtime = ?";
                    640:                if (!prepare_sqlite(UPD_CTIME, sql))
                    641:                        return 0;
                    642:                break;
                    643: 
                    644:        case PREP_MOUNT:
                    645:                sql="INSERT OR IGNORE INTO disk"
                    646:                    " (host, last_seen, mount_uniq, devno)"
                    647:                    " VALUES (?, ?, ?, ?)";
                    648:                if (!prepare_sqlite(INS_MOUNT, sql))
                    649:                        return 0;
                    650: 
                    651:                sql="UPDATE disk"
                    652:                    " SET last_seen = ?, devno = ?"
                    653:                    " WHERE host = ? AND mount_uniq = ?";
                    654:                if (!prepare_sqlite(UPD_MOUNT, sql))
                    655:                        return 0;
                    656: 
                    657:                sql="SELECT mount_uniq"
                    658:                    " FROM disk"
                    659:                    " WHERE host = ? AND last_seen < ? AND devno != 0";
                    660:                if (!prepare_sqlite(SEL_MOUNT, sql))
                    661:                        return 0;
                    662: 
                    663:                sql="UPDATE disk"
                    664:                    " SET devno = 0"
                    665:                    " WHERE host = ? AND last_seen < ? AND devno != 0";
                    666:                if (!prepare_sqlite(UN_MOUNT, sql))
                    667:                        return 0;
                    668:                break;
                    669:        }
                    670: 
                    671:        return 1;
                    672: }
                    673: #endif
                    674: 
                    675: #ifdef USE_SQLITE
                    676: static int db_connect_sqlite(void)
                    677: {
                    678:        int lock_failures = 0;
                    679:        int rc;
                    680: 
                    681: #ifdef SQLITE_CONFIG_LOG
                    682:        if (error_log) {
                    683:                if (DEBUG_GTE(DB, 1))
                    684:                        rprintf(FCLIENT, "[%s] Setting sqlite errlog to %s\n", who_am_i(), error_log);
                    685:                if (!(error_log_fp = fopen(error_log, "a"))) {
                    686:                        rsyserr(log_code, errno, "unable to append to logfile %s", error_log);
                    687:                        error_log = NULL;
                    688:                } else if (sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, NULL) != 0)
                    689:                        rprintf(log_code, "Failed to set errorLogCallback: %s\n", sqlite3_errmsg(dbh.sqlite));
                    690:        }
                    691: #endif
                    692: 
                    693:        while (1) {
                    694:                int open_flags = SQLITE_OPEN_READWRITE;
                    695:                if (db_init)
                    696:                        open_flags |= SQLITE_OPEN_CREATE;
                    697:                if (DEBUG_GTE(DB, 1))
                    698:                        rprintf(FCLIENT, "[%s] opening %s (%d)\n", who_am_i(), dbname, open_flags);
                    699:                if ((rc = sqlite3_open_v2(dbname, &dbh.sqlite, open_flags, NULL)) == 0) {
                    700:                        break;
                    701:                }
                    702:                if (DEBUG_GTE(DB, 4)) {
                    703:                        rprintf(FCLIENT, "[%s] sqlite3_open_v2(%s,,%d,NULL) returned %d\n",
                    704:                                who_am_i(), dbname, open_flags, rc);
                    705:                }
                    706:                if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED)
                    707:                        break;
                    708:                if (++lock_failures > MAX_LOCK_FAILURES)
                    709:                        break;
                    710:                msleep(LOCK_FAIL_MSLEEP);
                    711:        }
                    712: 
                    713:        if (rc) {
                    714:                rprintf(log_code, "Unable to connect to DB: %s (%d)\n", sqlite3_errmsg(dbh.sqlite), rc);
                    715:                return 0;
                    716:        }
                    717: 
                    718:        if (db_init) {
                    719:                char *sql;
                    720:                if (db_output_msgs)
                    721:                        rprintf(FCLIENT, "Dropping old tables (if they exist) ...\n");
                    722:                if (!run_sql("DROP TABLE IF EXISTS disk")
                    723:                 || !run_sql("DROP TABLE IF EXISTS inode_map"))
                    724:                        exit_cleanup(RERR_IPC);
                    725: 
                    726:                if (db_output_msgs)
                    727:                        rprintf(FCLIENT, "Creating empty tables ...\n");
                    728:                sql="CREATE TABLE disk (\n"
                    729:                    "  disk_id integer NOT NULL PRIMARY KEY AUTOINCREMENT,\n"
                    730:                    "  host varchar(128) NOT NULL default 'localhost',\n"
                    731:                    "  mount_uniq varchar(128) default NULL,\n"
                    732:                    "  devno bigint NOT NULL,\n" /* This is 0 when not mounted */
                    733:                    "  last_seen bigint NOT NULL,\n"
                    734:                    "  UNIQUE (host, mount_uniq)\n"
                    735:                    ")";
                    736:                if (!run_sql(sql))
                    737:                        exit_cleanup(RERR_IPC);
                    738: 
                    739:                sql="CREATE TABLE inode_map (\n"
                    740:                    "  disk_id integer NOT NULL,\n"
                    741:                    "  ino bigint NOT NULL,\n"
                    742:                    "  size bigint NOT NULL,\n"
                    743:                    "  mtime bigint NOT NULL,\n"
                    744:                    "  ctime bigint NOT NULL,\n"
                    745:                    "  sum_type tinyint NOT NULL default '0',\n"
                    746:                    "  checksum binary(16) NOT NULL,\n"
                    747:                    "  PRIMARY KEY (disk_id,ino,sum_type)\n"
                    748:                    ")";
                    749:                if (!run_sql(sql))
                    750:                        exit_cleanup(RERR_IPC);
                    751: 
                    752: #if SQLITE_VERSION_NUMBER >= 3007000
                    753:                /* Using WAL locking makes concurrency much better (requires sqlite 3.7.0). */
                    754:                sql="PRAGMA journal_mode = wal";
                    755:                run_sql(sql); /* We don't check this for success. */
                    756: #endif
                    757: 
                    758:                if (!db_mounts)
                    759:                        exit_cleanup(0);
                    760:        }
                    761: 
                    762:        if (db_mounts) {
                    763:                if (!prepare_sqlite_queries(PREP_MOUNT))
                    764:                        exit_cleanup(RERR_IPC);
                    765:                update_mounts();
                    766:                exit_cleanup(0);
                    767:        }
                    768: 
                    769:        if (!prepare_sqlite_queries(PREP_NORM)) {
                    770:                db_disconnect(False);
                    771:                return 0;
                    772:        }
                    773: 
                    774:        return 1;
                    775: }
                    776: #endif
                    777: 
                    778: int db_connect(int select_many)
                    779: {
                    780:        select_many_sums = select_many;
                    781: 
                    782:        switch (use_db) {
                    783: #ifdef USE_MYSQL
                    784:        case DB_TYPE_MYSQL:
                    785:                if (db_connect_mysql())
                    786:                        return 1;
                    787:                break;
                    788: #endif
                    789: #ifdef USE_SQLITE
                    790:        case DB_TYPE_SQLITE:
                    791:                if (db_connect_sqlite())
                    792:                        return 1;
                    793:                break;
                    794: #endif
                    795:        }
                    796: 
                    797:        db_disconnect(False);
                    798: 
                    799:        return 0;
                    800: }
                    801: 
                    802: void db_disconnect(BOOL commit)
                    803: {
                    804:        int ndx;
                    805: 
                    806:        if (!dbh.all)
                    807:                return;
                    808: 
                    809:        if (transaction_state > 0) {
                    810:                if (DEBUG_GTE(DB, 1)) {
                    811:                        rprintf(FCLIENT, "[%s] %s our DB transaction\n",
                    812:                                who_am_i(), commit ? "Committing" : "Rolling back");
                    813:                }
                    814:                transaction_state = 0;
                    815:                if (commit)
                    816:                        run_sql("COMMIT");
                    817:                else
                    818:                        run_sql("ROLLBACK");
                    819:        }
                    820: 
                    821:        if (DEBUG_GTE(DB, 1))
                    822:                rprintf(FCLIENT, "[%s] Disconnecting from the DB\n", who_am_i());
                    823: 
                    824:        for (ndx = 0; ndx < MAX_PREP_CNT; ndx++) {
                    825:                if (statements[ndx].all) {
                    826:                        switch (use_db) {
                    827: #ifdef USE_MYSQL
                    828:                        case DB_TYPE_MYSQL:
                    829:                                mysql_stmt_close(statements[ndx].mysql);
                    830:                                break;
                    831: #endif
                    832: #ifdef USE_SQLITE
                    833:                        case DB_TYPE_SQLITE:
                    834:                                sqlite3_finalize(statements[ndx].sqlite);
                    835:                                break;
                    836: #endif
                    837:                        }
                    838:                        statements[ndx].all = NULL;
                    839:                }
                    840:        }
                    841: 
                    842:        switch (use_db) {
                    843: #ifdef USE_MYSQL
                    844:        case DB_TYPE_MYSQL:
                    845:                mysql_close(dbh.mysql);
                    846:                break;
                    847: #endif
                    848: #ifdef USE_SQLITE
                    849:        case DB_TYPE_SQLITE:
                    850:                sqlite3_close(dbh.sqlite);
                    851:                break;
                    852: #endif
                    853:        }
                    854: 
                    855:        dbh.all = NULL;
                    856:        use_db = DB_TYPE_NONE;
                    857: }
                    858: 
                    859: #ifdef USE_MYSQL
                    860: static MYSQL_STMT *exec_mysql(int ndx)
                    861: {
                    862:        MYSQL_STMT *stmt = statements[ndx].mysql;
                    863:        int rc;
                    864: 
                    865:        if ((rc = mysql_stmt_execute(stmt)) == CR_SERVER_LOST) {
                    866:                db_disconnect(False);
                    867:                use_db = DB_TYPE_MYSQL;
                    868:                if (db_connect(select_many_sums)) {
                    869:                        stmt = statements[ndx].mysql;
                    870:                        rc = mysql_stmt_execute(stmt);
                    871:                }
                    872:        }
                    873:        if (rc != 0) {
                    874:                rprintf(log_code, "SQL execute failed: %s\n", mysql_stmt_error(stmt));
                    875:                return NULL;
                    876:        }
                    877: 
                    878:        return stmt;
                    879: }
                    880: #endif
                    881: 
                    882: #ifdef USE_MYSQL
                    883: /* This stores up to max_rows into the values pointed to by the bind data arrays.
                    884:  * If max_rows is > 1, then all the buffer pointers MUST be set to an array long
                    885:  * enough to hold the max count of rows.  The buffer pointer will be incremented
                    886:  * to read additional rows (but never past the end).  If stmt_ptr is non-NULL, it
                    887:  * will be set to the "stmt" pointer IFF we didn't run out of rows before hitting
                    888:  * the max.  In this case, the caller should call mysql_stmt_fetch() to read any
                    889:  * remaining rows (the buffer pointers will point at the final array element) and
                    890:  * then call mysql_stmt_free_result().  If *stmt_ptr is a NULL value, there were
                    891:  * not enough rows to fill the max_rows arrays, and the stmt was already freed. */
                    892: static int fetch_mysql(MYSQL_BIND *binds, int bind_cnt, int ndx, int max_rows, MYSQL_STMT **stmt_ptr)
                    893: {
                    894:        MYSQL_STMT *stmt;
                    895:        int i, rc, rows = 0;
                    896: 
                    897:        if (bind_cnt > MAX_RESULT_BINDS) {
                    898:                fprintf(stderr, "Internal error: MAX_RESULT_BINDS overflow\n");
                    899:                exit_cleanup(RERR_UNSUPPORTED);
                    900:        }
                    901: 
                    902:        if ((stmt = exec_mysql(ndx)) == NULL)
                    903:                return 0;
                    904: 
                    905:        for (i = 0; i < bind_cnt; i++) {
                    906:                binds[i].is_null = &result_is_null[i];
                    907:                binds[i].length = &result_length[i];
                    908:                binds[i].error = &result_error[i];
                    909:        }
                    910:        mysql_stmt_bind_result(stmt, binds);
                    911: 
                    912:        while (rows < max_rows) {
                    913:                if ((rc = mysql_stmt_fetch(stmt)) != 0) {
                    914:                        if (rc != MYSQL_NO_DATA)
                    915:                                rprintf(log_code, "SELECT fetch failed: %s\n", mysql_stmt_error(stmt));
                    916:                        break;
                    917:                }
                    918:                if (++rows >= max_rows)
                    919:                        break;
                    920:                for (i = 0; i < bind_cnt; i++) {
                    921:                        switch (binds[i].buffer_type) {
                    922:                        case MYSQL_TYPE_BLOB:
                    923:                        case MYSQL_TYPE_STRING:
                    924:                            binds[i].buffer += binds[i].buffer_length;
                    925:                            break;
                    926:                        case MYSQL_TYPE_LONG:
                    927:                            binds[i].buffer += sizeof (int);
                    928:                            break;
                    929:                        case MYSQL_TYPE_LONGLONG:
                    930:                            binds[i].buffer += sizeof (int64);
                    931:                            break;
                    932:                        default:
                    933:                            fprintf(stderr, "Unknown MYSQL_TYPE_* in multi-row read: %d.\n", binds[i].buffer_type);
                    934:                            exit_cleanup(RERR_UNSUPPORTED);
                    935:                        }
                    936:                }
                    937:        }
                    938: 
                    939:        if (!stmt_ptr || rows < max_rows) {
                    940:                mysql_stmt_free_result(stmt);
                    941:                stmt = NULL;
                    942:        }
                    943:        if (stmt_ptr)
                    944:                *stmt_ptr = stmt;
                    945: 
                    946:        return rows;
                    947: }
                    948: #endif
                    949: 
                    950: #if defined USE_MYSQL || defined USE_SQLITE
                    951: static void update_mounts(void)
                    952: {
                    953:        char buf[2048], *argv[2];
                    954:        int f_from, f_to, len;
                    955:        STRUCT_STAT st;
                    956:        int pid, status;
                    957: 
                    958:        if (DEBUG_GTE(DB, 2))
                    959:                printf("Running %s to grab mount info\n", mount_helper_script);
                    960:        argv[0] = mount_helper_script;
                    961:        argv[1] = NULL;
                    962:        pid = piped_child(argv, &f_from, &f_to);
                    963:        close(f_to);
                    964: 
                    965:        bind_mtime = time(NULL); /* abuse mtime slightly to hold our last_seen value */
                    966: 
                    967:        /* Strict format has 2 items with one tab as separator: MOUNT_UNIQ\tPATH */
                    968:        while ((len = read_line(f_from, buf, sizeof buf, 0)) > 0) {
                    969:                char *mount_uniq, *path;
                    970: 
                    971:                if (DEBUG_GTE(DB, 3))
                    972:                        printf("Parsing mount info: %s\n", buf);
                    973:                mount_uniq = strtok(buf, "\t");
                    974:                path = mount_uniq ? strtok(NULL, "\r\n") : NULL;
                    975:                if (!path) {
                    976:                        fprintf(stderr, "Failed to parse line from %s output\n", mount_helper_script);
                    977:                        exit_cleanup(RERR_SYNTAX);
                    978:                }
                    979: 
                    980:                if (lstat(path, &st) < 0) {
                    981:                        fprintf(stderr, "Failed to lstat(%s): %s\n", path, strerror(errno));
                    982:                        exit_cleanup(RERR_IPC);
                    983:                }
                    984: 
                    985:                bind_mount_uniq_len = strlcpy(bind_mount_uniq, mount_uniq, sizeof bind_mount_uniq);
                    986:                if (bind_mount_uniq_len >= (int)sizeof bind_mount_uniq)
                    987:                        bind_mount_uniq_len = sizeof bind_mount_uniq - 1;
                    988: 
                    989:                if (db_output_msgs) {
                    990:                        printf("Marking mount \"%s\" (%s) as a recent mount\n",
                    991:                                bind_mount_uniq, big_num(st.st_dev));
                    992:                }
                    993:                switch (use_db) {
                    994: #ifdef USE_MYSQL
                    995:                case DB_TYPE_MYSQL:
                    996:                        bind_devno = st.st_dev;
                    997:                        if (exec_mysql(INS_MOUNT) == NULL) {
                    998:                                fprintf(stderr, "Failed to update mount info for \"%s\" - %s\n",
                    999:                                        bind_mount_uniq, mysql_error(dbh.mysql));
                   1000:                                exit_cleanup(RERR_IPC);
                   1001:                        }
                   1002:                        break;
                   1003: #endif
                   1004: #ifdef USE_SQLITE
                   1005:                case DB_TYPE_SQLITE: {
                   1006:                        int rc, change_cnt;
                   1007:                        sqlite3_stmt *stmt = statements[INS_MOUNT].sqlite;
                   1008:                        sqlite3_bind_text(stmt, 1, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1009:                        sqlite3_bind_int64(stmt, 2, bind_mtime);
                   1010:                        sqlite3_bind_text(stmt, 3, bind_mount_uniq, bind_mount_uniq_len, SQLITE_STATIC);
                   1011:                        sqlite3_bind_int64(stmt, 4, st.st_dev);
                   1012:                        rc = sqlite3_step(stmt);
                   1013:                        if (rc != SQLITE_DONE) {
                   1014:                                fprintf(stderr, "Failed to insert mount info for \"%s\" - %s (%d)\n",
                   1015:                                        bind_mount_uniq, sqlite3_errmsg(dbh.sqlite), rc);
                   1016:                                exit_cleanup(RERR_IPC);
                   1017:                        }
                   1018:                        change_cnt = sqlite3_changes(dbh.sqlite);
                   1019:                        sqlite3_reset(stmt);
                   1020:                        if (change_cnt == 0) {
                   1021:                                stmt = statements[UPD_MOUNT].sqlite;
                   1022:                                sqlite3_bind_int64(stmt, 1, bind_mtime);
                   1023:                                sqlite3_bind_int64(stmt, 2, st.st_dev);
                   1024:                                sqlite3_bind_text(stmt, 3, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1025:                                sqlite3_bind_text(stmt, 4, bind_mount_uniq, bind_mount_uniq_len, SQLITE_STATIC);
                   1026:                                rc = sqlite3_step(stmt);
                   1027:                                if (rc != SQLITE_DONE) {
                   1028:                                        fprintf(stderr, "Failed to update mount info for \"%s\" - %s (%d)\n",
                   1029:                                                bind_mount_uniq, sqlite3_errmsg(dbh.sqlite), rc);
                   1030:                                        exit_cleanup(RERR_IPC);
                   1031:                                }
                   1032:                                sqlite3_reset(stmt);
                   1033:                        }
                   1034:                        break;
                   1035:                    }
                   1036: #endif
                   1037:                }
                   1038:        }
                   1039:        close(f_from);
                   1040: 
                   1041:        waitpid(pid, &status, 0);
                   1042: 
                   1043:        switch (use_db) {
                   1044: #ifdef USE_MYSQL
                   1045:        case DB_TYPE_MYSQL: {
                   1046:                if (db_output_msgs) {
                   1047:                        MYSQL_BIND binds[1];
                   1048:                        MYSQL_STMT *stmt;
                   1049: 
                   1050:                        binds[0].buffer_type = MYSQL_TYPE_BLOB;
                   1051:                        binds[0].buffer = bind_mount_uniq;
                   1052:                        binds[0].buffer_length = sizeof bind_mount_uniq;
                   1053:                        if (fetch_mysql(binds, 1, SEL_MOUNT, 1, &stmt)) {
                   1054:                                while (1) {
                   1055:                                        printf("Marking mount \"%s\" as unmounted.\n", bind_mount_uniq);
                   1056:                                        if (mysql_stmt_fetch(stmt) != 0)
                   1057:                                                break;
                   1058:                                }
                   1059:                                mysql_stmt_free_result(stmt);
                   1060:                        }
                   1061:                }
                   1062: 
                   1063:                if (exec_mysql(UN_MOUNT) == NULL) {
                   1064:                        fprintf(stderr, "Failed to update old mount info - %s\n",
                   1065:                                mysql_error(dbh.mysql));
                   1066:                        exit_cleanup(RERR_IPC);
                   1067:                }
                   1068:                break;
                   1069:            }
                   1070: #endif
                   1071: #ifdef USE_SQLITE
                   1072:        case DB_TYPE_SQLITE: {
                   1073:                sqlite3_stmt *stmt;
                   1074:                int rc;
                   1075: 
                   1076:                if (db_output_msgs) {
                   1077:                        stmt = statements[SEL_MOUNT].sqlite;
                   1078:                        sqlite3_bind_text(stmt, 1, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1079:                        sqlite3_bind_int64(stmt, 2, bind_mtime);
                   1080:                        while (1) {
                   1081:                                if (sqlite3_step(stmt) != SQLITE_ROW)
                   1082:                                        break;
                   1083:                                printf("Marking mount \"%s\" as unmounted.\n", sqlite3_column_text(stmt, 0));
                   1084:                        }
                   1085:                        sqlite3_reset(stmt);
                   1086:                }
                   1087: 
                   1088:                stmt = statements[UN_MOUNT].sqlite;
                   1089:                sqlite3_bind_text(stmt, 1, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1090:                sqlite3_bind_int64(stmt, 2, bind_mtime);
                   1091:                rc = sqlite3_step(stmt);
                   1092:                sqlite3_reset(stmt);
                   1093:                if (rc != SQLITE_DONE) {
                   1094:                        fprintf(stderr, "Failed to update old mount info - %s (%d)\n",
                   1095:                                sqlite3_errmsg(dbh.sqlite), rc);
                   1096:                        exit_cleanup(RERR_IPC);
                   1097:                }
                   1098:                break;
                   1099:            }
                   1100: #endif
                   1101:        }
                   1102: }
                   1103: #endif
                   1104: 
                   1105: static unsigned int get_disk_id(int64 devno)
                   1106: {
                   1107:        static unsigned int prior_disk_id = 0;
                   1108:        static int64 prior_devno = 0;
                   1109: 
                   1110:        if (prior_devno == devno && prior_disk_id) {
                   1111:                if (DEBUG_GTE(DB, 5))
                   1112:                        rprintf(FCLIENT, "get_disk_id(%s,%s) = %d (cached)\n", bind_thishost, big_num(devno), prior_disk_id);
                   1113:                return prior_disk_id;
                   1114:        }
                   1115:        prior_devno = devno;
                   1116: 
                   1117:        switch (use_db) {
                   1118: #ifdef USE_MYSQL
                   1119:        case DB_TYPE_MYSQL: {
                   1120:                MYSQL_BIND binds[1];
                   1121: 
                   1122:                bind_devno = devno; /* The one changing SEL_DEV input value. */
                   1123: 
                   1124:                /* Bind where to put the output. */
                   1125:                binds[0].buffer_type = MYSQL_TYPE_LONG;
                   1126:                binds[0].buffer = &prior_disk_id;
                   1127:                if (!fetch_mysql(binds, 1, SEL_DEV, 1, NULL))
                   1128:                        prior_disk_id = 0;
                   1129:                break;
                   1130:            }
                   1131: #endif
                   1132: #ifdef USE_SQLITE
                   1133:        case DB_TYPE_SQLITE: {
                   1134:                sqlite3_stmt *stmt = statements[SEL_DEV].sqlite;
                   1135:                sqlite3_bind_text(stmt, 1, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1136:                sqlite3_bind_int64(stmt, 2, devno);
                   1137:                if (sqlite3_step(stmt) == SQLITE_ROW)
                   1138:                        prior_disk_id = sqlite3_column_int(stmt, 0);
                   1139:                else
                   1140:                        prior_disk_id = 0;
                   1141:                sqlite3_reset(stmt);
                   1142:                break;
                   1143:            }
                   1144: #endif
                   1145:        }
                   1146: 
                   1147:        if (DEBUG_GTE(DB, 2))
                   1148:                rprintf(FCLIENT, "get_disk_id(%s,%s) = %d\n", bind_thishost, big_num(devno), prior_disk_id);
                   1149:        return prior_disk_id;
                   1150: }
                   1151: 
                   1152: int db_get_checksum(const STRUCT_STAT *st_p, char *sum)
                   1153: {
                   1154:        unsigned int disk_id = get_disk_id(st_p->st_dev);
                   1155:        int ok = 0;
                   1156: 
                   1157:        if (disk_id == 0)
                   1158:                return 0;
                   1159: 
                   1160:        switch (use_db) {
                   1161: #ifdef USE_MYSQL
                   1162:        case DB_TYPE_MYSQL: {
                   1163:                MYSQL_BIND binds[1];
                   1164: 
                   1165:                bind_disk_id = disk_id;
                   1166:                bind_ino = st_p->st_ino;
                   1167:                bind_size = st_p->st_size;
                   1168:                bind_mtime = st_p->st_mtime;
                   1169:                if (!db_lax)
                   1170:                        bind_ctime = st_p->st_ctime;
                   1171: 
                   1172:                binds[0].buffer_type = MYSQL_TYPE_BLOB;
                   1173:                binds[0].buffer = sum;
                   1174:                binds[0].buffer_length = MD5_DIGEST_LEN;
                   1175:                ok = fetch_mysql(binds, 1, SEL_SUM, 1, NULL);
                   1176:                break;
                   1177:            }
                   1178: #endif
                   1179: #ifdef USE_SQLITE
                   1180:        case DB_TYPE_SQLITE: {
                   1181:                sqlite3_stmt *stmt = statements[SEL_SUM].sqlite;
                   1182:                sqlite3_bind_int(stmt, 1, disk_id);
                   1183:                sqlite3_bind_int64(stmt, 2, st_p->st_ino);
                   1184:                sqlite3_bind_int64(stmt, 3, st_p->st_size);
                   1185:                sqlite3_bind_int64(stmt, 4, st_p->st_mtime);
                   1186:                if (!db_lax)
                   1187:                        sqlite3_bind_int64(stmt, 5, st_p->st_ctime);
                   1188:                if (sqlite3_step(stmt) == SQLITE_ROW) {
                   1189:                        int len = sqlite3_column_bytes(stmt, 0);
                   1190:                        if (len > MAX_DIGEST_LEN)
                   1191:                                len = MAX_DIGEST_LEN;
                   1192:                        memcpy(sum, sqlite3_column_blob(stmt, 0), len);
                   1193:                        ok = 1;
                   1194:                }
                   1195:                sqlite3_reset(stmt);
                   1196:                break;
                   1197:            }
                   1198: #endif
                   1199:        }
                   1200: 
                   1201:        if (DEBUG_GTE(DB, 2)) {
                   1202:                if (ok) {
                   1203:                        rprintf(FCLIENT, "[%s] Found DB checksum for %s,%s,%d: %s\n",
                   1204:                                who_am_i(), big_num(st_p->st_dev),
                   1205:                                big_num(st_p->st_ino), md_num, sum_as_hex(md_num, sum, 0));
                   1206:                } else {
                   1207:                        rprintf(FCLIENT, "[%s] No DB checksum for %s,%s,%d\n",
                   1208:                                who_am_i(), big_num(st_p->st_dev),
                   1209:                                big_num(st_p->st_ino), md_num);
                   1210:                }
                   1211:        }
                   1212: 
                   1213:        return ok;
                   1214: }
                   1215: 
                   1216: int db_get_both_checksums(const STRUCT_STAT *st_p, int *right_sum_cnt, int *wrong_sum_cnt, char **sum4, char **sum5)
                   1217: {
                   1218:        static char dbsum[MD5_DIGEST_LEN*2];
                   1219:        int rows, j, sum_type[2];
                   1220:        int64 dbsize[2], dbmtime[2], dbctime[2];
                   1221:        unsigned int disk_id = get_disk_id(st_p->st_dev);
                   1222: 
                   1223:        if (disk_id == 0)
                   1224:                return 0;
                   1225: 
                   1226:        switch (use_db) {
                   1227: #ifdef USE_MYSQL
                   1228:        case DB_TYPE_MYSQL: {
                   1229:                MYSQL_BIND binds[5];
                   1230: 
                   1231:                bind_disk_id = disk_id;
                   1232:                bind_ino = st_p->st_ino;
                   1233: 
                   1234:                binds[0].buffer_type = MYSQL_TYPE_BLOB;
                   1235:                binds[0].buffer = dbsum;
                   1236:                binds[0].buffer_length = MD5_DIGEST_LEN;
                   1237:                binds[1].buffer_type = MYSQL_TYPE_LONG;
                   1238:                binds[1].buffer = (char*)sum_type;
                   1239:                binds[2].buffer_type = MYSQL_TYPE_LONGLONG;
                   1240:                binds[2].buffer = (char*)dbsize;
                   1241:                binds[3].buffer_type = MYSQL_TYPE_LONGLONG;
                   1242:                binds[3].buffer = (char*)dbmtime;
                   1243:                binds[4].buffer_type = MYSQL_TYPE_LONGLONG;
                   1244:                binds[4].buffer = (char*)dbctime;
                   1245:                rows = fetch_mysql(binds, 5, SEL_SUM, 2, NULL);
                   1246:                break;
                   1247:            }
                   1248: #endif
                   1249: #ifdef USE_SQLITE
                   1250:        case DB_TYPE_SQLITE: {
                   1251:                sqlite3_stmt *stmt = statements[SEL_SUM].sqlite;
                   1252:                sqlite3_bind_int(stmt, 1, disk_id);
                   1253:                sqlite3_bind_int64(stmt, 2, st_p->st_ino);
                   1254:                for (j = 0; j < 2; j++) {
                   1255:                        int len;
                   1256:                        if (sqlite3_step(stmt) != SQLITE_ROW)
                   1257:                                break;
                   1258:                        len = sqlite3_column_bytes(stmt, 0);
                   1259:                        if (len > MD5_DIGEST_LEN)
                   1260:                                len = MD5_DIGEST_LEN;
                   1261:                        memcpy(dbsum + MD5_DIGEST_LEN*j, sqlite3_column_blob(stmt, 0), len);
                   1262:                        sum_type[j] = sqlite3_column_int(stmt, 1);
                   1263:                        dbsize[j] = sqlite3_column_int(stmt, 2);
                   1264:                        dbmtime[j] = sqlite3_column_int64(stmt, 3);
                   1265:                        dbctime[j] = sqlite3_column_int64(stmt, 4);
                   1266:                }
                   1267:                sqlite3_reset(stmt);
                   1268:                rows = j;
                   1269:                break;
                   1270:            }
                   1271: #endif
                   1272:        default:
                   1273:                return 0;
                   1274:        }
                   1275: 
                   1276:        if (sum4)
                   1277:                *sum4 = NULL;
                   1278:        if (sum5)
                   1279:                *sum5 = NULL;
                   1280:        *right_sum_cnt = *wrong_sum_cnt = 0;
                   1281:        for (j = 0; j < rows; j++) {
                   1282:                if (DEBUG_GTE(DB, 3)) {
                   1283:                        rprintf(FCLIENT, "DB checksum for %s,%s,%d: %s\n",
                   1284:                                big_num(st_p->st_dev), big_num(st_p->st_ino), sum_type[j],
                   1285:                                sum_as_hex(sum_type[j], dbsum + MD5_DIGEST_LEN*j, 0));
                   1286:                }
                   1287: 
                   1288:                if (sum_type[j] == 4) {
                   1289:                        if (!sum4)
                   1290:                                continue;
                   1291:                        *sum4 = dbsum + MD5_DIGEST_LEN*j;
                   1292:                } else {
                   1293:                        if (!sum5)
                   1294:                                continue;
                   1295:                        *sum5 = dbsum + MD5_DIGEST_LEN*j;
                   1296:                }
                   1297:                if (st_p->st_size == dbsize[j] && st_p->st_mtime == dbmtime[j] && (db_lax || st_p->st_ctime == dbctime[j]))
                   1298:                        ++*right_sum_cnt;
                   1299:                else
                   1300:                        ++*wrong_sum_cnt;
                   1301:        }
                   1302: 
                   1303:        return rows;
                   1304: }
                   1305: 
                   1306: int db_set_checksum(int mdnum, const STRUCT_STAT *st_p, const char *sum)
                   1307: {
                   1308:        unsigned int disk_id;
                   1309:        const char *errmsg = NULL;
                   1310:        int rc = 0;
                   1311: 
                   1312:        if (am_receiver || (am_generator && same_db)) {
                   1313:                /* Forward the setting to a single process.  The receiver always
                   1314:                 * forwards to the generator, and the generator will forward to
                   1315:                 * the sender ONLY if this is a local transfer. */
                   1316:                char data[MSG_CHECKSUM_LEN];
                   1317:                SIVAL64(data, 0, st_p->st_dev);
                   1318:                SIVAL64(data, 8, st_p->st_ino);
                   1319:                SIVAL64(data, 16, st_p->st_size);
                   1320:                SIVAL64(data, 24, st_p->st_mtime);
                   1321:                SIVAL64(data, 32, st_p->st_ctime);
                   1322: #if MSG_CHECKSUM_LONGS != 5
                   1323: #error Fix the setting of checksum long values
                   1324: #endif
                   1325:                SIVAL(data, MSG_CHECKSUM_LONGS*8, mdnum);
                   1326:                memcpy(data + MSG_CHECKSUM_LONGS*8 + 4, sum, MAX_DIGEST_LEN);
                   1327:                return send_msg(MSG_CHECKSUM, data, sizeof data, 0);
                   1328:        }
                   1329: 
                   1330:        if ((disk_id = get_disk_id(st_p->st_dev)) == 0)
                   1331:                return 0;
                   1332: 
                   1333:        switch (use_db) {
                   1334: #ifdef USE_MYSQL
                   1335:        case DB_TYPE_MYSQL:
                   1336:                if (transaction_state == 0) {
                   1337:                        if (!run_sql("BEGIN"))
                   1338:                                return 0;
                   1339:                        transaction_state = 1;
                   1340:                }
                   1341: 
                   1342:                bind_disk_id = disk_id;
                   1343:                bind_ino = st_p->st_ino;
                   1344:                bind_mdnum = mdnum;
                   1345:                bind_size = st_p->st_size;
                   1346:                bind_mtime = st_p->st_mtime;
                   1347:                bind_ctime = st_p->st_ctime;
                   1348:                memcpy(bind_sum, sum, MD5_DIGEST_LEN);
                   1349:                if (exec_mysql(REP_SUM) == NULL)
                   1350:                        errmsg = mysql_error(dbh.mysql);
                   1351:                break;
                   1352: #endif
                   1353: #ifdef USE_SQLITE
                   1354:        case DB_TYPE_SQLITE: {
                   1355:                sqlite3_stmt *stmt = statements[REP_SUM].sqlite;
                   1356:                int lock_failures = 0;
                   1357: 
                   1358:                if (transaction_state == 0) {
                   1359:                        if (!run_sql("BEGIN"))
                   1360:                                return 0;
                   1361:                        transaction_state = 1;
                   1362:                }
                   1363: 
                   1364:                sqlite3_bind_int(stmt, 1, disk_id);
                   1365:                sqlite3_bind_int64(stmt, 2, st_p->st_ino);
                   1366:                sqlite3_bind_int(stmt, 3, mdnum);
                   1367:                sqlite3_bind_int64(stmt, 4, st_p->st_size);
                   1368:                sqlite3_bind_int64(stmt, 5, st_p->st_mtime);
                   1369:                sqlite3_bind_int64(stmt, 6, st_p->st_ctime);
                   1370:                sqlite3_bind_blob(stmt, 7, sum, MD5_DIGEST_LEN, SQLITE_TRANSIENT);
                   1371:                while (1) {
                   1372:                        rc = sqlite3_step(stmt);
                   1373:                        if (rc != SQLITE_BUSY && rc != SQLITE_LOCKED)
                   1374:                                break;
                   1375:                        if (++lock_failures > MAX_LOCK_FAILURES)
                   1376:                                break;
                   1377:                        sqlite3_reset(stmt);
                   1378:                        msleep(LOCK_FAIL_MSLEEP);
                   1379:                }
                   1380:                if (rc != SQLITE_DONE)
                   1381:                        errmsg = sqlite3_errmsg(dbh.sqlite);
                   1382:                sqlite3_reset(stmt);
                   1383:                break;
                   1384:            }
                   1385: #endif
                   1386:        }
                   1387: 
                   1388:        if (!errmsg) {
                   1389:                if (DEBUG_GTE(DB, 2)) {
                   1390:                        rprintf(FCLIENT, "[%s] Set DB checksum for %s,%s,%d: %s\n",
                   1391:                                who_am_i(), big_num(st_p->st_dev), big_num(st_p->st_ino),
                   1392:                                md_num, sum_as_hex(md_num, sum, 0));
                   1393:                }
                   1394:        } else {
                   1395:                rprintf(log_code, "[%s] Failed to set checksum for %s,%s,%d: %s (%d) -- closing DB\n",
                   1396:                        who_am_i(), big_num(st_p->st_dev), big_num(st_p->st_ino),
                   1397:                        md_num, errmsg, rc);
                   1398:                db_disconnect(False);
                   1399:        }
                   1400: 
                   1401:        return errmsg ? 0 : 1;
                   1402: }
                   1403: 
                   1404: /* For a delayed-update copy, we set the checksum on the file when it was
                   1405:  * inside the partial-dir.  Since renaming the file changes its ctime, we need
                   1406:  * to update the ctime to its new value (we can skip this in db_lax mode). */
                   1407: int db_update_ctime(UNUSED(int mdnum), const STRUCT_STAT *st_p)
                   1408: {
                   1409:        unsigned int disk_id = get_disk_id(st_p->st_dev);
                   1410: 
                   1411:        if (disk_id == 0)
                   1412:                return 0;
                   1413: 
                   1414:        switch (use_db) {
                   1415: #ifdef USE_MYSQL
                   1416:        case DB_TYPE_MYSQL:
                   1417:                bind_ctime = st_p->st_ctime;
                   1418:                bind_disk_id = disk_id;
                   1419:                bind_ino = st_p->st_ino;
                   1420:                bind_mdnum = mdnum;
                   1421:                bind_size = st_p->st_size;
                   1422:                bind_mtime = st_p->st_mtime;
                   1423:                return exec_mysql(UPD_CTIME) != NULL;
                   1424: #endif
                   1425: #ifdef USE_SQLITE
                   1426:        case DB_TYPE_SQLITE: {
                   1427:                int rc;
                   1428: 
                   1429:                sqlite3_stmt *stmt = statements[UPD_CTIME].sqlite;
                   1430:                if (stmt == NULL)
                   1431:                        return 0;
                   1432:                sqlite3_bind_int64(stmt, 1, st_p->st_ctime);
                   1433:                sqlite3_bind_int(stmt, 2, disk_id);
                   1434:                sqlite3_bind_int64(stmt, 3, st_p->st_ino);
                   1435:                sqlite3_bind_int(stmt, 4, mdnum);
                   1436:                sqlite3_bind_int64(stmt, 5, st_p->st_size);
                   1437:                sqlite3_bind_int64(stmt, 6, st_p->st_mtime);
                   1438:                rc = sqlite3_step(stmt);
                   1439:                sqlite3_reset(stmt);
                   1440:                return rc == SQLITE_DONE;
                   1441:            }
                   1442: #endif
                   1443:        }
                   1444: 
                   1445:        return 0;
                   1446: }
                   1447: 
                   1448: static int db_clean_init(void)
                   1449: {
                   1450:        switch (use_db) {
                   1451: #ifdef USE_MYSQL
                   1452:        case DB_TYPE_MYSQL: {
                   1453:                MYSQL_BIND binds[MAX_BIND_CNT];
                   1454:                char *sql;
                   1455: 
                   1456:                mysql_query(dbh.mysql,
                   1457:                        "CREATE TEMPORARY TABLE inode_present ("
                   1458:                        " disk_id integer unsigned NOT NULL,"
                   1459:                        " ino bigint unsigned NOT NULL,"
                   1460:                        " PRIMARY KEY (disk_id,ino)"
                   1461:                        ") ENGINE=MEMORY"
                   1462:                        );
                   1463: 
                   1464:                sql="INSERT IGNORE INTO inode_present"
                   1465:                    " SET disk_id = ?, ino = ?";
                   1466:                memset(binds, 0, sizeof binds);
                   1467:                binds[0].buffer_type = MYSQL_TYPE_LONG;
                   1468:                binds[0].buffer = &bind_disk_id;
                   1469:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                   1470:                binds[1].buffer = &bind_ino;
                   1471:                if (!prepare_mysql(INS_PRESENT, binds, 2, sql))
                   1472:                        exit_cleanup(RERR_SYNTAX);
                   1473: 
                   1474:                sql="DELETE m.*"
                   1475:                    " FROM inode_map AS m"
                   1476:                    " LEFT JOIN inode_present AS p USING(disk_id, ino)"
                   1477:                    " JOIN disk AS d ON(m.disk_id = d.disk_id)"
                   1478:                    " WHERE host = ? AND devno != 0 AND p.disk_id IS NULL AND ctime < ?";
                   1479:                memset(binds, 0, sizeof binds);
                   1480:                binds[0].buffer_type = MYSQL_TYPE_STRING;
                   1481:                binds[0].buffer = &bind_thishost;
                   1482:                binds[0].buffer_length = bind_thishost_len;
                   1483:                binds[1].buffer_type = MYSQL_TYPE_LONGLONG;
                   1484:                binds[1].buffer = &bind_ctime;
                   1485:                if (!prepare_mysql(DEL_SUMS, binds, 2, sql))
                   1486:                        exit_cleanup(RERR_SYNTAX);
                   1487: 
                   1488:                return 1;
                   1489:            }
                   1490: #endif
                   1491: #ifdef USE_SQLITE
                   1492:        case DB_TYPE_SQLITE: {
                   1493:                char *sql;
                   1494:                sql="ATTACH DATABASE '' AS aux1;"; /* Private temp DB, probably in-memory */
                   1495:                if (!run_sql(sql))
                   1496:                        exit_cleanup(RERR_IPC);
                   1497: 
                   1498:                sql="CREATE TABLE aux1.inode_present ("
                   1499:                    " disk_id integer NOT NULL,"
                   1500:                    " ino bigint NOT NULL,"
                   1501:                    " PRIMARY KEY (disk_id,ino)"
                   1502:                    ")";
                   1503:                if (!run_sql(sql))
                   1504:                        exit_cleanup(RERR_IPC);
                   1505: 
                   1506:                sql="INSERT OR IGNORE INTO aux1.inode_present"
                   1507:                    " (disk_id, ino)"
                   1508:                    " VALUES (?, ?)";
                   1509:                if (!prepare_sqlite(INS_PRESENT, sql))
                   1510:                        exit_cleanup(RERR_IPC);
                   1511: 
                   1512:                sql="DELETE FROM inode_map"
                   1513:                    " WHERE ROWID IN ("
                   1514:                    "  SELECT m.ROWID"
                   1515:                    "  FROM inode_map AS m"
                   1516:                    "  LEFT JOIN aux1.inode_present AS p USING(disk_id, ino)"
                   1517:                    "  JOIN disk AS d ON(m.disk_id = d.disk_id)"
                   1518:                    "  WHERE host = ? AND devno != 0 AND p.disk_id IS NULL AND ctime < ?"
                   1519:                    " )";
                   1520:                if (!prepare_sqlite(DEL_SUMS, sql))
                   1521:                        exit_cleanup(RERR_IPC);
                   1522: 
                   1523:                transaction_state = -1; /* bug work-around -- force transaction off when cleaning XXX */
                   1524: 
                   1525:                return 1;
                   1526:            }
                   1527: #endif
                   1528:        }
                   1529: 
                   1530:        return 0;
                   1531: }
                   1532: 
                   1533: static int db_note_present(UNUSED(int disk_id), UNUSED(int64 ino))
                   1534: {
                   1535:        switch (use_db) {
                   1536: #ifdef USE_MYSQL
                   1537:        case DB_TYPE_MYSQL:
                   1538:                bind_disk_id = disk_id;
                   1539:                bind_ino = ino;
                   1540:                return exec_mysql(INS_PRESENT) != NULL;
                   1541: #endif
                   1542: #ifdef USE_SQLITE
                   1543:        case DB_TYPE_SQLITE: {
                   1544:                int rc;
                   1545:                sqlite3_stmt *stmt = statements[INS_PRESENT].sqlite;
                   1546:                sqlite3_bind_int(stmt, 1, disk_id);
                   1547:                sqlite3_bind_int64(stmt, 2, ino);
                   1548:                rc = sqlite3_step(stmt);
                   1549:                sqlite3_reset(stmt);
                   1550:                return rc == SQLITE_DONE;
                   1551:            }
                   1552: #endif
                   1553:        }
                   1554: 
                   1555:        return 0;
                   1556: }
                   1557: 
                   1558: /* This function requires the user to have populated all disk_id+inode pairs
                   1559:  * into the inode_present table. */
                   1560: static int db_clean_inodes(UNUSED(time_t start_time))
                   1561: {
                   1562:        int del_cnt = 0;
                   1563: 
                   1564:        /* The extra ctime < start_time check ensures that brand-new checksums that
                   1565:         * were added after the start of our cleaning run are not removed. */
                   1566:        switch (use_db) {
                   1567: #ifdef USE_MYSQL
                   1568:        case DB_TYPE_MYSQL: {
                   1569:                MYSQL_STMT *stmt;
                   1570:                bind_ctime = start_time;
                   1571:                stmt = exec_mysql(DEL_SUMS);
                   1572:                if (stmt != NULL)
                   1573:                        del_cnt = mysql_affected_rows(dbh.mysql);
                   1574:                break;
                   1575:            }
                   1576: #endif
                   1577: #ifdef USE_SQLITE
                   1578:        case DB_TYPE_SQLITE: {
                   1579:                int rc;
                   1580:                sqlite3_stmt *stmt = statements[DEL_SUMS].sqlite;
                   1581:                sqlite3_bind_text(stmt, 1, bind_thishost, bind_thishost_len, SQLITE_STATIC);
                   1582:                sqlite3_bind_int64(stmt, 2, start_time);
                   1583:                rc = sqlite3_step(stmt);
                   1584:                if (rc == SQLITE_DONE)
                   1585:                        del_cnt = sqlite3_changes(dbh.sqlite);
                   1586:                sqlite3_reset(stmt);
                   1587:                break;
                   1588:            }
                   1589: #endif
                   1590:        }
                   1591: 
                   1592:        return del_cnt;
                   1593: }
                   1594: 
                   1595: static int abs_path(char *buf, int bufsiz, const char *curdir, const char *dir)
                   1596: {
                   1597:        if (*dir == '/')
                   1598:                strlcpy(buf, dir, bufsiz);
                   1599:        else {
                   1600:                int len = snprintf(buf, bufsiz, "%s/%s", curdir, dir);
                   1601:                assert(len > 0); /* silence a compiler warning */
                   1602:        }
                   1603: 
                   1604:        return clean_fname(buf, CFN_DROP_TRAILING_DOT_DIR | CFN_COLLAPSE_DOT_DOT_DIRS);
                   1605: }
                   1606: 
                   1607: static struct name_list *new_name(const char *basename, const char *filename)
                   1608: {
                   1609:        struct name_list *n;
                   1610:        int blen = strlen(basename);
                   1611:        int slen = filename ? (int)strlen(filename) : -1;
                   1612:        int len = blen + 1 + slen;
                   1613: 
                   1614:        if (len >= MAXPATHLEN) {
                   1615:                if (filename)
                   1616:                        rprintf(FERROR, "Filename too long: %s/%s\n", basename, filename);
                   1617:                else
                   1618:                        rprintf(FERROR, "Filename too long: %s\n", basename);
                   1619:                return NULL;
                   1620:        }
                   1621: 
                   1622:        n = (struct name_list *)new_array(char, sizeof (struct name_list) + len);
                   1623: 
                   1624:        memcpy(n->name, basename, blen);
                   1625:        if (filename) {
                   1626:                n->name[blen] = '/';
                   1627:                memcpy(n->name + 1 + blen, filename, slen);
                   1628:        }
                   1629:        n->name[len] = '\0';
                   1630:        n->next = NULL;
                   1631: 
                   1632:        return n;
                   1633: }
                   1634: 
                   1635: static int name_compare(const void *n1, const void *n2)
                   1636: {
                   1637:        struct name_list *p1 = *(struct name_list **)n1;
                   1638:        struct name_list *p2 = *(struct name_list **)n2;
                   1639:        return strcmp(p1->name, p2->name);
                   1640: }
                   1641: 
                   1642: static struct name_list *get_sorted_names(const char *dir)
                   1643: {
                   1644:        struct name_list *add, **sortbuf, *names = NULL, *prior_name = NULL;
                   1645:        struct dirent *di;
                   1646:        int cnt = 0;
                   1647:        DIR *d;
                   1648: 
                   1649:        if (!(d = opendir("."))) {
                   1650:                rprintf(FERROR, "Unable to opendir %s: %s\n", dir, strerror(errno));
                   1651:                return NULL;
                   1652:        }
                   1653:        while ((di = readdir(d)) != NULL) {
                   1654:                char *dname = d_name(di);
                   1655:                if (dname[0] == '.' && (dname[1] == '\0' || (dname[1] == '.' && dname[2] == '\0')))
                   1656:                        continue;
                   1657:                if (!(add = new_name(dname, NULL)))
                   1658:                        continue;
                   1659:                if (prior_name)
                   1660:                        prior_name->next = add;
                   1661:                else
                   1662:                        names = add;
                   1663:                prior_name = add;
                   1664:                cnt++;
                   1665:        }
                   1666:        closedir(d);
                   1667: 
                   1668:        if (cnt) {
                   1669:                int j;
                   1670: 
                   1671:                sortbuf = new_array(struct name_list *, cnt);
                   1672:                for (j = 0; j < cnt; j++) {
                   1673:                        sortbuf[j] = names;
                   1674:                        names = names->next;
                   1675:                }
                   1676: 
                   1677:                qsort(sortbuf, cnt, PTR_SIZE, name_compare);
                   1678: 
                   1679:                names = prior_name = NULL;
                   1680:                for (j = 0; j < cnt; j++) {
                   1681:                        add = sortbuf[j];
                   1682:                        if (prior_name)
                   1683:                                prior_name->next = add;
                   1684:                        else
                   1685:                                names = add;
                   1686:                        prior_name = add;
                   1687:                }
                   1688: 
                   1689:                if (prior_name)
                   1690:                        prior_name->next = NULL;
                   1691:                free(sortbuf);
                   1692:        }
                   1693: 
                   1694:        return names;
                   1695: }
                   1696: 
                   1697: static inline int sums_ne(const char *sum1, const char *sum2)
                   1698: {
                   1699:        return memcmp(sum1, sum2, MD5_DIGEST_LEN) != 0;
                   1700: }
                   1701: 
                   1702: /* Returns 1 if there is a checksum change, else 0. */
                   1703: static int mention_file(const char *dir, const char *name, int right_cnt, int wrong_cnt,
                   1704:                        const char *dbsum4, const char *dbsum5, const char *sum4, const char *sum5)
                   1705: {
                   1706:        char *info_str = wrong_cnt && !right_cnt ? "!i " : "   ";
                   1707:        char *md4_str = !db_do_md4 ? NULL : !dbsum4 ? "+4 " : !sum4 ? "?4 " : sums_ne(sum4, dbsum4) ? "!4 " : "   ";
                   1708:        char *md5_str = !db_do_md5 ? NULL : !dbsum5 ? "+5 " : !sum5 ? "?5 " : sums_ne(sum5, dbsum5) ? "!5 " : "   ";
                   1709:        int chg = *info_str != ' ' || (md4_str && *md4_str != ' ') || (md5_str && *md5_str != ' ');
                   1710:        if (chg || db_output_unchanged) {
                   1711:                if (db_output_info) {
                   1712:                        fputs(info_str, stdout);
                   1713:                        if (md4_str)
                   1714:                                fputs(md4_str, stdout);
                   1715:                        if (md5_str)
                   1716:                                fputs(md5_str, stdout);
                   1717:                }
                   1718:                if (db_output_sum) {
                   1719:                        if (db_do_md4)
                   1720:                                printf("%s ", sum_as_hex(4, sum4, 0));
                   1721:                        if (db_do_md5)
                   1722:                                printf("%s ", sum_as_hex(5, sum5, 0));
                   1723:                }
                   1724:                if (db_output_name) {
                   1725:                        if (db_output_sum)
                   1726:                                putchar(' '); /* We want 2 spaces, like md5sum. */
                   1727:                        if (*dir != '.' || dir[1]) {
                   1728:                                fputs(dir, stdout);
                   1729:                                putchar('/');
                   1730:                        }
                   1731:                        puts(name);
                   1732:                }
                   1733:        }
                   1734: 
                   1735:        return chg;
                   1736: }
                   1737: 
                   1738: NORETURN void run_dbonly(const char **args)
                   1739: {
                   1740:        char start_dir[MAXPATHLEN], dirbuf[MAXPATHLEN];
                   1741:        int need_sum_cnt, start_dir_len;
                   1742:        struct name_list *prior_dir;
                   1743:        struct name_list *names;
                   1744:        time_t clean_start = 0;
                   1745:        int exit_code = 0;
                   1746: 
                   1747:        checksum_type = 5;
                   1748: 
                   1749:        need_sum_cnt = db_do_md4 + db_do_md5;
                   1750: 
                   1751:        if (!db_read_config(FERROR, db_config) || !db_connect(1))
                   1752:                exit_cleanup(RERR_FILEIO);
                   1753: 
                   1754:        if (db_clean) {
                   1755:                clean_start = time(NULL);
                   1756:                db_clean_init();
                   1757:        }
                   1758: 
                   1759:        if (getcwd(start_dir, sizeof start_dir - 1) == NULL) {
                   1760:                rsyserr(FERROR, errno, "getcwd()");
                   1761:                exit_cleanup(RERR_FILESELECT);
                   1762:        }
                   1763:        start_dir_len = strlen(start_dir);
                   1764: 
                   1765:        if (args) {
                   1766:                prior_dir = NULL;
                   1767:                while (*args) {
                   1768:                        struct name_list *add;
                   1769:                        if (abs_path(dirbuf, sizeof dirbuf, start_dir, *args++) <= 0)
                   1770:                                continue;
                   1771:                        if (!(add = new_name(dirbuf, NULL)))
                   1772:                                continue;
                   1773:                        if (prior_dir)
                   1774:                                prior_dir->next = add;
                   1775:                        else
                   1776:                                dirs_list = add;
                   1777:                        prior_dir = add;
                   1778:                }
                   1779:        } else
                   1780:                dirs_list = new_name(start_dir, NULL);
                   1781: 
                   1782:        prior_dir = NULL;
                   1783:        while (dirs_list) {
                   1784:                struct name_list *subdirs, *prior_subdir, *prior_name;
                   1785:                const char *dir = dirs_list->name;
                   1786:                const char *reldir = dir;
                   1787: 
                   1788:                if (prior_dir)
                   1789:                        free((void*)prior_dir);
                   1790:                prior_dir = dirs_list;
                   1791:                dirs_list = dirs_list->next;
                   1792: 
                   1793:                if (strncmp(reldir, start_dir, start_dir_len) == 0) {
                   1794:                        if (reldir[start_dir_len] == '\0')
                   1795:                                reldir = ".";
                   1796:                        else if (reldir[start_dir_len] == '/')
                   1797:                                reldir += start_dir_len + 1;
                   1798:                }
                   1799:                if (db_output_dirs)
                   1800:                        printf("... %s/ ...\n", reldir);
                   1801: 
                   1802:                if (chdir(dir) < 0) {
                   1803:                        rprintf(FERROR, "Unable to chdir to %s: %s\n", dir, strerror(errno));
                   1804:                        continue;
                   1805:                }
                   1806:                if (!(names = get_sorted_names(dir)))
                   1807:                        continue;
                   1808: 
                   1809:                subdirs = prior_subdir = prior_name = NULL;
                   1810:                while (names) {
                   1811:                        STRUCT_STAT st;
                   1812:                        char *dbsum4, *sum4, sumbuf4[MD5_DIGEST_LEN];
                   1813:                        char *dbsum5, *sum5, sumbuf5[MD5_DIGEST_LEN];
                   1814:                        int right_sum_cnt, wrong_sum_cnt;
                   1815:                        const char *name = names->name;
                   1816:                        unsigned int disk_id;
                   1817: 
                   1818:                        if (prior_name)
                   1819:                                free((void*)prior_name);
                   1820:                        prior_name = names;
                   1821:                        names = names->next;
                   1822: 
                   1823:                        dbsum4 = dbsum5 = sum4 = sum5 = NULL;
                   1824: 
                   1825:                        if (lstat(name, &st) < 0) {
                   1826:                                rprintf(FERROR, "Failed to lstat(%s): %s\n", name, strerror(errno));
                   1827:                                continue;
                   1828:                        }
                   1829:                        if (S_ISLNK(st.st_mode))
                   1830:                                continue;
                   1831:                        if (S_ISDIR(st.st_mode)) {
                   1832:                                /* add optional excluding of things like /^(CVS|\.svn|\.git|\.bzr)$/; */
                   1833:                                if (recurse) {
                   1834:                                        struct name_list *add = new_name(dir, name);
                   1835:                                        if (add) {
                   1836:                                                if (prior_subdir)
                   1837:                                                        prior_subdir->next = add;
                   1838:                                                else
                   1839:                                                        subdirs = add;
                   1840:                                                prior_subdir = add;
                   1841:                                        }
                   1842:                                }
                   1843:                                continue;
                   1844:                        }
                   1845:                        if (!S_ISREG(st.st_mode))
                   1846:                                continue;
                   1847: 
                   1848:                        if (!(disk_id = get_disk_id(st.st_dev)))
                   1849:                                continue;
                   1850:                        if (db_clean) {
                   1851:                                db_note_present(disk_id, st.st_ino);
                   1852:                                if (!db_update && !db_check)
                   1853:                                        continue;
                   1854:                        }
                   1855:                        db_get_both_checksums(&st, &right_sum_cnt, &wrong_sum_cnt,
                   1856:                                              db_do_md4 ? &dbsum4 : NULL, db_do_md5 ? &dbsum5 : NULL);
                   1857: 
                   1858:                        if (!db_check && right_sum_cnt == need_sum_cnt) {
                   1859:                                mention_file(reldir, name, right_sum_cnt, wrong_sum_cnt, dbsum4, dbsum5, dbsum4, dbsum5);
                   1860:                                continue;
                   1861:                        }
                   1862: 
                   1863:                        if (db_update || (db_check && right_sum_cnt) || db_output_sum) {
                   1864:                                uchar *data;
                   1865:                                int32 remainder;
                   1866:                                md_context m4;
                   1867:                                MD5_CTX m5;
                   1868:                                struct map_struct *buf;
                   1869:                                OFF_T off, len = st.st_size;
                   1870:                                int fd = do_open(name, O_RDONLY, 0);
                   1871: 
                   1872:                                if (fd < 0) {
                   1873:                                        rprintf(FERROR, "ERROR: unable to read %s: %s\n", name, strerror(errno));
                   1874:                                        continue;
                   1875:                                }
                   1876: 
                   1877:                                if (db_do_md4)
                   1878:                                        mdfour_begin(&m4);
                   1879:                                if (db_do_md5)
                   1880:                                        MD5_Init(&m5);
                   1881: 
                   1882:                                buf = map_file(fd, len, MAX_MAP_SIZE, CSUM_CHUNK);
                   1883: 
                   1884:                                for (off = 0; off + CSUM_CHUNK <= len; off += CSUM_CHUNK) {
                   1885:                                        data = (uchar*)map_ptr(buf, off, CSUM_CHUNK);
                   1886:                                        if (db_do_md4)
                   1887:                                                mdfour_update(&m4, data, CSUM_CHUNK);
                   1888:                                        if (db_do_md5)
                   1889:                                                MD5_Update(&m5, data, CSUM_CHUNK);
                   1890:                                }
                   1891: 
                   1892:                                remainder = (int32)(len - off);
                   1893:                                data = (uchar*)map_ptr(buf, off, remainder);
                   1894:                                if (db_do_md4) {
                   1895:                                        mdfour_update(&m4, data, remainder);
                   1896:                                        mdfour_result(&m4, (uchar*)(sum4 = sumbuf4));
                   1897:                                }
                   1898:                                if (db_do_md5) {
                   1899:                                        MD5_Update(&m5, data, remainder);
                   1900:                                        MD5_Final((uchar*)(sum5 = sumbuf5), &m5);
                   1901:                                }
                   1902: 
                   1903:                                close(fd);
                   1904:                                unmap_file(buf);
                   1905:                        }
                   1906: 
                   1907:                        int chg = mention_file(reldir, name, right_sum_cnt, wrong_sum_cnt, dbsum4, dbsum5, sum4, sum5);
                   1908:                        if (!chg) {
                   1909:                                /* Only db_check should get here... */
                   1910:                        } else if (!db_update) {
                   1911:                                exit_code = 1;
                   1912:                        } else {
                   1913:                                int fail = 0;
                   1914:                                if (db_do_md4 && !db_set_checksum(4, &st, sum4))
                   1915:                                        fail = 1;
                   1916:                                if (db_do_md5 && !db_set_checksum(5, &st, sum5))
                   1917:                                        fail = 1;
                   1918:                                if (fail) {
                   1919:                                        fprintf(stderr, "Failed to set checksum on %s/%s\n", reldir, name);
                   1920:                                        exit_cleanup(RERR_FILEIO);
                   1921:                                }
                   1922:                        }
                   1923:                }
                   1924:                if (prior_name)
                   1925:                        free((void*)prior_name);
                   1926: 
                   1927:                if (recurse && subdirs) {
                   1928:                        prior_subdir->next = dirs_list;
                   1929:                        dirs_list = subdirs;
                   1930:                }
                   1931:        }
                   1932:        if (prior_dir)
                   1933:                free((void*)prior_dir);
                   1934: 
                   1935:        if (db_clean) {
                   1936:                int rows = db_clean_inodes(clean_start);
                   1937:                if (db_output_msgs)
                   1938:                        printf("Cleaned out %d old inode%s.\n", rows, rows == 1 ? "" : "s");
                   1939:        }
                   1940: 
                   1941:        db_disconnect(True);
                   1942:        exit(exit_code);
                   1943: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>