]> arthur.barton.de Git - netatalk.git/blob - etc/cnid_dbd/cmd_dbd.c
Rewrite dbd to use CNID IPC instead of opening the db directly
[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"
96            "dbd scans or reindex Netatalk CNID databases of AFP volumes.\n"
97            "dbd must be run with appropiate permissions i.e. as root.\n"
98            "By default dbd rebuilds the CNID database of the volume.\n\n"
99            "Options:\n"
100            "   -s Scan volume:\n"
101            "   -c convert from adouble:v2 to adouble:ea (use with -r)\n"
102            "   -F location of the afp.conf config file\n"
103            "   -f delete and recreate CNID database\n"
104            "   -t show statistics while running\n"
105            "   -v verbose\n"
106            "   -V show version info\n\n"
107         );
108 }
109
110 /***************************************************************************
111  * Global functions
112  ***************************************************************************/
113
114 void dbd_log(enum logtype lt, char *fmt, ...)
115 {
116     int len;
117     static char logbuffer[1024];
118     va_list args;
119
120     if ( (lt == LOGSTD) || (flags & DBD_FLAGS_VERBOSE)) {
121         va_start(args, fmt);
122         len = vsnprintf(logbuffer, 1023, fmt, args);
123         va_end(args);
124         logbuffer[1023] = 0;
125
126         printf("%s\n", logbuffer);
127     }
128 }
129
130 int main(int argc, char **argv)
131 {
132     EC_INIT;
133     int dbd_cmd = dbd_rebuild;
134     int cdir = -1;
135     AFPObj obj = { 0 };
136     struct vol *vol = NULL;
137     const char *volpath = NULL;
138
139     int c;
140     while ((c = getopt(argc, argv, ":cfF:stvV")) != -1) {
141         switch(c) {
142         case 'c':
143             flags |= DBD_FLAGS_V2TOEA;
144             break;
145         case 'f':
146             flags |= DBD_FLAGS_FORCE;
147             break;
148         case 'F':
149             obj.cmdlineconfigfile = strdup(optarg);
150             break;
151         case 's':
152             dbd_cmd = dbd_scan;
153             flags |= DBD_FLAGS_SCAN;
154             break;
155         case 't':
156             flags |= DBD_FLAGS_STATS;
157             break;
158         case 'v':
159             flags |= DBD_FLAGS_VERBOSE;
160             break;
161         case 'V':
162             printf("dbd %s\n", VERSION);
163             exit(0);
164         case ':':
165         case '?':
166             usage();
167             exit(EXIT_FAILURE);
168             break;
169         }
170     }
171
172     if ( (optind + 1) != argc ) {
173         usage();
174         exit(EXIT_FAILURE);
175     }
176     volpath = argv[optind];
177
178     if (geteuid() != 0) {
179         usage();
180         exit(EXIT_FAILURE);
181     }
182     /* Inhereting perms in ad_mkdir etc requires this */
183     ad_setfuid(0);
184
185     setvbuf(stdout, (char *) NULL, _IONBF, 0);
186
187     /* Remember cwd */
188     if ((cdir = open(".", O_RDONLY)) < 0) {
189         dbd_log( LOGSTD, "Can't open dir: %s", strerror(errno));
190         exit(EXIT_FAILURE);
191     }
192         
193     /* Setup signal handling */
194     set_signal();
195
196     /* Load config */
197     if (afp_config_parse(&obj, "dbd") != 0) {
198         dbd_log( LOGSTD, "Couldn't load afp.conf");
199         exit(EXIT_FAILURE);
200     }
201
202     /* Initialize CNID subsystem */
203     cnid_init();
204
205     /* Setup logging. Should be portable among *NIXes */
206     if (flags & DBD_FLAGS_VERBOSE)
207         setuplog("default:note, cnid:debug", "/dev/tty");
208     else
209         setuplog("default:note", "/dev/tty");
210
211     if (load_volumes(&obj) != 0) {
212         dbd_log( LOGSTD, "Couldn't load volumes");
213         exit(EXIT_FAILURE);
214     }
215
216     if ((vol = getvolbypath(&obj, volpath)) == NULL) {
217         dbd_log( LOGSTD, "Couldn't find volume for '%s'", volpath);
218         exit(EXIT_FAILURE);
219     }
220
221     if (load_charset(vol) != 0) {
222         dbd_log( LOGSTD, "Couldn't load charsets for '%s'", volpath);
223         exit(EXIT_FAILURE);
224     }
225
226     /* open volume */
227     if (STRCMP(vol->v_cnidscheme, != , "dbd")) {
228         dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path);
229         exit(EXIT_FAILURE);
230     }
231     if ((vol->v_cdb = cnid_open(vol->v_path,
232                                 0000,
233                                 "dbd",
234                                 flags,
235                                 vol->v_cnidserver,
236                                 vol->v_cnidport)) == NULL) {
237         dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path);
238         exit(EXIT_FAILURE);
239     }
240
241     if (vol->v_adouble == AD_VERSION_EA)
242         dbd_log( LOGDEBUG, "adouble:ea volume");
243     else if (vol->v_adouble == AD_VERSION2)
244         dbd_log( LOGDEBUG, "adouble:v2 volume");
245     else {
246         dbd_log( LOGSTD, "unknown adouble volume");
247         exit(EXIT_FAILURE);
248     }
249
250     /* -C v2 to ea conversion only on adouble:ea volumes */
251     if ((flags & DBD_FLAGS_V2TOEA) && (vol->v_adouble!= AD_VERSION_EA)) {
252         dbd_log( LOGSTD, "Can't run adouble:v2 to adouble:ea conversion because not an adouble:ea volume");
253         exit(EXIT_FAILURE);
254     }
255
256     /* Sanity checks to ensure we can touch this volume */
257     if (vol->v_vfs_ea != AFPVOL_EA_AD && vol->v_vfs_ea != AFPVOL_EA_SYS) {
258         dbd_log( LOGSTD, "Unknown Extended Attributes option: %u", vol->v_vfs_ea);
259         exit(EXIT_FAILURE);        
260     }
261
262     if (flags & DBD_FLAGS_FORCE) {
263         if (cnid_wipe(vol->v_cdb) != 0) {
264             dbd_log( LOGSTD, "Failed to wipe CNID db");
265             EC_FAIL;
266         }
267     }
268
269     /* Now execute given command scan|rebuild|dump */
270     switch (dbd_cmd) {
271     case dbd_scan:
272     case dbd_rebuild:
273         if (cmd_dbd_scanvol(vol, flags) < 0) {
274             dbd_log( LOGSTD, "Error repairing database.");
275         }
276         break;
277     }
278
279 EC_CLEANUP:
280     if (vol)
281         cnid_close(vol->v_cdb);
282
283     if (cdir != -1 && (fchdir(cdir) < 0))
284         dbd_log(LOGSTD, "fchdir: %s", strerror(errno));
285
286     if (ret == 0)
287         exit(EXIT_SUCCESS);
288     else
289         exit(EXIT_FAILURE);
290 }