]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/dircmd.c
Autochanger for read + 64 bit addrs + Session key, see kes14Sep02
[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
73 struct s_cmds {
74    char *cmd;
75    int (*func)(JCR *jcr);
76 };
77
78 /*  
79  * The following are the recognized commands from the Director. 
80  */
81 static struct s_cmds cmds[] = {
82    {"JobId=",    job_cmd},            /* start Job */
83    {"setdebug=", setdebug_cmd},       /* set debug level */
84    {"cancel",    cancel_cmd},
85    {"label",     label_cmd},          /* label a tape */
86    {"mount",     mount_cmd},
87    {"unmount",   unmount_cmd},
88    {"status",    status_cmd},
89    {NULL,        NULL}                /* list terminator */
90 };
91
92
93 /* 
94  * Connection request. We accept connections either from the 
95  *  Director or a Client.
96  * 
97  * Note, we are running as a seperate thread of the Storage daemon.
98  *  and it is because a Director has made a connection with
99  *  us on the "Message" channel.    
100  *
101  * Basic tasks done here:  
102  *  - Create a JCR record
103  *  - Authenticate the Director
104  *  - We wait for a command
105  *  - We execute the command
106  *  - We continue or exit depending on the return status
107  */
108 void connection_request(void *arg)
109 {
110    BSOCK *bs = (BSOCK *)arg;
111    JCR *jcr;
112    int i, found, quit;
113    int bnet_stat = 0;
114    char name[MAX_NAME_LENGTH];
115
116    if (bnet_recv(bs) <= 0) {
117       Emsg0(M_ERROR, 0, "Connection request failed.\n");
118       return;
119    }
120
121    /* 
122     * See if this is a File daemon connection
123     */
124    if (sscanf(bs->msg, "Hello Start Job %127s calling\n", name) == 1) {
125       handle_filed_connection(bs, name);
126       return;
127    }
128    
129    jcr = new_jcr(sizeof(JCR), stored_free_jcr);     /* create Job Control Record */
130    jcr->dir_bsock = bs;               /* save Director bsock */
131
132    Dmsg0(1000, "stored in start_job\n");
133
134    /*
135     * Authenticate the Director
136     */
137    if (!authenticate_director(jcr)) {
138       Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate Director\n"));
139       free_jcr(jcr);
140       return;
141    }
142    Dmsg0(90, "Message channel init completed.\n");
143
144    for (quit=0; !quit;) {
145
146       /* Read command */
147       if ((bnet_stat = bnet_recv(bs)) <= 0) {
148          break;                       /* connection terminated */
149       }
150       Dmsg1(9, "<dird: %s\n", bs->msg);
151       found = FALSE;
152       for (i=0; cmds[i].cmd; i++) {
153          if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) {
154             if (!cmds[i].func(jcr)) {    /* do command */
155                quit = TRUE;              /* error, get out */
156                Dmsg1(90, "Command %s requsts quit\n", cmds[i].cmd);
157             }
158             found = TRUE;            /* indicate command found */
159             break;
160          }
161       }
162       if (!found) {                   /* command not found */
163          bnet_fsend(bs, derrmsg);
164          quit = TRUE;
165          break;
166       }
167    }
168    if (bnet_stat != BNET_TERMINATE) {
169       bnet_sig(bs, BNET_TERMINATE);
170    }
171    free_jcr(jcr);
172    return;
173 }
174
175 /*
176  * Set debug level as requested by the Director
177  *
178  */
179 static int setdebug_cmd(JCR *jcr)
180 {
181    BSOCK *dir = jcr->dir_bsock;
182    int level;
183
184    Dmsg1(10, "setdebug_cmd: %s", dir->msg);
185    if (sscanf(dir->msg, "setdebug=%d", &level) != 1 || level < 0) {
186       bnet_fsend(dir, "3991 Bad setdebug command: %s\n", dir->msg);
187       return 0;
188    }
189    debug_level = level;
190    return bnet_fsend(dir, OKsetdebug, level);
191 }
192
193
194 /*
195  * Cancel a Job
196  */
197 static int cancel_cmd(JCR *cjcr)
198 {
199    BSOCK *dir = cjcr->dir_bsock;
200    int oldStatus;
201    char Job[MAX_NAME_LENGTH];
202    JCR *jcr;
203
204    if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) {
205       if (!(jcr=get_jcr_by_full_name(Job))) {
206          bnet_fsend(dir, _("3992 Job %s not found.\n"), Job);
207       } else {
208          P(jcr->mutex);
209          oldStatus = jcr->JobStatus;
210          jcr->JobStatus = JS_Cancelled;
211          if (!jcr->authenticated && jcr->JobStatus == JS_WaitFD) {
212             pthread_cond_signal(&jcr->job_start_wait); /* wake waiting thread */
213          }
214          V(jcr->mutex);
215          if (jcr->file_bsock) {
216             bnet_sig(jcr->file_bsock, BNET_TERMINATE);
217          }
218          bnet_fsend(dir, _("3000 Job %s Status=%c marked to be cancelled.\n"), 
219             jcr->Job, oldStatus);
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);      /* autoload if possible */
328    block = new_block(dev);
329
330    /* See what we have for a Volume */
331    switch (read_dev_volume_label(jcr, dev, block)) {                
332       case VOL_NAME_ERROR:
333       case VOL_VERSION_ERROR:
334       case VOL_LABEL_ERROR:
335       case VOL_OK:
336          bnet_fsend(dir, _("3901 Cannot label Volume because it is \
337 already labeled: %s\n"), dev->VolHdr.VolName);
338          break;
339       case VOL_IO_ERROR:
340       case VOL_NO_LABEL:
341          write_volume_label_to_dev(jcr, jcr->device, vname, poolname);
342          strcpy(jcr->VolumeName, vname);
343          bnet_fsend(dir, _("3000 OK label. Volume=%s Device=%s\n"), 
344             vname, dev->dev_name);
345          break;
346       default:
347          bnet_fsend(dir, _("3902 Cannot label Volume. \
348 Unknown status %d from read_volume_label()\n"), jcr->label_status);
349          break;
350    }
351    free_block(block);
352    return_device_lock(dev, &hold);
353 }
354
355
356 /* 
357  * Read the tape label
358  *
359  *  Enter with the mutex set
360  */
361 static int read_label(JCR *jcr, DEVICE *dev)
362 {
363    int stat;
364    BSOCK *dir = jcr->dir_bsock;
365    DEV_BLOCK *block;
366 #ifndef NEW_LOCK
367    bsteal_lock_t hold;
368    
369    steal_device_lock(dev, &hold, BST_DOING_ACQUIRE);
370 #endif
371    
372    jcr->VolumeName[0] = 0;
373    block = new_block(dev);
374    dev->state &= ~ST_LABEL;           /* force read of label */
375    switch (read_dev_volume_label(jcr, dev, block)) {                
376       case VOL_OK:
377          bnet_fsend(dir, _("3001 Mounted Volume: %s\n"), dev->VolHdr.VolName);
378          stat = 1;
379          break;
380       default:
381          bnet_fsend(dir, _("3902 Cannot mount Volume on Storage Device \"%s\" because:\n%s\n"),
382             dev->dev_name, jcr->errmsg);
383          stat = 0;
384          break;
385    }
386    free_block(block);
387 #ifndef NEW_LOCK
388    return_device_lock(dev, &hold);
389 #endif
390    return stat;
391 }
392
393 /*
394  * Mount command from Director
395  */
396 static int mount_cmd(JCR *jcr)
397 {
398    char *dev_name;
399    BSOCK *dir = jcr->dir_bsock;
400    DEVRES *device;
401    DEVICE *dev;
402    int found = 0;
403
404    dev_name = (char *) get_memory(dir->msglen);
405    if (sscanf(dir->msg, "mount %s", dev_name) == 1) {
406       unbash_spaces(dev_name);
407       device = NULL;
408       LockRes();
409       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
410          /* Find resource, and make sure we were able to open it */
411          if (strcmp(device->hdr.name, dev_name) == 0 && device->dev) {
412             Dmsg1(20, "Found device %s\n", device->hdr.name);
413             found = 1;
414             break;
415          }
416       }
417       UnlockRes();
418       if (found) {
419          jcr->device = device;
420          dev = device->dev;
421          P(dev->mutex);               /* Use P to avoid indefinite block */
422          switch (dev->dev_blocked) {         /* device blocked? */
423             DEV_BLOCK *block;
424             case BST_WAITING_FOR_SYSOP:
425                /* Someone is waiting, wake him */
426                Dmsg0(90, "Waiting for mount attempt to wake thread\n");
427                pthread_cond_signal(&dev->wait_next_vol);
428                bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev->dev_name);
429                break;
430
431             case BST_UNMOUNTED_WAITING_FOR_SYSOP:
432             case BST_UNMOUNTED:
433                /* We freed the device, so reopen it and wake any waiting threads */
434                if (open_dev(dev, NULL, READ_WRITE) < 0) {
435                   bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
436                      strerror_dev(dev));
437                   break;
438                }
439                block = new_block(dev);
440                read_dev_volume_label(jcr, dev, block);
441                free_block(block);
442                if (dev->dev_blocked == BST_UNMOUNTED) {
443                   Dmsg0(90, "Unmounted unblocking device\n");
444                   read_label(jcr, dev);
445                   unblock_device(dev);
446                } else {
447                   Dmsg0(90, "Unmounted waiting for mount attempt to wake thread\n");
448                   dev->dev_blocked = BST_WAITING_FOR_SYSOP;
449                   pthread_cond_signal(&dev->wait_next_vol);
450                }
451                if (dev->state & ST_LABEL) {
452                   bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
453                      dev->dev_name, dev->VolHdr.VolName);
454                } else {
455                   bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
456                              dev->dev_name);
457                }
458                break;
459
460             case BST_DOING_ACQUIRE:
461                bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), 
462                           dev->dev_name);
463                break;
464
465             case BST_WRITING_LABEL:
466                bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev->dev_name);
467                break;
468
469             case BST_NOT_BLOCKED:
470                if (dev->state & ST_OPENED) {
471                   if (dev->state & ST_LABEL) {
472                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"),
473                         dev->dev_name, dev->VolHdr.VolName);
474                   } else {
475                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
476                                 dev->dev_name);
477                   }
478                } else {
479                   if (!dev_is_tape(dev)) {
480                      bnet_fsend(dir, _("3906 cannot mount non-tape.\n"));
481                      break;
482                   }
483                   if (open_dev(dev, NULL, READ_WRITE) < 0) {
484                      bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), 
485                         strerror_dev(dev));
486                      break;
487                   }
488                   read_label(jcr, dev);
489                   if (dev->state & ST_LABEL) {
490                      bnet_fsend(dir, _("3001 Device %s is mounted with Volume %s\n"), 
491                         dev->dev_name, dev->VolHdr.VolName);
492                   } else {
493                      bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n"), 
494                                 dev->dev_name);
495                   }
496                }
497                break;
498
499             default:
500                bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked);
501                break;
502          }
503          V(dev->mutex);
504       } else {
505          bnet_fsend(dir, _("3999 Device %s not found\n"), dev_name);
506       }
507    } else {
508       strcpy(dev_name, dir->msg);
509       bnet_fsend(dir, _("3906 Error scanning mount command: %s\n"), dev_name);
510    }
511    free_memory(dev_name);
512    bnet_sig(dir, BNET_EOD);
513    return 1;
514 }
515
516 /*
517  * unmount command from Director
518  */
519 static int unmount_cmd(JCR *jcr)
520 {
521    char *dname;
522    BSOCK *dir = jcr->dir_bsock;
523    DEVRES *device;
524    DEVICE *dev;
525    int found = 0;
526
527    dname = (char *) get_memory(dir->msglen+1);
528    if (sscanf(dir->msg, "unmount %s", dname) == 1) {
529       unbash_spaces(dname);
530       device = NULL;
531       LockRes();
532       while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) {
533          /* Find resource, and make sure we were able to open it */
534          if (strcmp(device->hdr.name, dname) == 0 && device->dev) {
535             Dmsg1(20, "Found device %s\n", device->hdr.name);
536             found = 1;
537             break;
538          }
539       }
540       UnlockRes();
541       if (found) {
542          jcr->device = device;
543          dev = device->dev;
544          P(dev->mutex);               /* Use P to avoid indefinite block */
545          if (!(dev->state & ST_OPENED)) {
546             Dmsg0(90, "Device already unmounted\n");
547             bnet_fsend(dir, _("3901 Device %s is already unmounted.\n"), dev_name(dev));
548
549          } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) {
550             Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
551                dev->dev_blocked);
552             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
553                offline_dev(dev);
554             }
555             force_close_dev(dev);
556             dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
557             bnet_fsend(dir, _("3001 Device %s unmounted.\n"), dev_name(dev));
558
559          } else if (dev->dev_blocked == BST_DOING_ACQUIRE) {
560             bnet_fsend(dir, _("3902 Device %s is busy in acquire.\n"),
561                dev_name(dev));
562
563          } else if (dev->dev_blocked == BST_WRITING_LABEL) {
564             bnet_fsend(dir, _("3903 Device %s is being labeled.\n"),
565                dev_name(dev));
566
567          } else if (dev->state & ST_READ || dev->num_writers) {
568             if (dev->state & ST_READ) {
569                 Dmsg0(90, "Device in read mode\n");
570                 bnet_fsend(dir, _("3904 Device %s is busy with 1 reader.\n"),
571                    dev_name(dev));
572             } else {
573                 Dmsg1(90, "Device busy with %d writers\n", dev->num_writers);
574                 bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"),
575                    dev_name(dev), dev->num_writers);
576             }
577
578          } else {                     /* device not being used */
579             Dmsg0(90, "Device not in use, unmounting\n");
580             block_device(dev, BST_UNMOUNTED);
581             if (dev->capabilities & CAP_OFFLINEUNMOUNT) {
582                offline_dev(dev);
583             }
584             force_close_dev(dev);
585             bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev));
586          }
587          V(dev->mutex);
588       } else {
589          bnet_fsend(dir, _("3999 Device %s not found\n"), dname);
590       }
591    } else {
592       /* NB dir->msg gets clobbered in bnet_fsend, so save command */
593       strcpy(dname, dir->msg);
594       bnet_fsend(dir, _("3907 Error scanning unmount command: %s\n"), dname);
595    }
596    free_memory(dname);
597    bnet_sig(dir, BNET_EOD);
598    return 1;
599 }
600
601 /*
602  * Status command from Director
603  */
604 static int status_cmd(JCR *jcr)
605 {
606    DEVRES *device;
607    DEVICE *dev;
608    int found, bps, sec, bpb;
609    BSOCK *user = jcr->dir_bsock;
610    char dt[MAX_TIME_LENGTH];
611    char b1[30], b2[30], b3[30];
612
613    bnet_fsend(user, "\n%s Version: " VERSION " (" DATE ")\n", my_name);
614    bstrftime(dt, sizeof(dt), daemon_start_time);
615    bnet_fsend(user, _("Daemon started %s, %d Job%s run.\n"), dt, last_job.NumJobs,
616         last_job.NumJobs == 1 ? "" : "s");
617    if (last_job.NumJobs > 0) {
618       char termstat[30];
619
620       bstrftime(dt, sizeof(dt), last_job.end_time);
621       bnet_fsend(user, _("Last Job %s finished at %s\n"), last_job.Job, dt);
622
623       jobstatus_to_ascii(last_job.JobStatus, termstat, sizeof(termstat));
624       bnet_fsend(user, _("  Files=%s Bytes=%s Termination Status=%s\n"), 
625            edit_uint64_with_commas(last_job.JobFiles, b1),
626            edit_uint64_with_commas(last_job.JobBytes, b2),
627            termstat);
628    }
629
630    LockRes();
631    for (device=NULL;  (device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device)); ) {
632       dev = device->dev;
633       if (dev) {
634          if (dev->state & ST_OPENED) {
635             if (dev->state & ST_LABEL) {
636                bnet_fsend(user, _("Device %s is mounted with Volume %s\n"), 
637                   dev_name(dev), dev->VolHdr.VolName);
638             } else {
639                bnet_fsend(user, _("Device %s open but no Bacula volume is mounted.\n"), dev_name(dev));
640             }
641             switch (dev->dev_blocked) {
642                case BST_UNMOUNTED:
643                   bnet_fsend(user, _("    Deviced is blocked. User unmounted.\n"));
644                   break;
645                case BST_UNMOUNTED_WAITING_FOR_SYSOP:
646                   bnet_fsend(user, _("    Deviced is blocked. User unmounted during wait for media/mount.\n"));
647                   break;
648                case BST_WAITING_FOR_SYSOP:
649                   if (jcr->JobStatus == JS_WaitMount) {
650                      bnet_fsend(user, _("    Device is blocked waiting for mount.\n"));
651                   } else {
652                      bnet_fsend(user, _("    Device is blocked waiting for appendable media.\n"));
653                   }
654                   break;
655                case BST_DOING_ACQUIRE:
656                   bnet_fsend(user, _("    Device is being initialized.\n"));
657                   break;
658                case BST_WRITING_LABEL:
659                   bnet_fsend(user, _("    Device is blocked labeling a Volume.\n"));
660                   break;
661                default:
662                   break;
663             }
664             bpb = dev->VolCatInfo.VolCatBlocks;
665             if (bpb <= 0) {
666                bpb = 1;
667             }
668             bpb = dev->VolCatInfo.VolCatBytes / bpb;
669             bnet_fsend(user, _("    Total Bytes=%s Blocks=%s Bytes/block=%s\n"),
670                edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1),
671                edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), 
672                edit_uint64_with_commas(bpb, b3));
673             bnet_fsend(user, _("    Positioned at File=%s Block=%s\n"), 
674                edit_uint64_with_commas(dev->file, b1),
675                edit_uint64_with_commas(dev->block_num, b2));
676
677          } else {
678             bnet_fsend(user, _("Device %s is not open.\n"), dev_name(dev));
679          }
680       }
681    }
682    UnlockRes();
683
684    found = 0;
685    lock_jcr_chain();
686    /* NOTE, we reuse a calling argument jcr. Be warned! */ 
687    for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
688       if (jcr->JobStatus == JS_WaitFD) {
689          bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"),
690             job_type_to_str(jcr->JobType), jcr->Job);
691       }
692       if (jcr->device) {
693          bnet_fsend(user, _("%s %s job %s is using device %s\n"), 
694                    job_level_to_str(jcr->JobLevel),
695                    job_type_to_str(jcr->JobType),
696                    jcr->Job, jcr->device->device_name);
697          sec = time(NULL) - jcr->run_time;
698          if (sec <= 0) {
699             sec = 1;
700          }
701          bps = jcr->JobBytes / sec;
702          bnet_fsend(user, _("    Files=%s Bytes=%s Bytes/sec=%s\n"), 
703             edit_uint64_with_commas(jcr->JobFiles, b1),
704             edit_uint64_with_commas(jcr->JobBytes, b2),
705             edit_uint64_with_commas(bps, b3));
706          found = 1;
707 #ifdef DEBUG
708          if (jcr->file_bsock) {
709             bnet_fsend(user, "    FDReadSeqNo=%" lld " fd=%d\n", 
710                jcr->file_bsock->read_seqno, jcr->file_bsock->fd);
711          } else {
712             bnet_fsend(user, "    FDSocket closed\n");
713          }
714 #endif
715       }
716       free_locked_jcr(jcr);
717    }
718    unlock_jcr_chain();
719    if (!found) {
720       bnet_fsend(user, _("No jobs running.\n"));
721    }
722
723 #ifdef full_status
724    bnet_fsend(user, "\n\n");
725    dump_resource(R_DEVICE, resources[R_DEVICE-r_first].res_head, sendit, user);
726 #endif
727    bnet_fsend(user, "====\n");
728
729    bnet_sig(user, BNET_EOD);
730    return 1;
731 }