2 Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
17 #endif /* HAVE_CONFIG_H */
20 #include <sys/types.h>
30 #include <atalk/logger.h>
31 #include <atalk/globals.h>
32 #include <atalk/netatalk_conf.h>
33 #include <atalk/util.h>
34 #include <atalk/errchk.h>
38 enum dbd_cmd {dbd_scan, dbd_rebuild};
40 /* Global variables */
41 volatile sig_atomic_t alarmed; /* flags for signals */
44 static dbd_flags_t flags;
46 /***************************************************************************
48 ***************************************************************************/
52 * catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
54 static void sig_handler(int signo)
60 static void set_signal(void)
64 sv.sa_handler = sig_handler;
65 sv.sa_flags = SA_RESTART;
66 sigemptyset(&sv.sa_mask);
67 if (sigaction(SIGTERM, &sv, NULL) < 0) {
68 dbd_log( LOGSTD, "error in sigaction(SIGTERM): %s", strerror(errno));
71 if (sigaction(SIGINT, &sv, NULL) < 0) {
72 dbd_log( LOGSTD, "error in sigaction(SIGINT): %s", strerror(errno));
76 memset(&sv, 0, sizeof(struct sigaction));
77 sv.sa_handler = SIG_IGN;
78 sigemptyset(&sv.sa_mask);
80 if (sigaction(SIGABRT, &sv, NULL) < 0) {
81 dbd_log( LOGSTD, "error in sigaction(SIGABRT): %s", strerror(errno));
84 if (sigaction(SIGHUP, &sv, NULL) < 0) {
85 dbd_log( LOGSTD, "error in sigaction(SIGHUP): %s", strerror(errno));
88 if (sigaction(SIGQUIT, &sv, NULL) < 0) {
89 dbd_log( LOGSTD, "error in sigaction(SIGQUIT): %s", strerror(errno));
94 static void usage (void)
96 printf("Usage: dbd [-cfFstuvV] <path to netatalk volume>\n\n"
97 "dbd scans all file and directories of AFP volumes, updating the\n"
98 "CNID database of the volume. dbd must be run with appropiate\n"
99 "permissions i.e. as root.\n\n"
101 " -s scan volume: treat the volume as read only and don't\n"
102 " perform any filesystem modifications\n"
103 " -c convert from adouble:v2 to adouble:ea\n"
104 " -F location of the afp.conf config file\n"
105 " -f delete and recreate CNID database\n"
106 " -t show statistics while running\n"
107 " -u username for use with AFP volumes using user variable $u\n"
109 " -V show version info\n\n"
113 /***************************************************************************
115 ***************************************************************************/
117 void dbd_log(enum logtype lt, char *fmt, ...)
120 static char logbuffer[1024];
123 if ( (lt == LOGSTD) || (flags & DBD_FLAGS_VERBOSE)) {
125 len = vsnprintf(logbuffer, 1023, fmt, args);
129 printf("%s\n", logbuffer);
133 int main(int argc, char **argv)
136 int dbd_cmd = dbd_rebuild;
139 struct vol *vol = NULL;
140 const char *volpath = NULL;
141 char *username = NULL;
143 while ((c = getopt(argc, argv, ":cfF:rstu:vV")) != -1) {
146 flags |= DBD_FLAGS_V2TOEA;
149 flags |= DBD_FLAGS_FORCE;
152 obj.cmdlineconfigfile = strdup(optarg);
159 flags |= DBD_FLAGS_SCAN;
162 flags |= DBD_FLAGS_STATS;
165 username = strdup(optarg);
168 flags |= DBD_FLAGS_VERBOSE;
171 printf("dbd %s\n", VERSION);
181 if ( (optind + 1) != argc ) {
185 volpath = argv[optind];
187 if (geteuid() != 0) {
191 /* Inhereting perms in ad_mkdir etc requires this */
194 setvbuf(stdout, (char *) NULL, _IONBF, 0);
197 if ((cdir = open(".", O_RDONLY)) < 0) {
198 dbd_log( LOGSTD, "Can't open dir: %s", strerror(errno));
202 /* Setup signal handling */
206 if (afp_config_parse(&obj, "dbd") != 0) {
207 dbd_log( LOGSTD, "Couldn't load afp.conf");
212 /* Initialize CNID subsystem */
215 /* Setup logging. Should be portable among *NIXes */
216 if (flags & DBD_FLAGS_VERBOSE)
217 setuplog("default:note, cnid:debug", "/dev/tty");
219 setuplog("default:note", "/dev/tty");
223 strncpy(obj.username, username, MAXUSERLEN);
225 pwd = getpwnam(obj.username);
227 dbd_log( LOGSTD, "unknown user");
230 obj.uid = pwd->pw_uid;
233 if (load_volumes(&obj, lv_all) != 0) {
234 dbd_log( LOGSTD, "Couldn't load volumes");
238 if ((vol = getvolbypath(&obj, volpath)) == NULL) {
239 dbd_log( LOGSTD, "Couldn't find volume for '%s'", volpath);
243 if (load_charset(vol) != 0) {
244 dbd_log( LOGSTD, "Couldn't load charsets for '%s'", volpath);
249 if (STRCMP(vol->v_cnidscheme, != , "dbd") && STRCMP(vol->v_cnidscheme, != , "mysql")) {
250 dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path);
253 vol->v_cdb = cnid_open(vol, vol->v_cnidscheme,
254 vol->v_flags & AFPVOL_NODEV ? CNID_FLAG_NODEV : 0);
255 if (vol->v_cdb == NULL) {
256 dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path);
260 if (vol->v_adouble == AD_VERSION_EA)
261 dbd_log( LOGDEBUG, "adouble:ea volume");
262 else if (vol->v_adouble == AD_VERSION2)
263 dbd_log( LOGDEBUG, "adouble:v2 volume");
265 dbd_log( LOGSTD, "unknown adouble volume");
269 /* -C v2 to ea conversion only on adouble:ea volumes */
270 if ((flags & DBD_FLAGS_V2TOEA) && (vol->v_adouble!= AD_VERSION_EA)) {
271 dbd_log( LOGSTD, "Can't run adouble:v2 to adouble:ea conversion because not an adouble:ea volume");
275 /* Sanity checks to ensure we can touch this volume */
276 if (vol->v_vfs_ea != AFPVOL_EA_AD && vol->v_vfs_ea != AFPVOL_EA_SYS) {
277 dbd_log( LOGSTD, "Unknown Extended Attributes option: %u", vol->v_vfs_ea);
281 if (flags & DBD_FLAGS_FORCE) {
282 if (cnid_wipe(vol->v_cdb) != 0) {
283 dbd_log( LOGSTD, "Failed to wipe CNID db");
288 /* Now execute given command scan|rebuild|dump */
292 if (cmd_dbd_scanvol(vol, flags) < 0) {
293 dbd_log( LOGSTD, "Error repairing database.");
300 cnid_close(vol->v_cdb);
302 if (cdir != -1 && (fchdir(cdir) < 0))
303 dbd_log(LOGSTD, "fchdir: %s", strerror(errno));