]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored.c
eabbd18efd1f88985cd84ecb33172cf84444e794
[bacula/bacula] / bacula / src / stored / stored.c
1 /*
2  * Second generation Storage daemon.
3  *
4  * It accepts a number of simple commands from the File daemon
5  * and acts on them. When a request to append data is made,
6  * it opens a data channel and accepts data from the
7  * File daemon. 
8  * 
9  */
10 /*
11    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12
13    This program is free software; you can redistribute it and/or
14    modify it under the terms of the GNU General Public License as
15    published by the Free Software Foundation; either version 2 of
16    the License, or (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21    General Public License for more details.
22
23    You should have received a copy of the GNU General Public
24    License along with this program; if not, write to the Free
25    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "stored.h"
32
33 /* Imported functions */
34
35
36 /* Forward referenced functions */
37 void terminate_stored(int sig);
38 static void check_config();
39 static void *director_thread(void *arg);
40
41 #define CONFIG_FILE "bacula-sd.conf"  /* Default config file */
42
43
44 /* Global variables exported */
45
46
47 struct s_shm *shm;                    /* memory shared with children */
48 BSHM bshm;                            /* shared memory control packet */
49
50
51 /* This is our own global resource */
52 static STORES *me;
53
54 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
55 static uint32_t VolSessionId = 0;
56 uint32_t VolSessionTime;
57
58 static char *configfile;
59 static int foreground = 0;
60
61 static workq_t dird_workq;            /* queue for processing connections */
62 static workq_t filed_workq;           /* queue for processing connections */
63
64
65 static void usage()
66 {
67    fprintf(stderr, _(
68 "\nVersion: " VERSION " (" DATE ")\n\n"
69 "Usage: stored [-s -f ] [-c config_file] [-d debug_level]  [config_file]\n"
70 "        -c <file>   use <file> as configuration file\n"
71 "        -dnn        set debug level to nn\n"
72 "        -f          run in foreground (for debugging)\n"
73 "        -s          no signals (for debugging)\n"
74 "        -t          test - read config and exit\n"
75 "        -?          print this message.\n"
76 "\n"));
77    exit(1);
78 }
79
80 /********************************************************************* 
81  *
82  *  Main Bacula Unix Storage Daemon
83  *
84  */
85 int main (int argc, char *argv[])
86 {
87    int ch, i;
88    int no_signals = FALSE;
89    int test_config = FALSE;
90    DEVRES *device;
91    pthread_t dirid;
92    int status;
93
94    init_stack_dump();
95    my_name_is(argc, argv, "stored");
96    daemon_start_time = time(NULL);
97    memset(&last_job, 0, sizeof(last_job));
98
99    /* Sanity checks */
100    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
101       Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
102          TAPE_BSIZE, DEV_BSIZE);
103    }
104    if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
105       Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
106    }
107
108    while ((ch = getopt(argc, argv, "c:d:fst?")) != -1) {
109       switch (ch) {
110          case 'c':                    /* configuration file */
111             if (configfile != NULL) {
112                free(configfile);
113             }
114             configfile = bstrdup(optarg);
115             break;
116
117          case 'd':                    /* debug level */
118             debug_level = atoi(optarg);
119             if (debug_level <= 0) {
120                debug_level = 1; 
121             }
122             break;
123
124          case 'f':                    /* run in foreground */
125             foreground = TRUE;
126             break;
127
128          case 's':                    /* no signals */
129             no_signals = TRUE;
130             break;
131
132          case 't':
133             test_config = TRUE;
134             break;
135
136          case '?':
137          default:
138             usage();
139
140       }  
141    }
142    argc -= optind;
143    argv += optind;
144
145    if (argc) {
146       if (configfile != NULL) {
147          free(configfile);
148       }
149       configfile = bstrdup(*argv);
150       argc--; 
151       argv++;
152    }
153    if (argc)
154       usage();
155
156    if (!no_signals) {
157       init_signals(terminate_stored);
158    }
159
160
161    if (configfile == NULL) {
162       configfile = bstrdup(CONFIG_FILE);
163    }
164
165    init_msg(NULL);
166    parse_config(configfile);
167    check_config();
168
169    bshm.size = 0;
170    if (test_config) {
171       terminate_stored(0);
172    }
173
174    if (!foreground) {
175       daemon_start();                 /* become daemon */
176       init_stack_dump();              /* pick up new pid */
177    }
178
179    /*  ****FIXME**** clean this up */
180    /* Create and attach to shared memory. This is a
181     * hold over from the days of child processes. 
182     * Note, in reality all memory is shared. This
183     * is just a global buffer for the device packets.
184     */
185    shm = (s_shm *) malloc(sizeof(struct s_shm));
186    /* Zero shared memory */
187    memset(shm, 0, sizeof(struct s_shm));
188
189    /* Ensure that Volume Session Time and Id are both
190     * set and are both non-zero.
191     */
192    VolSessionTime = (long)daemon_start_time;
193    if (VolSessionTime == 0) { /* paranoid */
194       Emsg0(M_ABORT, 0, _("Volume Session Time is ZERO!\n"));
195    }
196
197    LockRes();
198    for (device=NULL,i=0;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); i++) {
199       if (i >= MAX_DEVICES) {
200          UnlockRes();
201          Emsg1(M_ABORT, 0, _("Too many Device Resources. Max=%d\n"), MAX_DEVICES);
202       }
203       Dmsg1(90, "calling init_dev %s\n", device->device_name);
204       device->dev = init_dev(&shm->dev[i], device->device_name);
205       /* Copy some attributes from the Device Resource to the DEV structure */
206       if (device->dev) {
207          device->dev->capabilities = device->cap_bits;
208          device->dev->min_block_size = device->min_block_size;
209          device->dev->max_block_size = device->max_block_size;
210          device->dev->max_volume_jobs = device->max_volume_jobs;
211          device->dev->max_volume_files = device->max_volume_files;
212          device->dev->max_volume_size = device->max_volume_size;
213          device->dev->max_file_size = device->max_file_size;
214          device->dev->volume_capacity = device->volume_capacity;
215          device->dev->max_rewind_wait = device->max_rewind_wait;
216          device->dev->device = device;
217       }
218       Dmsg1(10, "Init done %s\n", device->device_name);
219       if (!device->dev) {
220          Emsg1(M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
221       }
222       if (device->cap_bits & CAP_ALWAYSOPEN) {
223          Dmsg1(20, "calling open_device %s\n", device->device_name);
224          if (!open_device(device->dev)) {
225             Emsg1(M_ERROR, 0, _("Could not open device %s\n"), device->device_name);
226          }
227       }
228       if (device->cap_bits & CAP_AUTOMOUNT && device->dev && 
229           device->dev->state & ST_OPENED) {
230          DEV_BLOCK *block;
231          JCR *jcr;
232          block = new_block(device->dev);
233          jcr = new_jcr(sizeof(JCR), stored_free_jcr);
234          switch (read_dev_volume_label(jcr, device->dev, block)) {
235             case VOL_OK:
236                break;
237             default:
238                Emsg1(M_WARNING, 0, _("Could not mount device %s\n"), device->device_name);
239                break;
240          }
241          free_jcr(jcr);
242          free_block(block);
243       }
244    } 
245    UnlockRes();
246    device = NULL;
247
248    init_watchdog();                   /* start watchdog thread */
249
250    /*
251     * Here we support either listening on one port or on two ports
252     */
253    if (me->SDDport == 0 || me->SDDport == me->SDport) {
254       /* Single server used for Director and File daemon */
255       bnet_thread_server(me->SDport, 20, &dird_workq, connection_request);
256    } else {
257       /* Start the Director server */
258       set_thread_concurrency(10);
259       if ((status=pthread_create(&dirid, NULL, director_thread,         
260            (void *)me->SDport)) != 0) {
261          Emsg1(M_ABORT, 0, _("Cannot create Director thread: %s\n"), strerror(status));
262       }
263       /* Start File daemon server */
264       bnet_thread_server(me->SDDport, 10, &filed_workq, connection_from_filed);
265       /* never returns */
266    }
267
268    exit(1);                           /* to keep compiler quiet */
269 }
270
271 static void *director_thread(void *arg)
272 {
273    int dir_port = (int)arg;
274    pthread_detach(pthread_self());
275    bnet_thread_server(dir_port, 10, &dird_workq, connection_request);
276    return NULL;
277 }
278
279 /* Return a new Session Id */
280 uint32_t newVolSessionId()
281 {
282    uint32_t Id;
283
284    P(mutex);
285    VolSessionId++;
286    Id = VolSessionId;
287    V(mutex);
288    return Id;
289 }
290
291 /* Check Configuration file for necessary info */
292 static void check_config()
293 {
294    struct stat stat_buf; 
295
296    LockRes();
297    me = (STORES *)GetNextRes(R_STORAGE, NULL);
298    if (!me) {
299       UnlockRes();
300       Emsg1(M_ABORT, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
301          configfile);
302    }
303
304    my_name_is(0, (char **)NULL, me->hdr.name);     /* Set our real name */
305
306    if (GetNextRes(R_STORAGE, (RES *)me) != NULL) {
307       UnlockRes();
308       Emsg1(M_ABORT, 0, _("Only one Storage resource permitted in %s\n"), 
309          configfile);
310    }
311    if (GetNextRes(R_DIRECTOR, NULL) == NULL) {
312       UnlockRes();
313       Emsg1(M_ABORT, 0, _("No Director resource defined in %s. Cannot continue.\n"),
314          configfile);
315    }
316    if (GetNextRes(R_DEVICE, NULL) == NULL){
317       UnlockRes();
318       Emsg1(M_ABORT, 0, _("No Device resource defined in %s. Cannot continue.\n"),
319            configfile);
320    }
321
322    UnlockRes();
323
324    if (!me->working_directory) {
325       Emsg1(M_ABORT, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
326          configfile);
327    }
328    if (stat(me->working_directory, &stat_buf) != 0) {
329       Emsg1(M_ABORT, 0, _("Working Directory: %s not found. Cannot continue.\n"),
330          me->working_directory);
331    }
332    if (!S_ISDIR(stat_buf.st_mode)) {
333       Emsg1(M_ABORT, 0, _("Working Directory: %s is not a directory. Cannot continue.\n"),
334          me->working_directory);
335    }
336    working_directory = me->working_directory;
337 }
338
339 /* Clean up and then exit */
340 void terminate_stored(int sig)
341 {
342    static int in_here = FALSE;
343    DEVRES *device;
344
345    if (in_here) {                     /* prevent loops */
346       exit(1);
347    }
348    in_here = TRUE;
349
350    term_watchdog();
351
352    Dmsg0(200, "In terminate_stored()\n");
353
354    LockRes();
355    for (device=NULL; (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
356       if (device->dev) {
357          term_dev(device->dev);
358       }
359    } 
360    UnlockRes();
361
362    if (configfile)
363    free(configfile);
364    free_config_resources();
365
366    if (debug_level > 10)
367       print_memory_pool_stats();
368    close_memory_pool();
369
370    if (shm)
371    free(shm);
372    term_msg();
373
374    sm_dump(False);                    /* dump orphaned buffers */
375    exit(1);
376 }