]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/stored.c
First cut SIGHUM + misc
[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  *   Version $Id$
10  * 
11  */
12 /*
13    Copyright (C) 2000-2004 Kern Sibbald and John Walker
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License as
17    published by the Free Software Foundation; either version 2 of
18    the License, or (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU General Public
26    License along with this program; if not, write to the Free
27    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28    MA 02111-1307, USA.
29
30  */
31
32 #include "bacula.h"
33 #include "stored.h"
34
35 /* Imported functions */
36
37
38 /* Forward referenced functions */
39 void terminate_stored(int sig);
40 static void check_config();
41
42 extern "C" void *device_allocation(void *arg);
43
44 #define CONFIG_FILE "bacula-sd.conf"  /* Default config file */
45
46
47 /* Global variables exported */
48 char OK_msg[]   = "3000 OK\n";
49 char TERM_msg[] = "3999 Terminate\n";
50 STORES *me = NULL;                    /* our Global resource */
51 bool forge_on = false;                /* proceed inspite of I/O errors */
52
53 static uint32_t VolSessionId = 0;
54 uint32_t VolSessionTime;
55 char *configfile;
56
57 /* Global static variables */
58 static int foreground = 0;
59 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
60 static workq_t dird_workq;            /* queue for processing connections */
61
62
63 static void usage()
64 {
65    fprintf(stderr, _(
66 "\nVersion: " VERSION " (" BDATE ")\n\n"
67 "Usage: stored [options] [-c config_file] [config_file]\n"
68 "        -c <file>   use <file> as configuration file\n"
69 "        -dnn        set debug level to nn\n"
70 "        -f          run in foreground (for debugging)\n"
71 "        -g <group>  set groupid to group\n"
72 "        -p          proceed despite I/O errors\n"
73 "        -s          no signals (for debugging)\n"
74 "        -t          test - read config and exit\n"
75 "        -u <user>   userid to <user>\n"
76 "        -v          verbose user messages\n"
77 "        -?          print this message.\n"
78 "\n"));
79    exit(1);
80 }
81
82 /********************************************************************* 
83  *
84  *  Main Bacula Unix Storage Daemon
85  *
86  */
87 int main (int argc, char *argv[])
88 {
89    int ch;   
90    int no_signals = FALSE;
91    int test_config = FALSE;
92    pthread_t thid;
93    char *uid = NULL;
94    char *gid = NULL;
95
96    init_stack_dump();
97    my_name_is(argc, argv, "bacula-sd");
98    textdomain("bacula");
99    init_msg(NULL, NULL);
100    daemon_start_time = time(NULL);
101
102    /* Sanity checks */
103    if (TAPE_BSIZE % DEV_BSIZE != 0 || TAPE_BSIZE / DEV_BSIZE == 0) {
104       Emsg2(M_ABORT, 0, "Tape block size (%d) not multiple of system size (%d)\n",
105          TAPE_BSIZE, DEV_BSIZE);
106    }
107    if (TAPE_BSIZE != (1 << (ffs(TAPE_BSIZE)-1))) {
108       Emsg1(M_ABORT, 0, "Tape block size (%d) is not a power of 2\n", TAPE_BSIZE);
109    }
110
111    while ((ch = getopt(argc, argv, "c:d:fg:pstu:v?")) != -1) {
112       switch (ch) {
113       case 'c':                    /* configuration file */
114          if (configfile != NULL) {
115             free(configfile);
116          }
117          configfile = bstrdup(optarg);
118          break;
119
120       case 'd':                    /* debug level */
121          debug_level = atoi(optarg);
122          if (debug_level <= 0) {
123             debug_level = 1; 
124          }
125          break;
126
127       case 'f':                    /* run in foreground */
128          foreground = TRUE;
129          break;
130
131       case 'g':                    /* set group id */
132          gid = optarg;
133          break;
134
135       case 'p':                    /* proceed in spite of I/O errors */
136          forge_on = true;
137          break;
138
139       case 's':                    /* no signals */
140          no_signals = TRUE;
141          break;
142
143       case 't':
144          test_config = TRUE;
145          break;
146
147       case 'u':                    /* set uid */
148          uid = optarg;
149          break;
150
151       case 'v':                    /* verbose */
152          verbose++;
153          break;
154
155       case '?':
156       default:
157          usage();
158          break;
159       }  
160    }
161    argc -= optind;
162    argv += optind;
163
164    if (argc) {
165       if (configfile != NULL) {
166          free(configfile);
167       }
168       configfile = bstrdup(*argv);
169       argc--; 
170       argv++;
171    }
172    if (argc)
173       usage();
174
175    if (!no_signals) {
176       init_signals(terminate_stored);
177    }
178
179
180    if (configfile == NULL) {
181       configfile = bstrdup(CONFIG_FILE);
182    }
183
184    parse_config(configfile);
185    check_config();
186
187    if (test_config) {
188       terminate_stored(0);
189    }
190
191    if (!foreground) {
192       daemon_start();                 /* become daemon */
193       init_stack_dump();              /* pick up new pid */
194    }
195
196    create_pid_file(me->pid_directory, "bacula-sd", me->SDport);
197    read_state_file(me->working_directory, "bacula-sd", me->SDport);
198
199    drop(uid, gid);
200
201    /* Ensure that Volume Session Time and Id are both
202     * set and are both non-zero.
203     */
204    VolSessionTime = (long)daemon_start_time;
205    if (VolSessionTime == 0) { /* paranoid */
206       Emsg0(M_ABORT, 0, _("Volume Session Time is ZERO!\n"));
207    }
208
209    /* Make sure on Solaris we can run concurrent, watch dog + servers + misc */
210    set_thread_concurrency(me->max_concurrent_jobs * 2 + 4);
211
212     /*
213      * Start the device allocation thread
214      */
215    if (pthread_create(&thid, NULL, device_allocation, NULL) != 0) {
216       Emsg1(M_ABORT, 0, _("Unable to create thread. ERR=%s\n"), strerror(errno));
217    }
218
219    start_watchdog();                  /* start watchdog thread */
220
221    init_jcr_subsystem();              /* start JCR watchdogs etc. */
222
223    /* 
224     * Sleep a bit to give device thread a chance to lock the resource
225     * chain before we start the server.
226     */
227    bmicrosleep(1, 0);
228                                  
229    /* Single server used for Director and File daemon */
230    bnet_thread_server(me->SDaddr, me->SDport, me->max_concurrent_jobs * 2 + 1,
231                       &dird_workq, handle_connection_request);
232    exit(1);                           /* to keep compiler quiet */
233 }
234
235 /* Return a new Session Id */
236 uint32_t newVolSessionId()
237 {
238    uint32_t Id;
239
240    P(mutex);
241    VolSessionId++;
242    Id = VolSessionId;
243    V(mutex);
244    return Id;
245 }
246
247 /* Check Configuration file for necessary info */
248 static void check_config()
249 {
250    LockRes();
251    me = (STORES *)GetNextRes(R_STORAGE, NULL);
252    if (!me) {
253       UnlockRes();
254       Emsg1(M_ERROR_TERM, 0, _("No Storage resource defined in %s. Cannot continue.\n"),
255          configfile);
256    }
257
258    my_name_is(0, (char **)NULL, me->hdr.name);     /* Set our real name */
259
260    if (GetNextRes(R_STORAGE, (RES *)me) != NULL) {
261       UnlockRes();
262       Emsg1(M_ERROR_TERM, 0, _("Only one Storage resource permitted in %s\n"), 
263          configfile);
264    }
265    if (GetNextRes(R_DIRECTOR, NULL) == NULL) {
266       UnlockRes();
267       Emsg1(M_ERROR_TERM, 0, _("No Director resource defined in %s. Cannot continue.\n"),
268          configfile);
269    }
270    if (GetNextRes(R_DEVICE, NULL) == NULL){
271       UnlockRes();
272       Emsg1(M_ERROR_TERM, 0, _("No Device resource defined in %s. Cannot continue.\n"),
273            configfile);
274    }
275    if (!me->messages) {
276       me->messages = (MSGS *)GetNextRes(R_MSGS, NULL);
277       if (!me->messages) {
278          Emsg1(M_ERROR_TERM, 0, _("No Messages resource defined in %s. Cannot continue.\n"),
279             configfile);
280       }
281    }
282    close_msg(NULL);                   /* close temp message handler */
283    init_msg(NULL, me->messages);      /* open daemon message handler */
284
285    UnlockRes();
286
287    if (!me->working_directory) {
288       Emsg1(M_ERROR_TERM, 0, _("No Working Directory defined in %s. Cannot continue.\n"),
289          configfile);
290    }
291    
292    set_working_directory(me->working_directory);
293 }
294
295 /*
296  * We are started as a separate thread.  The
297  *  resources are alread locked.
298  */
299 extern "C"
300 void *device_allocation(void *arg)
301 {
302    DEVRES *device;
303
304    LockRes();
305    pthread_detach(pthread_self());
306
307    foreach_res(device, R_DEVICE) {
308       Dmsg1(90, "calling init_dev %s\n", device->device_name);
309       device->dev = init_dev(NULL, device);
310       Dmsg1(10, "SD init done %s\n", device->device_name);
311       if (!device->dev) {
312          Emsg1(M_ERROR, 0, _("Could not initialize %s\n"), device->device_name);
313          continue;
314       }
315
316       if (device->cap_bits & CAP_ALWAYSOPEN) {
317          Dmsg1(20, "calling first_open_device %s\n", device->device_name);
318          if (!first_open_device(device->dev)) {
319             Emsg1(M_ERROR, 0, _("Could not open device %s\n"), device->device_name);
320          }
321       }
322       if (device->cap_bits & CAP_AUTOMOUNT && device->dev && 
323           device->dev->state & ST_OPENED) {
324          JCR *jcr;
325          DCR *dcr;
326          jcr = new_jcr(sizeof(JCR), stored_free_jcr);
327          jcr->JobType = JT_SYSTEM;
328          /* Initialize FD start condition variable */
329          int errstat = pthread_cond_init(&jcr->job_start_wait, NULL);
330          if (errstat != 0) {
331             Jmsg1(jcr, M_ABORT, 0, _("Unable to init job cond variable: ERR=%s\n"), strerror(errstat));
332          }
333          jcr->device = device;
334          dcr = new_dcr(jcr, device->dev);
335          switch (read_dev_volume_label(jcr, device->dev, dcr->block)) {
336             case VOL_OK:
337                break;
338             default:
339                Emsg1(M_WARNING, 0, _("Could not mount device %s\n"), device->device_name);
340                break;
341          }
342          free_jcr(jcr);
343       }
344    } 
345    UnlockRes();
346    return NULL;
347 }
348
349
350 /* Clean up and then exit */
351 void terminate_stored(int sig)
352 {
353    static int in_here = FALSE;
354    DEVRES *device;
355    JCR *jcr;
356
357    if (in_here) {                     /* prevent loops */
358       exit(1);
359    }
360    in_here = TRUE;
361
362    if (sig == SIGTERM) {              /* normal shutdown request? */
363       /*
364        * This is a normal shutdown request. We wiffle through
365        *   all open jobs canceling them and trying to wake
366        *   them up so that they will report back the correct
367        *   volume status.
368        */
369       lock_jcr_chain();
370       foreach_jcr(jcr) {
371          BSOCK *fd;
372          free_locked_jcr(jcr);
373          if (jcr->JobId == 0) {
374             continue;                 /* ignore console */
375          }
376          set_jcr_job_status(jcr, JS_Canceled);
377          fd = jcr->file_bsock;  
378          if (fd) {
379             fd->timed_out = TRUE;
380             Dmsg1(100, "killing JobId=%d\n", jcr->JobId);
381             pthread_kill(jcr->my_thread_id, TIMEOUT_SIGNAL);
382             if (jcr->device && jcr->device->dev && jcr->device->dev->dev_blocked) {
383                pthread_cond_signal(&jcr->device->dev->wait_next_vol);
384             }
385             bmicrosleep(0, 50000);
386           }
387       }
388       unlock_jcr_chain();
389       bmicrosleep(0, 500000);         /* give them 1/2 sec to clean up */
390    }
391
392    write_state_file(me->working_directory, "bacula-sd", me->SDport);
393    delete_pid_file(me->pid_directory, "bacula-sd", me->SDport);
394
395    Dmsg1(200, "In terminate_stored() sig=%d\n", sig);
396
397    LockRes();
398    foreach_res(device, R_DEVICE) {
399       if (device->dev) {
400          term_dev(device->dev);
401       }
402    } 
403    UnlockRes();
404
405    if (configfile)
406    free(configfile);
407    free_config_resources();
408
409    if (debug_level > 10) {
410       print_memory_pool_stats();
411    }
412    term_msg();
413    stop_watchdog();
414    close_memory_pool();
415
416    sm_dump(false);                    /* dump orphaned buffers */
417    exit(sig);
418 }