]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/cmd_dbd.c
266b986ba00da9905c56777b4ac5dff6f50b4625
[netatalk.git] / etc / cnid_dbd / cmd_dbd.c
1 /* 
2    Copyright (c) 2009 Frank Lahm <franklahm@gmail.com>
3    
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.
8  
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.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <stdarg.h>
24 #include <limits.h>
25 #include <signal.h>
26 #include <string.h>
27 #include <errno.h>
28
29 #include <atalk/logger.h>
30 #include <atalk/globals.h>
31 #include <atalk/netatalk_conf.h>
32 #include <atalk/util.h>
33 #include <atalk/errchk.h>
34
35 #include "cmd_dbd.h"
36
37 enum dbd_cmd {dbd_scan, dbd_rebuild};
38
39 /* Global variables */
40 volatile sig_atomic_t alarmed;  /* flags for signals */
41
42 /* Local variables */
43 static dbd_flags_t flags;
44
45 /***************************************************************************
46  * Local functions
47  ***************************************************************************/
48
49 /*
50  * SIGNAL handling:
51  * catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
52  */
53 static void sig_handler(int signo)
54 {
55     alarmed = 1;
56     return;
57 }
58
59 static void set_signal(void)
60 {
61     struct sigaction sv;
62
63     sv.sa_handler = sig_handler;
64     sv.sa_flags = SA_RESTART;
65     sigemptyset(&sv.sa_mask);
66     if (sigaction(SIGTERM, &sv, NULL) < 0) {
67         dbd_log( LOGSTD, "error in sigaction(SIGTERM): %s", strerror(errno));
68         exit(EXIT_FAILURE);
69     }        
70     if (sigaction(SIGINT, &sv, NULL) < 0) {
71         dbd_log( LOGSTD, "error in sigaction(SIGINT): %s", strerror(errno));
72         exit(EXIT_FAILURE);
73     }        
74
75     memset(&sv, 0, sizeof(struct sigaction));
76     sv.sa_handler = SIG_IGN;
77     sigemptyset(&sv.sa_mask);
78
79     if (sigaction(SIGABRT, &sv, NULL) < 0) {
80         dbd_log( LOGSTD, "error in sigaction(SIGABRT): %s", strerror(errno));
81         exit(EXIT_FAILURE);
82     }        
83     if (sigaction(SIGHUP, &sv, NULL) < 0) {
84         dbd_log( LOGSTD, "error in sigaction(SIGHUP): %s", strerror(errno));
85         exit(EXIT_FAILURE);
86     }        
87     if (sigaction(SIGQUIT, &sv, NULL) < 0) {
88         dbd_log( LOGSTD, "error in sigaction(SIGQUIT): %s", strerror(errno));
89         exit(EXIT_FAILURE);
90     }        
91 }
92
93 static void usage (void)
94 {
95     printf("Usage: dbd [-cfFstvV] <path to netatalk volume>\n\n"
96            "dbd scans all file and directories of AFP volumes, updating the\n"
97            "CNID database of the volume. dbd must be run with appropiate\n"
98            "permissions i.e. as root.\n\n"
99            "Options:\n"
100            "   -s scan volume: treat the volume as read only and don't\n"
101            "      perform any filesystem modifications\n"
102            "   -c convert from adouble:v2 to adouble:ea\n"
103            "   -F location of the afp.conf config file\n"
104            "   -f delete and recreate CNID database\n"
105            "   -t show statistics while running\n"
106            "   -v verbose\n"
107            "   -V show version info\n\n"
108         );
109 }
110
111 /***************************************************************************
112  * Global functions
113  ***************************************************************************/
114
115 void dbd_log(enum logtype lt, char *fmt, ...)
116 {
117     int len;
118     static char logbuffer[1024];
119     va_list args;
120
121     if ( (lt == LOGSTD) || (flags & DBD_FLAGS_VERBOSE)) {
122         va_start(args, fmt);
123         len = vsnprintf(logbuffer, 1023, fmt, args);
124         va_end(args);
125         logbuffer[1023] = 0;
126
127         printf("%s\n", logbuffer);
128     }
129 }
130
131 int main(int argc, char **argv)
132 {
133     EC_INIT;
134     int dbd_cmd = dbd_rebuild;
135     int cdir = -1;
136     AFPObj obj = { 0 };
137     struct vol *vol = NULL;
138     const char *volpath = NULL;
139
140     int c;
141     while ((c = getopt(argc, argv, ":cfF:rstvV")) != -1) {
142         switch(c) {
143         case 'c':
144             flags |= DBD_FLAGS_V2TOEA;
145             break;
146         case 'f':
147             flags |= DBD_FLAGS_FORCE;
148             break;
149         case 'F':
150             obj.cmdlineconfigfile = strdup(optarg);
151             break;
152         case 'r':
153             /* the default */
154             break;
155         case 's':
156             dbd_cmd = dbd_scan;
157             flags |= DBD_FLAGS_SCAN;
158             break;
159         case 't':
160             flags |= DBD_FLAGS_STATS;
161             break;
162         case 'v':
163             flags |= DBD_FLAGS_VERBOSE;
164             break;
165         case 'V':
166             printf("dbd %s\n", VERSION);
167             exit(0);
168         case ':':
169         case '?':
170             usage();
171             exit(EXIT_FAILURE);
172             break;
173         }
174     }
175
176     if ( (optind + 1) != argc ) {
177         usage();
178         exit(EXIT_FAILURE);
179     }
180     volpath = argv[optind];
181
182     if (geteuid() != 0) {
183         usage();
184         exit(EXIT_FAILURE);
185     }
186     /* Inhereting perms in ad_mkdir etc requires this */
187     ad_setfuid(0);
188
189     setvbuf(stdout, (char *) NULL, _IONBF, 0);
190
191     /* Remember cwd */
192     if ((cdir = open(".", O_RDONLY)) < 0) {
193         dbd_log( LOGSTD, "Can't open dir: %s", strerror(errno));
194         exit(EXIT_FAILURE);
195     }
196         
197     /* Setup signal handling */
198     set_signal();
199
200     /* Load config */
201     if (afp_config_parse(&obj, "dbd") != 0) {
202         dbd_log( LOGSTD, "Couldn't load afp.conf");
203         exit(EXIT_FAILURE);
204     }
205
206     /* Initialize CNID subsystem */
207     cnid_init();
208
209     /* Setup logging. Should be portable among *NIXes */
210     if (flags & DBD_FLAGS_VERBOSE)
211         setuplog("default:note, cnid:debug", "/dev/tty");
212     else
213         setuplog("default:note", "/dev/tty");
214
215     if (load_volumes(&obj, lv_all) != 0) {
216         dbd_log( LOGSTD, "Couldn't load volumes");
217         exit(EXIT_FAILURE);
218     }
219
220     if ((vol = getvolbypath(&obj, volpath)) == NULL) {
221         dbd_log( LOGSTD, "Couldn't find volume for '%s'", volpath);
222         exit(EXIT_FAILURE);
223     }
224
225     if (load_charset(vol) != 0) {
226         dbd_log( LOGSTD, "Couldn't load charsets for '%s'", volpath);
227         exit(EXIT_FAILURE);
228     }
229
230     /* open volume */
231     if (STRCMP(vol->v_cnidscheme, != , "dbd") && STRCMP(vol->v_cnidscheme, != , "mysql")) {
232         dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path);
233         exit(EXIT_FAILURE);
234     }
235     if ((vol->v_cdb = cnid_open(vol->v_path,
236                                 0000,
237                                 vol->v_cnidscheme,
238                                 vol->v_flags & AFPVOL_NODEV ? CNID_FLAG_NODEV : 0,
239                                 vol->v_cnidserver,
240                                 vol->v_cnidport,
241                                 &obj,
242                                 vol->v_uuid)) == NULL) {
243         dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path);
244         exit(EXIT_FAILURE);
245     }
246
247     if (vol->v_adouble == AD_VERSION_EA)
248         dbd_log( LOGDEBUG, "adouble:ea volume");
249     else if (vol->v_adouble == AD_VERSION2)
250         dbd_log( LOGDEBUG, "adouble:v2 volume");
251     else {
252         dbd_log( LOGSTD, "unknown adouble volume");
253         exit(EXIT_FAILURE);
254     }
255
256     /* -C v2 to ea conversion only on adouble:ea volumes */
257     if ((flags & DBD_FLAGS_V2TOEA) && (vol->v_adouble!= AD_VERSION_EA)) {
258         dbd_log( LOGSTD, "Can't run adouble:v2 to adouble:ea conversion because not an adouble:ea volume");
259         exit(EXIT_FAILURE);
260     }
261
262     /* Sanity checks to ensure we can touch this volume */
263     if (vol->v_vfs_ea != AFPVOL_EA_AD && vol->v_vfs_ea != AFPVOL_EA_SYS) {
264         dbd_log( LOGSTD, "Unknown Extended Attributes option: %u", vol->v_vfs_ea);
265         exit(EXIT_FAILURE);        
266     }
267
268     if (flags & DBD_FLAGS_FORCE) {
269         if (cnid_wipe(vol->v_cdb) != 0) {
270             dbd_log( LOGSTD, "Failed to wipe CNID db");
271             EC_FAIL;
272         }
273     }
274
275     /* Now execute given command scan|rebuild|dump */
276     switch (dbd_cmd) {
277     case dbd_scan:
278     case dbd_rebuild:
279         if (cmd_dbd_scanvol(vol, flags) < 0) {
280             dbd_log( LOGSTD, "Error repairing database.");
281         }
282         break;
283     }
284
285 EC_CLEANUP:
286     if (vol)
287         cnid_close(vol->v_cdb);
288
289     if (cdir != -1 && (fchdir(cdir) < 0))
290         dbd_log(LOGSTD, "fchdir: %s", strerror(errno));
291
292     if (ret == 0)
293         exit(EXIT_SUCCESS);
294     else
295         exit(EXIT_FAILURE);
296 }