lintian doesn't like orphan packages with uploaders...
[debian/amanda] / ndmp-src / ndma_cops_backreco.c
1 /*
2  * Copyright (c) 1998,1999,2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  */
36
37
38 #include "ndmagents.h"
39 #include "util.h"
40
41
42 #ifndef NDMOS_OPTION_NO_CONTROL_AGENT
43
44 int ndmca_monitor_backup_tape_tcp (struct ndm_session *sess);
45 int ndmca_monitor_recover_tape_tcp (struct ndm_session *sess);
46 int ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess);
47
48 int
49 ndmca_op_create_backup (struct ndm_session *sess)
50 {
51         struct ndm_control_agent *ca = &sess->control_acb;
52         int                     rc;
53
54         ca->tape_mode = NDMP9_TAPE_RDWR_MODE;
55         ca->mover_mode = NDMP9_MOVER_MODE_READ;
56         ca->is_label_op = 0;
57
58         rc = ndmca_backreco_startup (sess);
59         if (rc) return rc;
60
61         rc = ndmca_data_start_backup (sess);
62         if (rc == 0) {
63             rc = ndmca_monitor_startup (sess);
64             if (rc == 0) {
65                 rc = ndmca_monitor_backup (sess);
66             }
67         }
68
69         if (rc == 0)
70             rc = ndmca_monitor_shutdown (sess);
71         else
72             ndmca_monitor_shutdown (sess);
73
74         ndmca_media_tattle (sess);
75
76         return rc;
77 }
78
79 int
80 ndmca_op_recover_files (struct ndm_session *sess)
81 {
82         struct ndm_control_agent *ca = &sess->control_acb;
83         int                     rc;
84
85         ca->tape_mode = NDMP9_TAPE_READ_MODE;
86         ca->mover_mode = NDMP9_MOVER_MODE_WRITE;
87         ca->is_label_op = 0;
88
89         rc = ndmca_backreco_startup (sess);
90         if (rc) return rc;
91
92         rc = ndmca_data_start_recover (sess);
93         if (rc == 0) {
94                 rc = ndmca_monitor_startup (sess);
95                 if (rc == 0) {
96                         rc = ndmca_monitor_recover (sess);
97                 }
98         }
99
100         if (rc == 0)
101             rc = ndmca_monitor_shutdown (sess);
102         else
103             ndmca_monitor_shutdown (sess);
104
105         if (rc == 0) {
106             if (ca->recover_log_file_count > 0) {
107                 struct ndm_control_agent *ca = &sess->control_acb;
108                 int                 n_nlist = ca->job.nlist_tab.n_nlist;
109
110                 ndmalogf (sess, 0, 0,
111                           "LOG_FILE messages: %d OK, %d ERROR, total %d of %d",
112                           ca->recover_log_file_ok,
113                           ca->recover_log_file_error,
114                           ca->recover_log_file_count,
115                           n_nlist);
116                 if (ca->recover_log_file_ok < n_nlist) {
117                     rc = 1;
118                 }
119             } else {
120                 ndmalogf (sess, 0, 1,
121                           "DATA did not report any LOG_FILE messages");
122             }
123         }
124
125         if(!ca->job.tape_tcp)
126                 ndmca_media_tattle (sess);
127
128         return rc;
129 }
130
131 int
132 ndmca_op_recover_fh (struct ndm_session *sess)
133 {
134         struct ndm_control_agent *ca = &sess->control_acb;
135         int                     rc;
136
137         ca->tape_mode = NDMP9_TAPE_READ_MODE;
138         ca->mover_mode = NDMP9_MOVER_MODE_WRITE;
139         ca->is_label_op = 0;
140
141         rc = ndmca_backreco_startup (sess);
142         if (rc) return rc;
143
144         rc = ndmca_data_start_recover_filehist (sess);
145         if (rc == 0) {
146                 rc = ndmca_monitor_startup (sess);
147                 if (rc == 0) {
148                         rc = ndmca_monitor_recover (sess);
149                 }
150         }
151
152         if (rc == 0)
153             rc = ndmca_monitor_shutdown (sess);
154         else
155             ndmca_monitor_shutdown (sess);
156
157         ndmca_media_tattle (sess);
158
159         return rc;
160 }
161
162 char *ndmca_data_est(struct ndm_control_agent *ca)
163 {
164     char *estb;
165     static char estb_buf[64];
166
167     estb = 0;
168     if (ca->data_state.est_bytes_remain.valid &&
169         (ca->data_state.est_bytes_remain.value >= 1024)) {
170         snprintf(estb_buf,
171                  sizeof (estb_buf),
172                  " left %lldKB",
173                  ca->data_state.est_bytes_remain.value/1024LL);
174         estb = estb_buf;
175     }
176
177     return estb;
178 }
179
180 int
181 ndmca_monitor_backup (struct ndm_session *sess)
182 {
183         struct ndm_control_agent *ca = &sess->control_acb;
184         int                     count;
185         ndmp9_data_state        ds;
186         ndmp9_mover_state       ms;
187         char *estb;
188
189         if (ca->job.tape_tcp) {
190                 return ndmca_monitor_backup_tape_tcp(sess);
191         }
192
193         ndmalogf (sess, 0, 3, "Monitoring backup");
194
195         for (count = 0; count < 10; count++) {
196                 ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
197                 if (ndmca_monitor_get_states(sess) < 0)
198                     break;
199
200 #if 0
201                 if (count > 2)
202                         ndmca_mon_show_states(sess);
203 #endif
204
205                 ds = ca->data_state.state;
206                 ms = ca->mover_state.state;
207
208                 estb = ndmca_data_est(ca);
209
210                 ndmalogf (sess, 0, 1,
211                           "DATA: bytes %lldKB%s  MOVER: written %lldKB record %d",
212                           ca->data_state.bytes_processed/1024LL,
213                           estb ? estb : "",
214                           ca->mover_state.bytes_moved/1024LL,
215                           ca->mover_state.record_num);
216
217                 if (ds == NDMP9_DATA_STATE_ACTIVE
218                  && ms == NDMP9_MOVER_STATE_ACTIVE) {
219                         count = 0;
220                         continue;
221                 }
222
223                 /*
224                  * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE.
225                  * Have to do this before checking DATA. Even if DATA halted,
226                  * MOVER may be holding unwritten data. Have to perform
227                  * the tape change.
228                  */
229                 if (ms == NDMP9_MOVER_STATE_PAUSED) {
230                         ndmp9_mover_pause_reason        pr;
231
232                         pr = ca->mover_state.pause_reason;
233
234                         if (!ca->pending_notify_mover_paused) {
235                                 /* count=count */
236                                 continue;               /* wait for notice */
237                         }
238
239                         ca->pending_notify_mover_paused = 0;
240
241                         ndmalogf (sess, 0, 3, "Mover paused, reason=%s",
242                                         ndmp9_mover_pause_reason_to_str (pr));
243
244                         /* backups are different then recoverys... When
245                          * we reach the end of a window, we signal EOW
246                          * except in V2 where we signal EOF. EOM occurs
247                          * at EOT (or EOF does).
248                          * This is based on reading comments in the email
249                          * archives...
250                          */
251                         if ((pr == NDMP9_MOVER_PAUSE_EOM) ||
252                             (pr == NDMP9_MOVER_PAUSE_EOW)) {
253                                 if (ndmca_monitor_load_next(sess) == 0) {
254                                         /* count=count */
255                                         continue;       /* Happy */
256                                 }
257                                 /* Something went wrong with tape change. */
258                         } else if ((sess->plumb.tape->protocol_version <= 2) &&
259                                    pr == NDMP9_MOVER_PAUSE_EOF) {
260                                 if (ndmca_monitor_load_next(sess) == 0) {
261                                         /* count=count */
262                                         continue;       /* Happy */
263                                 }
264                                 /* Something went wrong with tape change. */
265                         } else {
266                                 /* All other pause reasons
267                                  * are critically bogus. */
268
269                         }
270                         ndmalogf (sess, 0, 0,
271                                 "Operation paused w/o remedy, cancelling");
272                         ndmca_mover_abort (sess);
273                         return -1;
274                 }
275
276                 /*
277                  * If DATA has halted, the show is over.
278                  */
279                 if (ds == NDMP9_DATA_STATE_HALTED) {
280                         if (ms != NDMP9_MOVER_STATE_HALTED) {
281                                 ndmalogf (sess, 0, 3,
282                                         "DATA halted, MOVER active");
283                                 /*
284                                  * MOVER still occupied. It might be a
285                                  * heartbeat away from asking for another
286                                  * tape. Give it a chance.
287                                  */
288                                 continue;
289                         }
290
291                         ndmalogf (sess, 0, 2, "Operation done, cleaning up");
292
293                         ndmca_monitor_get_post_backup_env (sess);
294
295                         return 0;
296                 }
297 #if 1
298                 if (ms == NDMP9_MOVER_STATE_HALTED) {
299                         if (ds == NDMP9_DATA_STATE_ACTIVE) {
300                                 ndmalogf (sess, 0, 3,
301                                         "MOVER halted, DATA active");
302                                 /*
303                                  * DATA still occupied.
304                                  */
305                                 continue;
306                         }
307                 }
308 #endif
309
310                 if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) {
311                         /* Not active. Not paused. Something wrong */
312                         ndmalogf (sess, 0, 0,
313                                 "Operation in unreasonable state, cancelling");
314                         return -1;
315                 }
316         }
317
318         ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
319         return -1;
320 }
321
322 int
323 ndmca_monitor_backup_tape_tcp (struct ndm_session *sess)
324 {
325         struct ndm_control_agent *ca = &sess->control_acb;
326         int                     count;
327         ndmp9_data_state        ds;
328         char *estb;
329         struct ndmlog *         ixlog = &ca->job.index_log;
330         char *                  pname = get_pname();
331
332         ndmalogf (sess, 0, 3, "Monitoring backup");
333
334         for (count = 0; count < 10; count++) {
335                 ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
336                 if (ndmca_monitor_get_states(sess) < 0)
337                     break;
338
339 #if 0
340                 if (count > 2)
341                         ndmca_mon_show_states(sess);
342 #endif
343
344                 ds = ca->data_state.state;
345
346                 estb = ndmca_data_est(ca);
347
348                 ndmalogf (sess, 0, 1,
349                           "DATA: bytes %lldKB%s",
350                           ca->data_state.bytes_processed/1024LL,
351                           estb ? estb : "");
352
353                 if (strcmp(pname, "amndmjob") == 0) {
354                         ndmlogf (ixlog, "DATA SIZE", 0, "%lldKB",
355                                  ca->data_state.bytes_processed/1024LL);
356                 }
357
358                 if (ds == NDMP9_DATA_STATE_ACTIVE) {
359                         count = 0;
360                         continue;
361                 }
362
363                 /*
364                  * If DATA has halted, the show is over.
365                  */
366                 if (ds == NDMP9_DATA_STATE_HALTED) {
367                         ndmalogf (sess, 0, 2, "Operation done, cleaning up");
368
369                         ndmca_monitor_get_post_backup_env (sess);
370
371                         return 0;
372                 }
373         }
374
375         ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
376         return -1;
377 }
378
379 int
380 ndmca_monitor_get_post_backup_env (struct ndm_session *sess)
381 {
382         struct ndm_control_agent *ca = &sess->control_acb;
383         struct ndmlog *         ixlog = &ca->job.index_log;
384         int                     rc, i;
385         ndmp9_pval *            pv;
386
387         rc = ndmca_data_get_env (sess);
388         if (rc && ca->data_state.error == NDMP9_ILLEGAL_STATE_ERR) {
389                 ndmalogf (sess, 0, 2, "fetch post backup env failed");
390                 return 0;
391         }
392         if (rc) {
393                 ndmalogf (sess, 0, 0, "fetch post backup env failed");
394                 return -1;
395         }
396
397         for (i = 0; i < ca->job.result_env_tab.n_env; i++) {
398                 pv = &ca->job.result_env_tab.env[i];
399
400                 ndmlogf (ixlog, "DE", 0, "%s=%s", pv->name, pv->value);
401         }
402
403         return 0;
404 }
405
406 int
407 ndmca_monitor_recover (struct ndm_session *sess)
408 {
409         struct ndm_control_agent *ca = &sess->control_acb;
410         int                     count, rc;
411         ndmp9_data_state        ds;
412         ndmp9_mover_state       ms;
413         char *estb;
414         int last_state_print = 0;
415
416         if (ca->job.tape_tcp) {
417                 return (ndmca_monitor_recover_tape_tcp(sess));
418         }
419
420         ndmalogf (sess, 0, 3, "Monitoring recover");
421
422         for (count = 0; count < 10; count++) {
423                 if (ca->pending_notify_data_read) {
424                         ca->pending_notify_data_read = 0;
425
426                         rc = ndmca_mover_read (sess,
427                                 ca->last_notify_data_read.offset,
428                                 ca->last_notify_data_read.length);
429                         if (rc) {
430                                 ndmalogf (sess, 0, 0, "data-read failed");
431                                 return -1;
432                         }
433                         if (count < 5)
434                                 continue;
435                 }
436
437                 ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
438
439                 if (ndmca_monitor_get_states(sess) < 0)
440                     break;
441
442 #if 0
443                 if (count > 2)
444                         ndmca_mon_show_states(sess);
445 #endif
446
447                 ds = ca->data_state.state;
448                 ms = ca->mover_state.state;
449
450                 estb = ndmca_data_est(ca);
451
452                 if ((ds != NDMP9_DATA_STATE_ACTIVE) ||
453                     (ms != NDMP9_MOVER_STATE_ACTIVE) ||
454                     ((time(0) - last_state_print) >= 5)) {
455
456                     ndmalogf (sess, 0, 1,
457                               "DATA: bytes %lldKB%s  MOVER: read %lldKB record %d",
458                               ca->data_state.bytes_processed/1024LL,
459                               estb ? estb : "",
460                               ca->mover_state.bytes_moved/1024LL,
461                               ca->mover_state.record_num);
462                     last_state_print = time(0);
463                 }
464
465                 if (ds == NDMP9_DATA_STATE_ACTIVE
466                  && ms == NDMP9_MOVER_STATE_ACTIVE) {
467                         count = 0;
468                         continue;
469                 }
470
471                 /*
472                  * Check MOVER for needed tape change during DATA_FLOW_TO_TAPE.
473                  * Have to do this before checking DATA. Even if DATA halted,
474                  * MOVER may be holding unwritten data. Have to perform
475                  * the tape change.
476                  */
477                 if (ms == NDMP9_MOVER_STATE_PAUSED) {
478                         ndmp9_mover_pause_reason        pr;
479
480                         pr = ca->mover_state.pause_reason;
481
482                         if (!ca->pending_notify_mover_paused) {
483                                 /* count=count */
484                                 continue;               /* wait for notice */
485                         }
486
487                         ca->pending_notify_mover_paused = 0;
488
489                         ndmalogf (sess, 0, 3, "Mover paused, reason=%s",
490                                         ndmp9_mover_pause_reason_to_str (pr));
491
492                         if (((pr == NDMP9_MOVER_PAUSE_EOF) ||
493                              (pr == NDMP9_MOVER_PAUSE_SEEK))
494                             && (ca->cur_media_ix+1 == ca->job.media_tab.n_media)) {
495                                 /*
496                                  * Last tape consumed by tape agent.
497                                  * The DATA agent may be just shy
498                                  * of done, but there is no way for
499                                  * us to tell. So, close the
500                                  * image stream from the TAPE
501                                  * agent side, thus indicating
502                                  * EOF to the DATA agent.
503                                  */
504                                 ndmalogf (sess, 0, 2, "End of tapes");
505                                 ndmca_mover_close (sess);
506                                 /* count=count */
507                                 continue;
508                         }
509
510                         if (pr == NDMP9_MOVER_PAUSE_EOM
511                          || pr == NDMP9_MOVER_PAUSE_EOF) {
512                                 if (ndmca_monitor_load_next(sess) == 0) {
513                                         /* count=count */
514                                         continue;       /* Happy */
515                                 }
516                                 /* Something went wrong with tape change. */
517                         } else if (pr == NDMP9_MOVER_PAUSE_SEEK) {
518                                 if (ndmca_monitor_seek_tape(sess) == 0) {
519                                         /* count=count */
520                                         continue;       /* Happy */
521                                 }
522                                 /* Something went wrong with tape change. */
523                         } else {
524                                 /* All other pause reasons
525                                  * are critically bogus. */
526                         }
527                         ndmalogf (sess, 0, 0,
528                                 "Operation paused w/o remedy, cancelling");
529                         ndmca_mover_abort (sess);
530                         return -1;
531                 }
532
533                 /*
534                  * If DATA has halted, the show is over.
535                  */
536                 if (ds == NDMP9_DATA_STATE_HALTED) {
537                         if (ms != NDMP9_MOVER_STATE_HALTED) {
538                                 ndmalogf (sess, 0, 3,
539                                         "DATA halted, MOVER active");
540                                 /*
541                                  * MOVER still occupied. It might
542                                  * figure it out. Then again, it might
543                                  * be awaiting a MOVER_READ. The NDMP
544                                  * design does not provide a state
545                                  * for awaiting MOVER_READ, so we have
546                                  * to guess.
547                                  */
548                                 if (count > 0) {
549                                         ndmca_mover_close(sess);
550                                 }
551                                 continue;
552                         }
553
554                         ndmalogf (sess, 0, 2, "Operation done, cleaning up");
555
556                         ndmca_monitor_get_post_backup_env (sess);
557
558                         return 0;
559                 }
560
561                 if (ms != NDMP9_MOVER_STATE_ACTIVE && count == 0) {
562                         /* Not active. Not paused. Something wrong */
563                         ndmalogf (sess, 0, 0,
564                                 "Operation in unreasonable state, cancelling");
565                         return -1;
566                 }
567         }
568
569         ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
570         return -1;
571 }
572
573
574 int
575 ndmca_monitor_recover_tape_tcp (struct ndm_session *sess)
576 {
577         struct ndm_control_agent *ca = &sess->control_acb;
578         int                     count;
579         ndmp9_data_state        ds;
580         char *estb;
581         int last_state_print = 0;
582
583         ndmalogf (sess, 0, 3, "Monitoring recover");
584
585         for (count = 0; count < 10; count++) {
586
587                 ndmca_mon_wait_for_something (sess, count <= 1 ? 30 : 10);
588
589                 if (ndmca_monitor_get_states(sess) < 0)
590                     break;
591
592 #if 0
593                 if (count > 2)
594                         ndmca_mon_show_states(sess);
595 #endif
596
597                 ds = ca->data_state.state;
598
599                 estb = ndmca_data_est(ca);
600
601                 if ((ds != NDMP9_DATA_STATE_ACTIVE) ||
602                     ((time(0) - last_state_print) >= 5)) {
603
604                     ndmalogf (sess, 0, 1,
605                               "DATA: bytes %lldKB%s  MOVER: read %lldKB record %d",
606                               ca->data_state.bytes_processed/1024LL,
607                               estb ? estb : "",
608                               ca->mover_state.bytes_moved/1024LL,
609                               ca->mover_state.record_num);
610                     last_state_print = time(0);
611                 }
612
613                 if (ds == NDMP9_DATA_STATE_ACTIVE) {
614                         count = 0;
615                         continue;
616                 }
617
618                 /*
619                  * If DATA has halted, the show is over.
620                  */
621                 if (ds == NDMP9_DATA_STATE_HALTED) {
622                         ndmalogf (sess, 0, 2, "Operation done, cleaning up");
623
624                         ndmca_monitor_get_post_backup_env (sess);
625
626                         return 0;
627                 }
628
629         }
630
631         ndmalogf (sess, 0, 0, "Operation monitoring mishandled, cancelling");
632         return -1;
633 }
634
635
636 int
637 ndmca_backreco_startup (struct ndm_session *sess)
638 {
639         struct ndm_control_agent *ca = &sess->control_acb;
640         int                     rc = 0;
641
642         if (!ca->job.tape_tcp)
643                 rc = ndmca_op_robot_startup (sess, 1);
644         if (rc) return rc;
645
646         rc = ndmca_connect_data_agent(sess);
647         if (rc) {
648                 ndmconn_destruct (sess->plumb.data);
649                 return rc;
650         }
651
652         if (ca->job.tape_tcp) {
653                 return 0;
654         }
655
656         rc = ndmca_connect_tape_agent(sess);
657         if (rc) {
658                 ndmconn_destruct (sess->plumb.tape);
659                 return rc;
660         }
661
662         rc = ndmca_mover_set_record_size (sess);
663         if (rc) return rc;
664
665         rc = ndmca_media_load_first (sess);
666         if (rc) return rc;
667
668         ndmca_media_calculate_offsets (sess);
669
670         if (sess->control_acb.swap_connect &&
671             (sess->plumb.tape->protocol_version >= 3)) {
672             if (sess->plumb.tape->protocol_version < 4) {
673                 rc = ndmca_data_listen (sess);
674                 if (rc) return rc;
675
676                 rc = ndmca_media_set_window_current (sess);
677                 if (rc) return rc;
678             } else {
679                 rc = ndmca_media_set_window_current (sess);
680                 if (rc) return rc;
681
682                 rc = ndmca_data_listen (sess);
683                 if (rc) return rc;
684             }
685         } else {
686             if (sess->plumb.tape->protocol_version < 4) {
687                 rc = ndmca_mover_listen (sess);
688                 if (rc) return rc;
689
690                 rc = ndmca_media_set_window_current (sess);
691                 if (rc) return rc;
692             } else {
693                 rc = ndmca_media_set_window_current (sess);
694                 if (rc) return rc;
695
696                 rc = ndmca_mover_listen (sess);
697                 if (rc) return rc;
698             }
699         }
700
701         return 0;
702 }
703
704 int
705 ndmca_monitor_startup (struct ndm_session *sess)
706 {
707         struct ndm_control_agent *ca = &sess->control_acb;
708         ndmp9_data_state        ds;
709         ndmp9_mover_state       ms;
710         int                     count;
711
712         ndmalogf (sess, 0, 3, "Waiting for operation to start");
713
714         if (ca->job.tape_tcp)
715                 return 0;
716
717         for (count = 0; count < 10; count++) {
718                 if (ndmca_monitor_get_states (sess) < 0)
719                     break;
720
721                 ds = ca->data_state.state;
722                 if (!ca->job.tape_tcp)
723                         ms = ca->mover_state.state;
724                 else
725                         ms = NDMP9_MOVER_STATE_ACTIVE;
726
727                 if (ds == NDMP9_DATA_STATE_ACTIVE
728                  && ms == NDMP9_MOVER_STATE_ACTIVE) {
729                         ndmalogf (sess, 0, 1, "Operation started");
730                         return 0;
731                 }
732
733                 if (ds == NDMP9_DATA_STATE_HALTED
734                     && ms == NDMP9_MOVER_STATE_HALTED) {
735                         /* operation finished immediately */
736                         return 0;
737                 }
738
739                 if (ds != NDMP9_DATA_STATE_IDLE
740                  && ms != NDMP9_MOVER_STATE_IDLE
741                  && ms != NDMP9_MOVER_STATE_LISTEN) {
742                         ndmalogf (sess, 0, 1,
743                                   "Operation started in unusual fashion");
744                         return 0;
745                 }
746
747                 ndmca_mon_wait_for_something (sess, 2);
748         }
749
750         ndmalogf (sess, 0, 0, "Operation failed to start");
751         return -1;
752 }
753
754 /*
755  * Just make sure things get finished
756  */
757 int
758 ndmca_monitor_shutdown (struct ndm_session *sess)
759 {
760         struct ndm_control_agent *ca = &sess->control_acb;
761         ndmp9_data_state        ds;
762         ndmp9_data_halt_reason  dhr;
763         ndmp9_mover_state       ms;
764         ndmp9_mover_halt_reason mhr;
765         int                     count;
766         int                     finish;
767
768         if (ca->job.tape_tcp) {
769                 return ndmca_monitor_shutdown_tape_tcp(sess);
770         }
771         ndmalogf (sess, 0, 3, "Waiting for operation to halt");
772
773         for (count = 0; count < 10; count++) {
774                 ndmca_mon_wait_for_something (sess, 2);
775
776                 if (ndmca_monitor_get_states (sess) < 0)
777                     break;
778
779 #if 0
780                 if (count > 2)
781                         ndmca_mon_show_states(sess);
782 #endif
783
784                 ds = ca->data_state.state;
785                 ms = ca->mover_state.state;
786
787                 if (ds == NDMP9_DATA_STATE_HALTED
788                  && ms == NDMP9_MOVER_STATE_HALTED) {
789                         dhr = ca->data_state.halt_reason;
790                         mhr = ca->mover_state.halt_reason;
791                         break;
792                 }
793
794                 if (count > 2) {
795                         if (ds != NDMP9_DATA_STATE_HALTED)
796                                 ndmca_data_abort(sess);
797                         if (ms != NDMP9_MOVER_STATE_HALTED)
798                                 ndmca_mover_abort(sess);
799                 }
800         }
801
802         if (ca->tape_state.error == NDMP9_NO_ERR) {
803                 ndmca_monitor_unload_last_tape (sess);
804         }
805
806         if (count >= 10) {
807                 ndmalogf (sess, 0, 0,
808                         "Operation did not halt, something wrong");
809         }
810
811         ndmalogf (sess, 0, 2, "Operation halted, stopping");
812
813         ds = ca->data_state.state;
814         ms = ca->mover_state.state;
815         dhr = ca->data_state.halt_reason;
816         mhr = ca->mover_state.halt_reason;
817
818         if ((ds == NDMP9_DATA_STATE_HALTED)
819             && (ms == NDMP9_MOVER_STATE_HALTED)) {
820             if ((dhr == NDMP9_DATA_HALT_SUCCESSFUL) &&
821                 (mhr == NDMP9_MOVER_HALT_CONNECT_CLOSED)) {
822                 /* Successful operation */
823                 ndmalogf (sess, 0, 0, "Operation ended OKAY");
824                 finish = 0;
825             } else {
826                 /* Questionable success */
827                 ndmalogf (sess, 0, 0, "Operation ended questionably");
828                 finish = 1;
829             }
830         } else {
831             ndmalogf (sess, 0, 0, "Operation ended in failure");
832             finish = -1;
833         }
834
835         ndmca_data_stop (sess);
836         ndmca_mover_stop (sess);
837
838         for (count = 0; count < 10; count++) {
839                 if (ndmca_monitor_get_states(sess) < 0)
840                     break;
841
842 #if 0
843                 if (count > 2)
844                         ndmca_mon_show_states(sess);
845 #endif
846
847                 ds = ca->data_state.state;
848                 ms = ca->mover_state.state;
849
850                 if (ds == NDMP9_DATA_STATE_IDLE
851                  && ms == NDMP9_MOVER_STATE_IDLE) {
852                         break;
853                 }
854         }
855
856         if (count >= 10) {
857                 ndmalogf (sess, 0, 0,
858                         "Operation did not stop, something wrong");
859                 return -1;
860         }
861
862         return finish;
863 }
864
865 int
866 ndmca_monitor_shutdown_tape_tcp (struct ndm_session *sess)
867 {
868         struct ndm_control_agent *ca = &sess->control_acb;
869         ndmp9_data_state        ds;
870         ndmp9_data_halt_reason  dhr;
871         int                     count;
872         int                     finish;
873
874         ndmalogf (sess, 0, 3, "Waiting for operation to halt");
875
876         for (count = 0; count < 10; count++) {
877                 ndmca_mon_wait_for_something (sess, 2);
878
879                 if (ndmca_monitor_get_states (sess) < 0)
880                     break;
881
882 #if 0
883                 if (count > 2)
884                         ndmca_mon_show_states(sess);
885 #endif
886
887                 ds = ca->data_state.state;
888
889                 if (ds == NDMP9_DATA_STATE_HALTED) {
890                         dhr = ca->data_state.halt_reason;
891                         break;
892                 }
893
894                 if (count > 2) {
895                         if (ds != NDMP9_DATA_STATE_HALTED)
896                                 ndmca_data_abort(sess);
897                 }
898         }
899
900         if (count >= 10) {
901                 ndmalogf (sess, 0, 0,
902                         "Operation did not halt, something wrong");
903         }
904
905         ndmalogf (sess, 0, 2, "Operation halted, stopping");
906
907         ds = ca->data_state.state;
908         dhr = ca->data_state.halt_reason;
909
910         if (ds == NDMP9_DATA_STATE_HALTED) {
911             if (dhr == NDMP9_DATA_HALT_SUCCESSFUL) {
912                 /* Successful operation */
913                 ndmalogf (sess, 0, 0, "Operation ended OKAY");
914                 finish = 0;
915             } else {
916                 /* Questionable success */
917                 ndmalogf (sess, 0, 0, "Operation ended questionably");
918                 finish = 1;
919             }
920         } else {
921             ndmalogf (sess, 0, 0, "Operation ended in failure");
922             finish = -1;
923         }
924
925         ndmca_data_stop (sess);
926
927         for (count = 0; count < 10; count++) {
928                 if (ndmca_monitor_get_states(sess) < 0)
929                     break;
930
931 #if 0
932                 if (count > 2)
933                         ndmca_mon_show_states(sess);
934 #endif
935
936                 ds = ca->data_state.state;
937
938                 if (ds == NDMP9_DATA_STATE_IDLE) {
939                         break;
940                 }
941         }
942
943         if (count >= 10) {
944                 ndmalogf (sess, 0, 0,
945                         "Operation did not stop, something wrong");
946                 return -1;
947         }
948
949         return finish;
950 }
951
952 int
953 ndmca_monitor_get_states (struct ndm_session *sess)
954 {
955         struct ndm_control_agent *ca = &sess->control_acb;
956         int rc = 0;
957
958         if (ndmca_data_get_state (sess) < 0)
959             rc = -1;
960         if (!ca->job.tape_tcp) {
961             if (ndmca_mover_get_state (sess) < 0)
962                 rc = -1;
963             ndmca_tape_get_state_no_tattle (sess);
964         }
965
966         return rc;
967 }
968
969 int
970 ndmca_monitor_load_next (struct ndm_session *sess)
971 {
972         struct ndm_control_agent *ca = &sess->control_acb;
973         int                     rc;
974
975         ndmalogf (sess, 0, 1, "Operation requires next tape");
976
977         ndmca_media_capture_mover_window (sess);
978         ndmca_media_calculate_offsets (sess);
979
980         if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) {
981             if (ca->mover_state.pause_reason != NDMP9_MOVER_PAUSE_EOM)
982                 ndmca_media_write_filemarks (sess);
983             else
984                 ndmalogf (sess, 0, 1, "At EOM, not writing filemarks");
985         }
986
987         rc = ndmca_media_unload_current(sess);
988         if (rc) return rc;
989
990         rc = ndmca_media_load_next(sess);
991         if (rc) return rc;
992
993         rc = ndmca_media_set_window_current (sess);
994         if (rc) return rc;
995
996         rc = ndmca_mover_continue(sess);
997         if (rc) return rc;
998
999         ndmalogf (sess, 0, 1, "Operation resuming");
1000
1001         return 0;
1002 }
1003
1004 /* VERY VERY HARD */
1005 int
1006 ndmca_monitor_seek_tape (struct ndm_session *sess)
1007 {
1008         struct ndm_control_agent *ca = &sess->control_acb;
1009         int                     rc;
1010         unsigned long long      pos;
1011
1012         pos = ca->last_notify_mover_paused.seek_position;
1013
1014         ndmalogf (sess, 0, 1, "Operation requires a different tape");
1015
1016 /*      ndmca_media_capture_mover_window (sess);        // !!! */
1017         ndmca_media_calculate_offsets (sess);
1018
1019         rc = ndmca_media_unload_current(sess);
1020         if (rc) return rc;
1021
1022         rc = ndmca_media_load_seek (sess, pos);
1023         if (rc) return rc;
1024
1025         rc = ndmca_media_set_window_current (sess);
1026         if (rc) return rc;
1027
1028         rc = ndmca_mover_continue(sess);
1029         if (rc) return rc;
1030
1031         ndmalogf (sess, 0, 1, "Operation resuming");
1032
1033         return 0;
1034 }
1035
1036 int
1037 ndmca_monitor_unload_last_tape (struct ndm_session *sess)
1038 {
1039         struct ndm_control_agent *ca = &sess->control_acb;
1040         int                     rc;
1041
1042         if (!ca->media_is_loaded)
1043                 return 0;
1044
1045         ndmca_media_capture_mover_window (sess);
1046         ndmca_media_calculate_offsets (sess);
1047
1048         if (ca->tape_mode == NDMP9_TAPE_RDWR_MODE) {
1049                 ndmca_media_write_filemarks (sess);
1050         }
1051
1052         rc = ndmca_media_unload_current(sess);
1053         if (rc) return rc;
1054
1055         return 0;
1056 }
1057
1058 int
1059 ndmca_mon_wait_for_something (struct ndm_session *sess, int max_delay_secs)
1060 {
1061         struct ndm_control_agent *ca = &sess->control_acb;
1062         int                     delta, notices;
1063         int                     time_ref = time(0) + max_delay_secs;
1064
1065         ndmalogf (sess, 0, 5, "mon_wait_for_something() entered");
1066
1067         for (;;) {
1068                 delta = time_ref - time(0);
1069                 if (delta <= 0)
1070                         break;
1071
1072                 notices = 0;
1073                 if (ca->pending_notify_data_read) {
1074                         /* leave visible */
1075                         notices++;
1076                 }
1077                 if (ca->pending_notify_data_halted) {
1078                         /* just used to "wake up" */
1079                         ca->pending_notify_data_halted = 0;
1080                         notices++;
1081                 }
1082                 if (ca->pending_notify_mover_paused) {
1083                         /* leave visible */
1084                         notices++;
1085                 }
1086                 if (ca->pending_notify_mover_halted) {
1087                         /* just used to "wake up" */
1088                         ca->pending_notify_mover_halted = 0;
1089                         notices++;
1090                 }
1091
1092                 ndma_session_quantum (sess, notices ? 0 : delta);
1093
1094                 if (notices)
1095                         break;
1096         }
1097
1098         ndmalogf (sess, 0, 5, "mon_wait_for_something() happened, resid=%d",
1099                         delta);
1100
1101         return 0;
1102 }
1103 #endif /* !NDMOS_OPTION_NO_CONTROL_AGENT */