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