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