/* Check if -f is requested and wipe db if yes */
if ((flags & DBD_FLAGS_FORCE) && rebuild && (volinfo.v_flags & AFPVOL_CACHE)) {
char cmd[8 + MAXPATHLEN];
-
- if ((db_locked = get_lock(0, NULL)) != 0)
+ if ((db_locked = get_lock(LOCK_FREE, NULL)) != 0)
goto exit_failure;
- snprintf(cmd, 8 + MAXPATHLEN, "rm -f %s/*", dbpath);
+
+ snprintf(cmd, 8 + MAXPATHLEN, "rm -rf \"%s\"", dbpath);
dbd_log( LOGDEBUG, "Removing old database of volume: '%s'", volpath);
system(cmd);
+ if ((mkdir(dbpath, 0755)) != 0) {
+ dbd_log( LOGSTD, "Can't create dbpath \"%s\": %s", dbpath, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
dbd_log( LOGDEBUG, "Removed old database.");
- if ((db_locked = get_lock(1, dbpath)) == -1)
+ if ((db_locked = get_lock(LOCK_EXCL, dbpath)) == -1)
goto exit_failure;
}
dbif_close(dbd);
goto exit_failure;
}
-
- if (dbd_stamp(dbd) < 0) {
- dbif_close(dbd);
- goto exit_failure;
- }
}
+ /* Downgrade db lock if not running exclusive */
+ if (!exclusive && (db_locked == LOCK_EXCL)) {
+ if (get_lock(LOCK_UNLOCK, NULL) != 0)
+ goto exit_failure;
+ if (get_lock(LOCK_SHRD, NULL) != LOCK_SHRD)
+ goto exit_failure;
+ }
+
/* Now execute given command scan|rebuild|dump */
if (dump && ! nocniddb) {
if (dbif_dump(dbd, dumpindexes) < 0) {
return ret;
}
-/* --------------- */
-int dbif_stamp(DBD *dbd, void *buffer, int size)
-{
- struct stat st;
- int rc,cwd;
-
- if (size < 8)
- return -1;
-
- /* Remember cwd */
- if ((cwd = open(".", O_RDONLY)) < 0) {
- LOG(log_error, logtype_cnid, "error opening cwd: %s", strerror(errno));
- return -1;
- }
-
- /* chdir to db_envhome */
- if ((chdir(dbd->db_envhome)) != 0) {
- LOG(log_error, logtype_cnid, "error chdiring to db_env '%s': %s", dbd->db_envhome, strerror(errno));
- return -1;
- }
-
- if ((rc = stat(dbd->db_table[DBIF_CNID].name, &st)) < 0) {
- LOG(log_error, logtype_cnid, "error stating database %s: %s", dbd->db_table[DBIF_CNID].name, db_strerror(errno));
- return -1;
- }
- memset(buffer, 0, size);
- memcpy(buffer, &st.st_ctime, sizeof(st.st_ctime));
-
- if ((fchdir(cwd)) != 0) {
- LOG(log_error, logtype_cnid, "error chdiring back: %s", strerror(errno));
- return -1;
- }
-
- return 0;
-}
-
+ /*!
+ * Get lock on db lock file
+ *
+ * @args cmd (r) lock command:
+ * LOCK_FREE: close lockfd
+ * LOCK_UNLOCK: unlock lockm keep lockfd open
+ * LOCK_EXCL: F_WRLCK on lockfd
+ * LOCK_SHRD: F_RDLCK on lockfd
+ * @args dbpath (r) path to lockfile, only used on first call,
+ * later the stored fd is used
+ * @returns LOCK_FREE/LOCK_UNLOCK return 0 on success, -1 on error
+ * LOCK_EXCL/LOCK_SHRD return LOCK_EXCL or LOCK_SHRD respectively on
+ * success, 0 if the lock couldn't be acquired, -1 on other errors
+ */
+ int get_lock(int cmd, const char *dbpath)
+ {
+ static int lockfd = -1;
+ int ret;
+ char lockpath[PATH_MAX];
+ struct stat st;
+
+ switch (cmd) {
+ case LOCK_FREE:
+ if (lockfd == -1)
+ return -1;
+ close(lockfd);
+ lockfd = -1;
+ return 0;
+
+ case LOCK_UNLOCK:
+ if (lockfd == -1)
+ return -1;
+ return unlock(lockfd, 0, SEEK_SET, 0);
+
+ case LOCK_EXCL:
+ case LOCK_SHRD:
+ if (lockfd == -1) {
+ if ( (strlen(dbpath) + strlen(LOCKFILENAME+1)) > (PATH_MAX - 1) ) {
+ LOG(log_error, logtype_cnid, ".AppleDB pathname too long");
+ return -1;
+ }
+ strncpy(lockpath, dbpath, PATH_MAX - 1);
+ strcat(lockpath, "/");
+ strcat(lockpath, LOCKFILENAME);
+
+ if ((lockfd = open(lockpath, O_RDWR | O_CREAT, 0644)) < 0) {
+ LOG(log_error, logtype_cnid, "Error opening lockfile: %s", strerror(errno));
+ return -1;
+ }
+
+ if ((stat(dbpath, &st)) != 0) {
+ LOG(log_error, logtype_cnid, "Error statting lockfile: %s", strerror(errno));
+ return -1;
+ }
+
+ if ((chown(lockpath, st.st_uid, st.st_gid)) != 0) {
+ LOG(log_error, logtype_cnid, "Error inheriting lockfile permissions: %s",
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ if (cmd == LOCK_EXCL)
+ ret = write_lock(lockfd, 0, SEEK_SET, 0);
+ else
+ ret = read_lock(lockfd, 0, SEEK_SET, 0);
+
+ if (ret != 0) {
+ if (cmd == LOCK_SHRD)
+ LOG(log_error, logtype_cnid, "Volume CNID db is locked, try again...");
+ return 0;
+ }
+
+ LOG(log_debug, logtype_cnid, "get_lock: got %s lock",
+ cmd == LOCK_EXCL ? "LOCK_EXCL" : "LOCK_SHRD");
+ return cmd;
+
+ default:
+ return -1;
+ } /* switch(cmd) */
+
+ /* deadc0de, never get here */
+ return -1;
+ }
+
/* --------------- */
DBD *dbif_init(const char *envhome, const char *filename)
{
#define DBIF_CNID 0
#define DBIF_IDX_DEVINO 1
#define DBIF_IDX_DIDNAME 2
+#define DBIF_IDX_NAME 3
+ /* get_lock cmd and return value */
+ #define LOCKFILENAME "lock"
+ #define LOCK_FREE 0
+ #define LOCK_UNLOCK 1
+ #define LOCK_EXCL 2
+ #define LOCK_SHRD 3
+
/* Structures */
typedef struct {
char *name;
logconfig = strdup(argv[4]);
setuplog(logconfig);
- switch_to_user(dir);
+ /* Load .volinfo file */
+ if (loadvolinfo(argv[1], &volinfo) == -1) {
+ LOG(log_error, logtype_cnid, "Cant load volinfo for \"%s\"", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+ /* Put "/.AppleDB" at end of volpath, get path from volinfo file */
+ char dbpath[MAXPATHLEN+1];
+ if ((strlen(volinfo.v_dbpath) + strlen("/.AppleDB")) > MAXPATHLEN ) {
+ LOG(log_error, logtype_cnid, "CNID db pathname too long: \"%s\"", volinfo.v_dbpath);
+ exit(EXIT_FAILURE);
+ }
+ strncpy(dbpath, volinfo.v_dbpath, MAXPATHLEN - strlen("/.AppleDB"));
+ strcat(dbpath, "/.AppleDB");
+
+ if (vol_load_charsets(&volinfo) == -1) {
+ LOG(log_error, logtype_cnid, "Error loading charsets!");
+ exit(EXIT_FAILURE);
+ }
+ LOG(log_debug, logtype_cnid, "db dir: \"%s\"", dbpath);
+
+ switch_to_user(dbpath);
- /* Before we do anything else, check if there is an instance of cnid_dbd
- running already and silently exit if yes. */
- if ((db_locked = get_lock(1)) == -1) {
+ /* Get db lock */
+ if ((db_locked = get_lock(LOCK_EXCL, dir)) == -1) {
+ LOG(log_error, logtype_cnid, "main: fatal db lock error");
exit(1);
}
+ if (db_locked != LOCK_EXCL) {
+ /* Couldn't get exclusive lock, try shared lock */
+ if ((db_locked = get_lock(LOCK_SHRD, NULL)) != LOCK_SHRD) {
+ LOG(log_error, logtype_cnid, "main: fatal db lock error");
+ exit(1);
+ }
+ }
- LOG(log_info, logtype_cnid, "Startup, DB dir %s", dir);
-
set_signal();
/* SIGINT and SIGTERM are always off, unless we are in pselect */
}
LOG(log_debug, logtype_cnid, "Finished opening BerkeleyDB databases");
- if (dbd_stamp(dbd) < 0) {
- dbif_close(dbd);
- exit(5);
- }
- LOG(log_maxdebug, logtype_cnid, "Finished checking database stamp");
-
+ /* Downgrade db lock */
+ if (db_locked == LOCK_EXCL) {
+ if (get_lock(LOCK_UNLOCK, NULL) != 0) {
+ dbif_close(dbd);
+ exit(2);
+ }
+ if (get_lock(LOCK_SHRD, NULL) != LOCK_SHRD) {
+ dbif_close(dbd);
+ exit(2);
+ }
+ }
+
+
if (comm_init(dbp, ctrlfd, clntfd) < 0) {
dbif_close(dbd);
exit(3);
if (dbif_close(dbd) < 0)
err++;
- if (dbif_prep_upgrade(dir) < 0)
+ if (dbif_env_remove(dbpath) < 0)
err++;
- (void)get_lock(0);
-
if (err)
exit(4);
else if (exit_sig)