]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dircmd.c
Restore from multiple simultaneous backups
[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    char *dname, *volname, *poolname, *mtype;
230    BSOCK *dir = jcr->dir_bsock;
231    DEVRES *device;
232    DEVICE *dev;
233    int found = 0;
234
235    dname = (char *) get_memory(dir->msglen+1);
236    volname = (char *) get_memory(dir->msglen+1);
237    poolname = (char *) get_memory(dir->msglen+1);
238    mtype = (char *) get_memory(dir->msglen+1);
239    if (sscanf(dir->msg, "label %s VolumeName=%s PoolName=%s MediaType=%s", 
240        dname, volname, poolname, mtype) == 4) {
241       unbash_spaces(dname);
242       unbash_spaces(volname);
243       unbash_spaces(poolname);
244       unbash_spaces(mtype);
245       device = NULL;
246       LockRes();
247       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
248          /* Find resource, and make sure we were able to open it */
249          if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
250             Dmsg1(20, "Found device %s\n", device->hdr.name);
251             found = 1;
252             break;
253          }
254       }
255       UnlockRes();
256       if (found) {
257 #ifdef NEW_LOCK
258          int label_it = FALSE;
259          brwsteal_t hold;
260 #endif
261          /******FIXME**** compare MediaTypes */
262          jcr->device = device;
263          dev = device->dev;
264
265 #ifdef NEW_LOCK
266          P(dev->lock.mutex);
267          if (!(dev->state & ST_OPENED)) {
268             label_it = TRUE;
269          } else if (dev->dev_blocked && 
270                     dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
271             label_it = TRUE;
272          } else if (dev->state & ST_READ || dev->num_writers) {
273             if (dev->state & ST_READ) {
274                 bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
275                    dev_name(dev));
276             } else {
277                 bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
278                    dev_name(dev), dev->num_writers);
279             }
280          } else {                     /* device not being used */
281             label_it = TRUE;
282          }
283          if (label_it) {
284             new_steal_device_lock(dev, &hold, BST_WRITING_LABEL);
285             if (!(dev->state & ST_OPENED)) {
286                if (open_dev(dev, volname, READ_WRITE) < 0) {
287                   bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
288                } else {
289                   label_volume_if_ok(jcr, dev, volname, poolname);
290                   force_close_dev(dev);
291                }
292             } else {
293                label_volume_if_ok(jcr, dev, volname, poolname);
294             }
295             new_return_device_lock(dev, &hold);
296          }
297          V(dev->lock.mutex);
298 #else
299          P(dev->mutex);
300          if (!(dev->state & ST_OPENED)) {
301             if (open_dev(dev, volname, READ_WRITE) < 0) {
302                bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev));
303             } else {
304                label_volume_if_ok(jcr, dev, volname, poolname);
305                force_close_dev(dev);
306             }
307          } else if (dev->dev_blocked && 
308                     dev->dev_blocked != BST_DOING_ACQUIRE) {  /* device blocked? */
309             label_volume_if_ok(jcr, dev, volname, poolname);
310          } else if (dev->state & ST_READ || dev->num_writers) {
311             if (dev->state & ST_READ) {
312                 bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"),
313                    dev_name(dev));
314             } else {
315                 bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"),
316                    dev_name(dev), dev->num_writers);
317             }
318          } else {                     /* device not being used */
319             label_volume_if_ok(jcr, dev, volname, poolname);
320          }
321          V(dev->mutex);
322 #endif
323       } else {
324          bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
325       }
326    } else {
327       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
328       strcpy(dname, dir->msg);
329       bnet_fsend(dir, _("3903 Error scanning label command: %s\n"), dname);
330    }
331    free_memory(dname);
332    free_memory(volname);
333    free_memory(poolname);
334    free_memory(mtype);
335    bnet_sig(dir, BNET_EOD);
336    return 1;
337 }
338
339 /* 
340  * Read the tape label and determine if we can safely
341  * label the tape (not a Bacula volume), then label it.
342  *
343  *  Enter with the mutex set
344  */
345 static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *vname, char *poolname)
346 {
347    BSOCK *dir = jcr->dir_bsock;
348    DEV_BLOCK *block;
349 #ifndef NEW_LOCK
350    bsteal_lock_t hold;
351    
352    steal_device_lock(dev, &hold, BST_WRITING_LABEL);
353 #endif
354    
355    strcpy(jcr->VolumeName, vname);
356    block = new_block(dev);
357    switch (read_dev_volume_label(jcr, dev, block)) {                
358       case VOL_NAME_ERROR:
359       case VOL_VERSION_ERROR:
360       case VOL_LABEL_ERROR:
361       case VOL_OK:
362          bnet_fsend(dir, _("3901 Cannot label Volume because it is \
363 already labeled: %s\n"), dev->VolHdr.VolName);
364          break;
365       case VOL_IO_ERROR:
366       case VOL_NO_LABEL:
367          write_volume_label_to_dev(jcr, jcr->device, vname, poolname);
368          strcpy(jcr->VolumeName, vname);
369          bnet_fsend(dir, _("3000 OK label. Volume=%s Device=%s\n"), 
370             vname, dev->dev_name);
371          break;
372       default:
373          bnet_fsend(dir, _("3902 Cannot label Volume. \
374 Unknown status %d from read_volume_label()\n"), jcr->label_status);
375          break;
376    }
377    free_block(block);
378 #ifndef NEW_LOCK
379    return_device_lock(dev, &hold);
380 #endif
381 }
382
383
384 /* 
385  * Read the tape label
386  *
387  *  Enter with the mutex set
388  */
389 static int read_label(JCR *jcr, DEVICE *dev)
390 {
391    int stat;
392    BSOCK *dir = jcr->dir_bsock;
393    DEV_BLOCK *block;
394 #ifndef NEW_LOCK
395    bsteal_lock_t hold;
396    
397    steal_device_lock(dev, &hold, BST_DOING_ACQUIRE);
398 #endif
399    
400    jcr->VolumeName[0] = 0;
401    block = new_block(dev);
402    dev->state &= ~ST_LABEL;           /* force read of label */
403    switch (read_dev_volume_label(jcr, dev, block)) {                
404       case VOL_OK:
405          bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
406          stat = 1;
407          break;
408       default:
409          bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s\n"),
410             dev->dev_name, jcr->errmsg);
411          stat = 0;
412          break;
413    }
414    free_block(block);
415 #ifndef NEW_LOCK
416    return_device_lock(dev, &hold);
417 #endif
418    return stat;
419 }
420
421 /*
422  * Mount command from Director
423  */
424 static int mount_cmd(JCR *jcr)
425 {
426    char *dev_name;
427    BSOCK *dir = jcr->dir_bsock;
428    DEVRES *device;
429    DEVICE *dev;
430    int found = 0;
431
432    dev_name = (char *) get_memory(dir->msglen);
433    if (sscanf(dir->msg, "mount %s", dev_name) == 1) {
434       unbash_spaces(dev_name);
435       device = NULL;
436       LockRes();
437       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
438          /* Find resource, and make sure we were able to open it */
439          if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
440             Dmsg1(20, "Found device %s\n", device->hdr.name);
441             found = 1;
442             break;
443          }
444       }
445       UnlockRes();
446       if (found) {
447          jcr->device = device;
448          dev = device->dev;
449          P(dev->mutex);
450          switch (dev->dev_blocked) {         /* device blocked? */
451             DEV_BLOCK *block;
452             case BST_WAITING_FOR_SYSOP:
453                /* Someone is waiting, wake him */
454                Dmsg0(90, "Waiting for mount attempt to wake thread\n");
455                pthread_cond_signal(&dev->wait_next_vol);
456                bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev->dev_name);
457                break;
458
459             case BST_UNMOUNTED_WAITING_FOR_SYSOP:
460             case BST_UNMOUNTED:
461                /* We freed the device, so reopen it and wake any waiting threads */
462                if (open_dev(dev, NULL, READ_WRITE) < 0) {
463                   bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
464                      strerror_dev(dev));
465                   break;
466                }
467                block = new_block(dev);
468                read_dev_volume_label(jcr, dev, block);
469                free_block(block);
470                if (dev->dev_blocked == BST_UNMOUNTED) {
471                   Dmsg0(90, "Unmounted unblocking device\n");
472                   read_label(jcr, dev);
473                   new_unlock_device(dev);
474                   unblock_device(dev);
475                } else {
476                   Dmsg0(90, "Unmounted waiting for mount attempt to wake thread\n");
477                   dev->dev_blocked = BST_WAITING_FOR_SYSOP;
478                   pthread_cond_signal(&dev->wait_next_vol);
479                }
480                if (dev->state & ST_LABEL) {
481                   bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
482                      dev->dev_name, dev->VolHdr.VolName);
483                } else {
484                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
485                              dev->dev_name);
486                }
487                break;
488
489             case BST_DOING_ACQUIRE:
490                bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), 
491                           dev->dev_name);
492                break;
493
494             case BST_WRITING_LABEL:
495                bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev->dev_name);
496                break;
497
498             case BST_NOT_BLOCKED:
499                if (dev->state & ST_OPENED) {
500                   if (dev->state & ST_LABEL) {
501                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"),
502                         dev->dev_name, dev->VolHdr.VolName);
503                   } else {
504                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
505                                 dev->dev_name);
506                   }
507                } else {
508                   if (!dev_is_tape(dev)) {
509                      bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
510                      break;
511                   }
512                   if (open_dev(dev, NULL, READ_WRITE) < 0) {
513                      bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
514                         strerror_dev(dev));
515                      break;
516                   }
517                   read_label(jcr, dev);
518                   if (dev->state & ST_LABEL) {
519                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
520                         dev->dev_name, dev->VolHdr.VolName);
521                   } else {
522                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
523                                 dev->dev_name);
524                   }
525                }
526                break;
527
528             default:
529                bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
530                break;
531          }
532          V(dev->mutex);
533       } else {
534          bnet_fsend(dir, _("3999 Device %s not found\n"), dev_name);
535       }
536    } else {
537       strcpy(dev_name, dir->msg);
538       bnet_fsend(dir, _("3906 Error scanning mount command: %s\n"), dev_name);
539    }
540    free_memory(dev_name);
541    bnet_sig(dir, BNET_EOD);
542    return 1;
543 }
544
545 /*
546  * unmount command from Director
547  */
548 static int unmount_cmd(JCR *jcr)
549 {
550    char *dname;
551    BSOCK *dir = jcr->dir_bsock;
552    DEVRES *device;
553    DEVICE *dev;
554    int found = 0;
555
556    dname = (char *) get_memory(dir->msglen+1);
557    if (sscanf(dir->msg, "unmount %s", dname) == 1) {
558       unbash_spaces(dname);
559       device = NULL;
560       LockRes();
561       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
562          /* Find resource, and make sure we were able to open it */
563          if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
564             Dmsg1(20, "Found device %s\n", device->hdr.name);
565             found = 1;
566             break;
567          }
568       }
569       UnlockRes();
570       if (found) {
571          jcr->device = device;
572          dev = device->dev;
573          P(dev->mutex);
574          if (!(dev->state & ST_OPENED)) {
575             Dmsg0(90, "Device already unmounted\n");
576             bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), dev_name(dev));
577
578          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
579             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
580                dev->dev_blocked);
581             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
582                offline_dev(dev);
583             }
584             force_close_dev(dev);
585             dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
586             bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev));
587
588          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
589             bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
590                dev_name(dev));
591
592          } else if (dev->dev_blocked == BST_WRITING_LABEL) {
593             bnet_fsend(dir, _("3903 Device %s is being labeled.\n"),
594                dev_name(dev));
595
596          } else if (dev->state & ST_READ || dev->num_writers) {
597             if (dev->state & ST_READ) {
598                 Dmsg0(90, "Device in read mode\n");
599                 bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"),
600                    dev_name(dev));
601             } else {
602                 Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
603                 bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
604                    dev_name(dev), dev->num_writers);
605             }
606
607          } else {                     /* device not being used */
608             Dmsg0(90, "Device not in use, unmounting\n");
609             new_lock_device_state(dev, BST_UNMOUNTED);
610             block_device(dev, BST_UNMOUNTED);
611             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
612                offline_dev(dev);
613             }
614             force_close_dev(dev);
615             bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
616          }
617          V(dev->mutex);
618       } else {
619          bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
620       }
621    } else {
622       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
623       strcpy(dname, dir->msg);
624       bnet_fsend(dir, _("3907 Error scanning unmount command: %s\n"), dname);
625    }
626    free_memory(dname);
627    bnet_sig(dir, BNET_EOD);
628    return 1;
629 }
630
631 /*
632  * Status command from Director
633  */
634 static int status_cmd(JCR *jcr)
635 {
636    DEVRES *device;
637    DEVICE *dev;
638    int found, bps, sec, bpb;
639    BSOCK *user = jcr->dir_bsock;
640    char dt[MAX_TIME_LENGTH];
641    char b1[30], b2[30], b3[30];
642
643    bnet_fsend(user, "\n%s Version: " VERSION " (" DATE ")\n", my_name);
644    bstrftime(dt, sizeof(dt), daemon_start_time);
645    bnet_fsend(user, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
646         last_job.NumJobs == 1 ? "" : "s");
647    if (last_job.NumJobs > 0) {
648       char termstat[30];
649
650       bstrftime(dt, sizeof(dt), last_job.end_time);
651       bnet_fsend(user, _("Last Job %s finished at %s\n"), last_job.Job, dt);
652
653       jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
654       bnet_fsend(user, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
655            edit_uint64_with_commas(last_job.JobFiles, b1),
656            edit_uint64_with_commas(last_job.JobBytes, b2),
657            termstat);
658    }
659
660    LockRes();
661    for (device=NULL;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
662       dev = device->dev;
663       if (dev) {
664          if (dev->state & ST_OPENED) {
665             if (dev->state & ST_LABEL) {
666                bnet_fsend(user, _("Device %s is mounted with Volume %s\n"), 
667                   dev_name(dev), dev->VolHdr.VolName);
668             } else {
669                bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), dev_name(dev));
670             }
671             switch (dev->dev_blocked) {
672                case BST_UNMOUNTED:
673                   bnet_fsend(user, _("    Deviced is blocked. User unmounted.\n"));
674                   break;
675                case BST_UNMOUNTED_WAITING_FOR_SYSOP:
676                   bnet_fsend(user, _("    Deviced is blocked. User unmounted during wait for media/mount.\n"));
677                   break;
678                case BST_WAITING_FOR_SYSOP:
679                   if (jcr->JobStatus == JS_WaitMount) {
680                      bnet_fsend(user, _("    Device is blocked waiting for mount.\n"));
681                   } else {
682                      bnet_fsend(user, _("    Device is blocked waiting for appendable media.\n"));
683                   }
684                   break;
685                case BST_DOING_ACQUIRE:
686                   bnet_fsend(user, _("    Device is being initialized.\n"));
687                   break;
688                case BST_WRITING_LABEL:
689                   bnet_fsend(user, _("    Device is blocked labeling a Volume.\n"));
690                   break;
691                default:
692                   break;
693             }
694             bpb = dev->VolCatInfo.VolCatBlocks;
695             if (bpb <= 0) {
696                bpb = 1;
697             }
698             bpb = dev->VolCatInfo.VolCatBytes / bpb;
699             bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
700                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
701                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), 
702                edit_uint64_with_commas(bpb, b3));
703             bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"), 
704                edit_uint64_with_commas(dev->file, b1),
705                edit_uint64_with_commas(dev->block_num, b2));
706
707          } else {
708             bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev));
709          }
710       }
711    }
712    UnlockRes();
713
714    found = 0;
715    lock_jcr_chain();
716    /* NOTE, we reuse a calling argument jcr. Be warned! */ 
717    for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
718       if (jcr->JobStatus == JS_WaitFD) {
719          bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
720             job_type_to_str(jcr->JobType), jcr->Job);
721       }
722       if (jcr->device) {
723          bnet_fsend(user, _("%s %s job %s is using device %s\n"), 
724                    job_level_to_str(jcr->JobLevel),
725                    job_type_to_str(jcr->JobType),
726                    jcr->Job, jcr->device->device_name);
727          sec = time(NULL) - jcr->run_time;
728          if (sec <= 0) {
729             sec = 1;
730          }
731          bps = jcr->JobBytes / sec;
732          bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
733             edit_uint64_with_commas(jcr->JobFiles, b1),
734             edit_uint64_with_commas(jcr->JobBytes, b2),
735             edit_uint64_with_commas(bps, b3));
736          found = 1;
737 #ifdef DEBUG
738          if (jcr->file_bsock) {
739             bnet_fsend(user, "    FDReadSeqNo=%" lld " fd=%d\n", 
740                jcr->file_bsock->read_seqno, jcr->file_bsock->fd);
741          } else {
742             bnet_fsend(user, "    FDSocket closed\n");
743          }
744 #endif
745       }
746       free_locked_jcr(jcr);
747    }
748    unlock_jcr_chain();
749    if (!found) {
750       bnet_fsend(user, _("No jobs running.\n"));
751    }
752
753 #ifdef full_status
754    bnet_fsend(user, "\n\n");
755    dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
756 #endif
757    bnet_fsend(user, "====\n");
758
759    bnet_sig(user, BNET_EOD);
760    return 1;
761 }