]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dircmd.c
482f7f78033be08696f828ceaa7f45c76d3a27c0
[bacula/bacula] / bacula / src / stored / dircmd.c
1 /*
2  *  This file handles accepting Director Commands
3  *
4  *    Most Director commands are handled here, with the 
5  *    exception of the Job command command and subsequent 
6  *    subcommands that are handled
7  *    in job.c.  
8  *
9  *    File daemon commands are handled in fdcmd.c
10  *
11  *     Kern Sibbald, May MMI
12  *
13  *   Version $Id$
14  *  
15  */
16 /*
17    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
18
19    This program is free software; you can redistribute it and/or
20    modify it under the terms of the GNU General Public License as
21    published by the Free Software Foundation; either version 2 of
22    the License, or (at your option) any later version.
23
24    This program is distributed in the hope that it will be useful,
25    but WITHOUT ANY WARRANTY; without even the implied warranty of
26    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27    General Public License for more details.
28
29    You should have received a copy of the GNU General Public
30    License along with this program; if not, write to the Free
31    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32    MA 02111-1307, USA.
33
34  */
35
36 #include "bacula.h"
37 #include "stored.h"
38
39 /* Exported variables */
40
41 /* Imported variables */
42 extern BSOCK *filed_chan;
43 extern int r_first, r_last;
44 extern struct s_res resources[];
45 extern char my_name[];
46 extern time_t daemon_start_time;
47 extern struct s_last_job last_job;
48
49 /* Static variables */
50 static char derrmsg[]       = "3900 Invalid command\n";
51 static char OKsetdebug[]   = "3000 OK setdebug=%d\n";
52
53
54 /* Imported functions */
55 extern void terminate_child();
56 extern int job_cmd(JCR *jcr);
57
58 /* Forward referenced functions */
59 static int label_cmd(JCR *jcr);
60 static int setdebug_cmd(JCR *jcr);
61 static int cancel_cmd(JCR *cjcr);
62 static int mount_cmd(JCR *jcr);
63 static int unmount_cmd(JCR *jcr);
64 static int status_cmd(JCR *sjcr);
65 static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname);
66
67 struct s_cmds {
68    char *cmd;
69    int (*func)(JCR *jcr);
70 };
71
72 /*  
73  * The following are the recognized commands from the Director. 
74  */
75 static struct s_cmds cmds[] = {
76    {"JobId=",    job_cmd},            /* start Job */
77    {"setdebug=", setdebug_cmd},       /* set debug level */
78    {"cancel",    cancel_cmd},
79    {"label",     label_cmd},          /* label a tape */
80    {"mount",     mount_cmd},
81    {"unmount",   unmount_cmd},
82    {"status",    status_cmd},
83    {NULL,        NULL}                /* list terminator */
84 };
85
86
87 /* 
88  * Connection request. We accept connections either from the 
89  *  Director or a Client.
90  * 
91  * Note, we are running as a seperate thread of the Storage daemon.
92  *  and it is because a Director has made a connection with
93  *  us on the "Message" channel.    
94  *
95  * Basic tasks done here:  
96  *  - Create a JCR record
97  *  - Authenticate the Director
98  *  - We wait for a command
99  *  - We execute the command
100  *  - We continue or exit depending on the return status
101  */
102 void connection_request(void *arg)
103 {
104    BSOCK *bs = (BSOCK *)arg;
105    JCR *jcr;
106    int i, found, quit;
107    int bnet_stat = 0;
108    char name[MAX_NAME_LENGTH];
109
110    if (bnet_recv(bs) <= 0) {
111       Emsg0(M_ERROR, 0, "Connection request failed.\n");
112       return;
113    }
114
115    /* 
116     * See if this is a File daemon connection
117     */
118    if (sscanf(bs->msg, "Hello Start Job %127s calling\n", name) == 1) {
119       handle_filed_connection(bs, name);
120       return;
121    }
122    
123    jcr = new_jcr(sizeof(JCR), stored_free_jcr);     /* create Job Control Record */
124    jcr->dir_bsock = bs;               /* save Director bsock */
125
126    Dmsg0(1000, "stored in start_job\n");
127
128    /*
129     * Authenticate the Director
130     */
131    if (!authenticate_director(jcr)) {
132       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate Director\n"));
133       free_jcr(jcr);
134       return;
135    }
136    Dmsg0(90, "Message channel init completed.\n");
137
138    for (quit=0; !quit;) {
139
140       /* Read command */
141       if ((bnet_stat = bnet_recv(bs)) <= 0) {
142          break;                       /* connection terminated */
143       }
144       Dmsg1(9, "<dird: %s\n", bs->msg);
145       found = FALSE;
146       for (i=0; cmds[i].cmd; i++) {
147          if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
148             if (!cmds[i].func(jcr)) {    /* do command */
149                quit = TRUE;              /* error, get out */
150                Dmsg1(90, "Command %s requsts quit\n", cmds[i].cmd);
151             }
152             found = TRUE;            /* indicate command found */
153             break;
154          }
155       }
156       if (!found) {                   /* command not found */
157          bnet_fsend(bs, derrmsg);
158          quit = TRUE;
159          break;
160       }
161    }
162    if (bnet_stat != BNET_TERMINATE) {
163       bnet_sig(bs, BNET_TERMINATE);
164    }
165    free_jcr(jcr);
166    return;
167 }
168
169 /*
170  * Set debug level as requested by the Director
171  *
172  */
173 static int setdebug_cmd(JCR *jcr)
174 {
175    BSOCK *dir = jcr->dir_bsock;
176    int level;
177
178    Dmsg1(10, "setdebug_cmd: %s", dir->msg);
179    if (sscanf(dir->msg, "setdebug=%d", &level) != 1 || level < 0) {
180       bnet_fsend(dir, "3991 Bad setdebug command: %s\n", dir->msg);
181       return 0;
182    }
183    debug_level = level;
184    return bnet_fsend(dir, OKsetdebug, level);
185 }
186
187
188 /*
189  * Cancel a Job
190  */
191 static int cancel_cmd(JCR *cjcr)
192 {
193    BSOCK *dir = cjcr->dir_bsock;
194    int oldStatus;
195    char Job[MAX_NAME_LENGTH];
196    JCR *jcr;
197
198    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
199       if (!(jcr=get_jcr_by_full_name(Job))) {
200          bnet_fsend(dir, _("3992 Job %s not found.\n"), Job);
201       } else {
202          P(jcr->mutex);
203          oldStatus = jcr->JobStatus;
204          jcr->JobStatus = JS_Cancelled;
205          if (!jcr->authenticated && jcr->JobStatus == JS_WaitFD) {
206             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
207          }
208          V(jcr->mutex);
209          if (jcr->file_bsock) {
210             bnet_sig(jcr->file_bsock, BNET_TERMINATE);
211          }
212          bnet_fsend(dir, _("3000 Job %s Status=%c marked to be cancelled.\n"), 
213             jcr->Job, oldStatus);
214          free_jcr(jcr);
215       }
216    } else {
217       bnet_fsend(dir, _("3993 Error scanning cancel command.\n"));
218    }
219    bnet_sig(dir, BNET_EOD);
220    return 1;
221 }
222
223 /*
224  * Label a tape
225  *
226  */
227 static int label_cmd(JCR *jcr) 
228 {
229    POOLMEM *dname, *volname, *poolname, *mtype;
230    BSOCK *dir = jcr->dir_bsock;
231    DEVRES *device;
232    DEVICE *dev;
233    int found = 0;
234    int slot;    
235
236    dname = get_memory(dir->msglen+1);
237    volname = get_memory(dir->msglen+1);
238    poolname = get_memory(dir->msglen+1);
239    mtype = get_memory(dir->msglen+1);
240    if (sscanf(dir->msg, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
241        dname, volname, poolname, mtype, &slot) == 5) {
242       unbash_spaces(dname);
243       unbash_spaces(volname);
244       unbash_spaces(poolname);
245       unbash_spaces(mtype);
246       device = NULL;
247       LockRes();
248       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
249          /* Find resource, and make sure we were able to open it */
250          if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
251             Dmsg1(20, "Found device %s\n", device->hdr.name);
252             found = 1;
253             break;
254          }
255       }
256       UnlockRes();
257       if (found) {
258          /******FIXME**** compare MediaTypes */
259          jcr->device = device;
260          dev = device->dev;
261
262 /* *****FIXME***** add autochanger code */
263
264 #ifdef NEW_LOCK
265          P(dev->lock.mutex);
266          if (!(dev->state & ST_OPENED)) {
267             label_it = TRUE;
268          } else if (dev->dev_blocked && 
269                     dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
270             label_it = TRUE;
271          } else if (dev->state & ST_READ || dev->num_writers) {
272             if (dev->state & ST_READ) {
273                 bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
274                    dev_name(dev));
275             } else {
276                 bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
277                    dev_name(dev), dev->num_writers);
278             }
279          } else {                     /* device not being used */
280             label_it = TRUE;
281          }
282          if (label_it) {
283             new_steal_device_lock(dev, &hold, BST_WRITING_LABEL);
284             if (!(dev->state & ST_OPENED)) {
285                if (open_dev(dev, volname, READ_WRITE) < 0) {
286                   bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
287                } else {
288                   label_volume_if_ok(jcr, dev, volname, poolname);
289                   force_close_dev(dev);
290                }
291             } else {
292                label_volume_if_ok(jcr, dev, volname, poolname);
293             }
294             new_return_device_lock(dev, &hold);
295          }
296          V(dev->lock.mutex);
297 #else
298          P(dev->mutex);
299          if (!(dev->state & ST_OPENED)) {
300             if (open_dev(dev, volname, READ_WRITE) < 0) {
301                bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
302             } else {
303                label_volume_if_ok(jcr, dev, volname, poolname);
304                force_close_dev(dev);
305             }
306          } else if (dev->dev_blocked && 
307                     dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
308             label_volume_if_ok(jcr, dev, volname, poolname);
309          } else if (dev->state & ST_READ || dev->num_writers) {
310             if (dev->state & ST_READ) {
311                 bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
312                    dev_name(dev));
313             } else {
314                 bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
315                    dev_name(dev), dev->num_writers);
316             }
317          } else {                     /* device not being used */
318             label_volume_if_ok(jcr, dev, volname, poolname);
319          }
320          V(dev->mutex);
321 #endif
322       } else {
323          bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
324       }
325    } else {
326       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
327       strcpy(dname, dir->msg);
328       bnet_fsend(dir, _("3903 Error scanning label command: %s\n"), dname);
329    }
330    free_memory(dname);
331    free_memory(volname);
332    free_memory(poolname);
333    free_memory(mtype);
334    bnet_sig(dir, BNET_EOD);
335    return 1;
336 }
337
338 /* 
339  * Read the tape label and determine if we can safely
340  * label the tape (not a Bacula volume), then label it.
341  *
342  *  Enter with the mutex set
343  */
344 static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname)
345 {
346    BSOCK *dir = jcr->dir_bsock;
347    DEV_BLOCK *block;
348    bsteal_lock_t hold;
349    
350    steal_device_lock(dev, &hold, BST_WRITING_LABEL);
351    
352    strcpy(jcr->VolumeName, vname);
353    block = new_block(dev);
354    switch (read_dev_volume_label(jcr, dev, block)) {                
355       case VOL_NAME_ERROR:
356       case VOL_VERSION_ERROR:
357       case VOL_LABEL_ERROR:
358       case VOL_OK:
359          bnet_fsend(dir, _("3901 Cannot label Volume because it is \
360 already labeled: %s\n"), dev->VolHdr.VolName);
361          break;
362       case VOL_IO_ERROR:
363       case VOL_NO_LABEL:
364          write_volume_label_to_dev(jcr, jcr->device, vname, poolname);
365          strcpy(jcr->VolumeName, vname);
366          bnet_fsend(dir, _("3000 OK label. Volume=%s Device=%s\n"), 
367             vname, dev->dev_name);
368          break;
369       default:
370          bnet_fsend(dir, _("3902 Cannot label Volume. \
371 Unknown status %d from read_volume_label()\n"), jcr->label_status);
372          break;
373    }
374    free_block(block);
375    return_device_lock(dev, &hold);
376 }
377
378
379 /* 
380  * Read the tape label
381  *
382  *  Enter with the mutex set
383  */
384 static int read_label(JCR *jcr, DEVICE *dev)
385 {
386    int stat;
387    BSOCK *dir = jcr->dir_bsock;
388    DEV_BLOCK *block;
389 #ifndef NEW_LOCK
390    bsteal_lock_t hold;
391    
392    steal_device_lock(dev, &hold, BST_DOING_ACQUIRE);
393 #endif
394    
395    jcr->VolumeName[0] = 0;
396    block = new_block(dev);
397    dev->state &= ~ST_LABEL;           /* force read of label */
398    switch (read_dev_volume_label(jcr, dev, block)) {                
399       case VOL_OK:
400          bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
401          stat = 1;
402          break;
403       default:
404          bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s\n"),
405             dev->dev_name, jcr->errmsg);
406          stat = 0;
407          break;
408    }
409    free_block(block);
410 #ifndef NEW_LOCK
411    return_device_lock(dev, &hold);
412 #endif
413    return stat;
414 }
415
416 /*
417  * Mount command from Director
418  */
419 static int mount_cmd(JCR *jcr)
420 {
421    char *dev_name;
422    BSOCK *dir = jcr->dir_bsock;
423    DEVRES *device;
424    DEVICE *dev;
425    int found = 0;
426
427    dev_name = (char *) get_memory(dir->msglen);
428    if (sscanf(dir->msg, "mount %s", dev_name) == 1) {
429       unbash_spaces(dev_name);
430       device = NULL;
431       LockRes();
432       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
433          /* Find resource, and make sure we were able to open it */
434          if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
435             Dmsg1(20, "Found device %s\n", device->hdr.name);
436             found = 1;
437             break;
438          }
439       }
440       UnlockRes();
441       if (found) {
442          jcr->device = device;
443          dev = device->dev;
444          P(dev->mutex);
445          switch (dev->dev_blocked) {         /* device blocked? */
446             DEV_BLOCK *block;
447             case BST_WAITING_FOR_SYSOP:
448                /* Someone is waiting, wake him */
449                Dmsg0(90, "Waiting for mount attempt to wake thread\n");
450                pthread_cond_signal(&dev->wait_next_vol);
451                bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev->dev_name);
452                break;
453
454             case BST_UNMOUNTED_WAITING_FOR_SYSOP:
455             case BST_UNMOUNTED:
456                /* We freed the device, so reopen it and wake any waiting threads */
457                if (open_dev(dev, NULL, READ_WRITE) < 0) {
458                   bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
459                      strerror_dev(dev));
460                   break;
461                }
462                block = new_block(dev);
463                read_dev_volume_label(jcr, dev, block);
464                free_block(block);
465                if (dev->dev_blocked == BST_UNMOUNTED) {
466                   Dmsg0(90, "Unmounted unblocking device\n");
467                   read_label(jcr, dev);
468                   new_unlock_device(dev);
469                   unblock_device(dev);
470                } else {
471                   Dmsg0(90, "Unmounted waiting for mount attempt to wake thread\n");
472                   dev->dev_blocked = BST_WAITING_FOR_SYSOP;
473                   pthread_cond_signal(&dev->wait_next_vol);
474                }
475                if (dev->state & ST_LABEL) {
476                   bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
477                      dev->dev_name, dev->VolHdr.VolName);
478                } else {
479                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
480                              dev->dev_name);
481                }
482                break;
483
484             case BST_DOING_ACQUIRE:
485                bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), 
486                           dev->dev_name);
487                break;
488
489             case BST_WRITING_LABEL:
490                bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev->dev_name);
491                break;
492
493             case BST_NOT_BLOCKED:
494                if (dev->state & ST_OPENED) {
495                   if (dev->state & ST_LABEL) {
496                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"),
497                         dev->dev_name, dev->VolHdr.VolName);
498                   } else {
499                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
500                                 dev->dev_name);
501                   }
502                } else {
503                   if (!dev_is_tape(dev)) {
504                      bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
505                      break;
506                   }
507                   if (open_dev(dev, NULL, READ_WRITE) < 0) {
508                      bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
509                         strerror_dev(dev));
510                      break;
511                   }
512                   read_label(jcr, dev);
513                   if (dev->state & ST_LABEL) {
514                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
515                         dev->dev_name, dev->VolHdr.VolName);
516                   } else {
517                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
518                                 dev->dev_name);
519                   }
520                }
521                break;
522
523             default:
524                bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
525                break;
526          }
527          V(dev->mutex);
528       } else {
529          bnet_fsend(dir, _("3999 Device %s not found\n"), dev_name);
530       }
531    } else {
532       strcpy(dev_name, dir->msg);
533       bnet_fsend(dir, _("3906 Error scanning mount command: %s\n"), dev_name);
534    }
535    free_memory(dev_name);
536    bnet_sig(dir, BNET_EOD);
537    return 1;
538 }
539
540 /*
541  * unmount command from Director
542  */
543 static int unmount_cmd(JCR *jcr)
544 {
545    char *dname;
546    BSOCK *dir = jcr->dir_bsock;
547    DEVRES *device;
548    DEVICE *dev;
549    int found = 0;
550
551    dname = (char *) get_memory(dir->msglen+1);
552    if (sscanf(dir->msg, "unmount %s", dname) == 1) {
553       unbash_spaces(dname);
554       device = NULL;
555       LockRes();
556       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
557          /* Find resource, and make sure we were able to open it */
558          if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
559             Dmsg1(20, "Found device %s\n", device->hdr.name);
560             found = 1;
561             break;
562          }
563       }
564       UnlockRes();
565       if (found) {
566          jcr->device = device;
567          dev = device->dev;
568          P(dev->mutex);
569          if (!(dev->state & ST_OPENED)) {
570             Dmsg0(90, "Device already unmounted\n");
571             bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), dev_name(dev));
572
573          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
574             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
575                dev->dev_blocked);
576             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
577                offline_dev(dev);
578             }
579             force_close_dev(dev);
580             dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
581             bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev));
582
583          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
584             bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
585                dev_name(dev));
586
587          } else if (dev->dev_blocked == BST_WRITING_LABEL) {
588             bnet_fsend(dir, _("3903 Device %s is being labeled.\n"),
589                dev_name(dev));
590
591          } else if (dev->state & ST_READ || dev->num_writers) {
592             if (dev->state & ST_READ) {
593                 Dmsg0(90, "Device in read mode\n");
594                 bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"),
595                    dev_name(dev));
596             } else {
597                 Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
598                 bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
599                    dev_name(dev), dev->num_writers);
600             }
601
602          } else {                     /* device not being used */
603             Dmsg0(90, "Device not in use, unmounting\n");
604             new_lock_device_state(dev, BST_UNMOUNTED);
605             block_device(dev, BST_UNMOUNTED);
606             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
607                offline_dev(dev);
608             }
609             force_close_dev(dev);
610             bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
611          }
612          V(dev->mutex);
613       } else {
614          bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
615       }
616    } else {
617       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
618       strcpy(dname, dir->msg);
619       bnet_fsend(dir, _("3907 Error scanning unmount command: %s\n"), dname);
620    }
621    free_memory(dname);
622    bnet_sig(dir, BNET_EOD);
623    return 1;
624 }
625
626 /*
627  * Status command from Director
628  */
629 static int status_cmd(JCR *jcr)
630 {
631    DEVRES *device;
632    DEVICE *dev;
633    int found, bps, sec, bpb;
634    BSOCK *user = jcr->dir_bsock;
635    char dt[MAX_TIME_LENGTH];
636    char b1[30], b2[30], b3[30];
637
638    bnet_fsend(user, "\n%s Version: " VERSION " (" DATE ")\n", my_name);
639    bstrftime(dt, sizeof(dt), daemon_start_time);
640    bnet_fsend(user, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
641         last_job.NumJobs == 1 ? "" : "s");
642    if (last_job.NumJobs > 0) {
643       char termstat[30];
644
645       bstrftime(dt, sizeof(dt), last_job.end_time);
646       bnet_fsend(user, _("Last Job %s finished at %s\n"), last_job.Job, dt);
647
648       jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
649       bnet_fsend(user, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
650            edit_uint64_with_commas(last_job.JobFiles, b1),
651            edit_uint64_with_commas(last_job.JobBytes, b2),
652            termstat);
653    }
654
655    LockRes();
656    for (device=NULL;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
657       dev = device->dev;
658       if (dev) {
659          if (dev->state & ST_OPENED) {
660             if (dev->state & ST_LABEL) {
661                bnet_fsend(user, _("Device %s is mounted with Volume %s\n"), 
662                   dev_name(dev), dev->VolHdr.VolName);
663             } else {
664                bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), dev_name(dev));
665             }
666             switch (dev->dev_blocked) {
667                case BST_UNMOUNTED:
668                   bnet_fsend(user, _("    Deviced is blocked. User unmounted.\n"));
669                   break;
670                case BST_UNMOUNTED_WAITING_FOR_SYSOP:
671                   bnet_fsend(user, _("    Deviced is blocked. User unmounted during wait for media/mount.\n"));
672                   break;
673                case BST_WAITING_FOR_SYSOP:
674                   if (jcr->JobStatus == JS_WaitMount) {
675                      bnet_fsend(user, _("    Device is blocked waiting for mount.\n"));
676                   } else {
677                      bnet_fsend(user, _("    Device is blocked waiting for appendable media.\n"));
678                   }
679                   break;
680                case BST_DOING_ACQUIRE:
681                   bnet_fsend(user, _("    Device is being initialized.\n"));
682                   break;
683                case BST_WRITING_LABEL:
684                   bnet_fsend(user, _("    Device is blocked labeling a Volume.\n"));
685                   break;
686                default:
687                   break;
688             }
689             bpb = dev->VolCatInfo.VolCatBlocks;
690             if (bpb <= 0) {
691                bpb = 1;
692             }
693             bpb = dev->VolCatInfo.VolCatBytes / bpb;
694             bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
695                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
696                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), 
697                edit_uint64_with_commas(bpb, b3));
698             bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"), 
699                edit_uint64_with_commas(dev->file, b1),
700                edit_uint64_with_commas(dev->block_num, b2));
701
702          } else {
703             bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev));
704          }
705       }
706    }
707    UnlockRes();
708
709    found = 0;
710    lock_jcr_chain();
711    /* NOTE, we reuse a calling argument jcr. Be warned! */ 
712    for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
713       if (jcr->JobStatus == JS_WaitFD) {
714          bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
715             job_type_to_str(jcr->JobType), jcr->Job);
716       }
717       if (jcr->device) {
718          bnet_fsend(user, _("%s %s job %s is using device %s\n"), 
719                    job_level_to_str(jcr->JobLevel),
720                    job_type_to_str(jcr->JobType),
721                    jcr->Job, jcr->device->device_name);
722          sec = time(NULL) - jcr->run_time;
723          if (sec <= 0) {
724             sec = 1;
725          }
726          bps = jcr->JobBytes / sec;
727          bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
728             edit_uint64_with_commas(jcr->JobFiles, b1),
729             edit_uint64_with_commas(jcr->JobBytes, b2),
730             edit_uint64_with_commas(bps, b3));
731          found = 1;
732 #ifdef DEBUG
733          if (jcr->file_bsock) {
734             bnet_fsend(user, "    FDReadSeqNo=%" lld " fd=%d\n", 
735                jcr->file_bsock->read_seqno, jcr->file_bsock->fd);
736          } else {
737             bnet_fsend(user, "    FDSocket closed\n");
738          }
739 #endif
740       }
741       free_locked_jcr(jcr);
742    }
743    unlock_jcr_chain();
744    if (!found) {
745       bnet_fsend(user, _("No jobs running.\n"));
746    }
747
748 #ifdef full_status
749    bnet_fsend(user, "\n\n");
750    dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
751 #endif
752    bnet_fsend(user, "====\n");
753
754    bnet_sig(user, BNET_EOD);
755    return 1;
756 }