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