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