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