1 /* ***********************************************************
  2    *                                                         *
  3    * Copyright, (C) Honeywell Information Systems Inc., 1982 *
  4    *                                                         *
  5    * Copyright (c) 1972 by Massachusetts Institute of        *
  6    * Technology and Honeywell Information Systems, Inc.      *
  7    *                                                         *
  8    *********************************************************** */
  9 
 10 
 11 
 12 /****^  HISTORY COMMENTS:
 13   1) change(81-12-16,Texada), approve(), audit(), install():
 14      fix phx12050 and phx12187
 15   2) change(82-08-01,Texada), approve(), audit(), install():
 16      for phx12187, phx13713, phx13662
 17   3) change(82-11-12,Texada), approve(), audit(), install():
 18      to implement phx13262
 19   4) change(82-11-16,Texada), approve(), audit(), install():
 20      to implement phx14088,  allow preattachment of dump volumes to an
 21      existing incremental dump.
 22   5) change(83-01-26,Texada), approve(), audit(), install():
 23      to support version 2 dmpr_data_ and fix a problem when volumes were
 24      attached but not opened then crash.
 25   6) change(83-03-01,Kittlitz), approve(), audit(), install():
 26      for 256K segments.
 27   7) change(83-04-05,Texada), approve(), audit(), install():
 28      add trace entries.
 29   8) change(83-08-18,Texada), approve(), audit(), install():
 30      redefine -detach/-no_detach.
 31   9) change(84-02-01,Texada), approve(), audit(), install():
 32      support version 3 dmpr_data_.
 33  10) change(84-03-05,Texada), approve(), audit(), install():
 34      add set_volume_wakeup_interval.
 35  11) change(85-11-05,GWMay), approve(85-12-02,MCR7310), audit(85-12-05,Dupuis),
 36      install(85-12-16,MR12.0-1001):
 37      modified the routine set_volume_wakeup_interval to allow a wakeup
 38      interval up to 1440 minutes, this was raised from 480.  To
 39      accomodate the size of the interval when converted to microseconds,
 40      the variable my_interval was increased in size.
 41                                                    END HISTORY COMMENTS */
 42 
 43 
 44 /* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/
 45 
 46 dumper: proc;
 47 
 48 /* This proc provides the command interface for the volume dumper subsystem.  It initializes the static
 49    data base and other external data bases, attaches to, opens and parses the dump
 50    control file converting the control file into an ordered array of physical volume names and ids. It then
 51    successivly dumps this array , volume by volume. */
 52 
 53 
 54 dcl Area                 area based (areap);
 55 dcl tp                   (4) ptr;
 56 dcl dump_control_name    char (32);
 57 dcl was_asleep           bit (1);                           /* if incr dump, is saved value of dmpr_data_.dmpr_asleep, else is "0"b*/
 58 dcl (YES, dmpr_data_already_locked, new_control_seg, trace) bit (1);
 59 dcl mname                char (21);
 60 dcl (cycle_uid, ignored_lvid) bit (36);
 61 dcl answer               char (3) var;
 62 dcl (ac, argl, narg, nelemt, idx, num_pv, first_pvx, nvols, tnpv) fixed bin;
 63 dcl control_seg_name     char (32);
 64 dcl (areap, argp)        ptr;
 65 dcl line                 char (120) aligned;
 66 dcl tlvname              char (32) aligned;
 67 dcl lvname               (100) char (32);
 68 dcl pvname               (100) char (32);
 69 dcl time_string          char (24);
 70 dcl pvid                 (100) bit (36);
 71 dcl device_type          (100) fixed bin;
 72 dcl (old_time, time_pass_started) fixed bin (71);           /* Time this pass started. */
 73 dcl (code, ignore)       fixed bin (35);                    /* Error code. */
 74 
 75 dcl 1 query_info         aligned,
 76     2 version            fixed bin init (2),
 77     2 yes                bit (1) init ("1"b),
 78     2 name               bit (1) init ("0"b),
 79     2 code               fixed bin (35) init (0),
 80     2 pad                fixed bin;
 81 
 82 dcl 1 pva                (100) aligned,
 83     2 pvname             char (32),
 84     2 device_type        fixed bin,
 85     2 pvid               bit (36);
 86 
 87 
 88 dcl type_char            (3) char (4) int static init ("incr", "cons", "comp") options (constant);
 89 dcl force_write_bits     bit (36) init ((36)"0"b) int static options (constant); /* write pages in parallel                       */
 90 dcl lock_wait_time       fixed bin static init (60) options (constant);
 91 
 92 dcl arg                  char (argl) based (argp);
 93 
 94 dcl iox_$user_io         ptr external;
 95 dcl error_table_$action_not_performed fixed bin (35) ext static;
 96 dcl error_table_$end_of_info ext fixed bin (35);
 97 dcl error_table_$invalid_lock_reset ext fixed bin (35);
 98 dcl error_table_$inconsistent fixed bin (35) ext static;
 99 dcl error_table_$bad_arg ext fixed bin (35);
100 dcl error_table_$bad_conversion fixed bin (35) ext static;
101 dcl error_table_$wrong_no_of_args fixed bin (35) ext static;
102 dcl command_query_$yes_no entry () options (variable);
103 dcl cv_dec_check_        entry (char (*), fixed bin (35)) returns (fixed bin (35));
104 dcl get_system_free_area_ entry () returns (ptr);
105 dcl suffixed_name_$make  entry (char (*), char (*), char (*), fixed bin (35));
106 dcl hcs_$force_write     entry (ptr, bit (36), fixed bin (35));
107 dcl hcs_$set_256K_switch entry (bit (2) aligned, bit (2) aligned, fixed bin (35));
108 dcl hcs_$status_minf     entry (char (*), char (*), fixed bin, fixed bin, fixed bin, fixed bin (35));
109 dcl manage_volume_pool_$set_pool_path entry (entry options (variable), char (*), ptr, fixed bin (35));
110 dcl com_err_             entry options (variable);
111 dcl command_query_       entry options (variable);
112 dcl set_lock_$lock       entry (bit (36) aligned, fixed bin, fixed bin (35));
113 dcl ipc_$mask_ev_calls   entry (fixed bin (35));
114 dcl ipc_$unmask_ev_calls entry (fixed bin (35));
115 dcl ioa_$rsnnl           entry options (variable);
116 dcl cu_$arg_count        entry (fixed bin);
117 dcl cu_$arg_ptr          entry (fixed bin, ptr, fixed bin, fixed bin (35));
118 dcl hcs_$make_seg        entry (char (*), char (*), char (*), fixed bin (5), ptr, fixed bin (35));
119 dcl get_wdir_            entry returns (char (168) aligned);
120 dcl mdc_$check_mounted   entry (char (*) aligned, fixed bin (35));
121 dcl add_epilogue_handler_ entry (entry, fixed bin (35));
122 dcl iox_$control         entry (ptr, char (*), ptr, fixed bin (35));
123 dcl purge_volume_log_    entry (char (*) aligned, char (*) aligned, fixed bin, bit (1), fixed bin (35));
124 dcl hc_backup_$init_dmpr entry (ptr, ptr, fixed bin (35));
125 dcl dmpr_output_$init    entry (fixed bin (35));
126 dcl dmpr_output_$end_pass_detach entry (fixed bin (35));
127 dcl dmpr_output_$preattach_vols entry (fixed bin, fixed bin, fixed bin (35));
128 dcl dmpr_output_$preattach_ioname entry (fixed bin, fixed bin, fixed bin (35));
129 dcl get_temp_segments_   entry (char (*), (*) ptr, fixed bin (35));
130 dcl dump_volume_         entry (fixed bin (35));
131 dcl dmpr_info_           entry (fixed bin (35));
132 dcl dmpr_arg_reader_     entry (ptr, fixed bin (35));
133 dcl dmpr_finish_         entry (fixed bin (35));
134 dcl timer_manager_$alarm_wakeup entry (fixed bin (71), bit (2), fixed bin (71));
135 dcl timer_manager_$get_schedule entry (ptr, ptr, fixed bin (35));
136 dcl timer_manager_$reset_alarm_wakeup entry (fixed bin (71));
137 dcl mdc_$lvname_info     entry (char (*) aligned, ptr, fixed bin, fixed bin (35));
138 dcl mdc_$pvname_info     entry (char (*), bit (36), char (*), bit (36), fixed bin, fixed bin (35));
139 dcl date_time_           entry (fixed bin (71), char (*));
140 dcl cu_$arg_list_ptr     entry (ptr);                       /* Arg list location */
141 dcl iox_$attach_ioname   entry (char (*), ptr, char (*), fixed bin (35));
142 dcl iox_$position        entry (ptr, fixed bin, fixed bin, fixed bin (35));
143 dcl iox_$open            entry (ptr, fixed bin, bit (36), fixed bin (35));
144 dcl iox_$get_line        entry (ptr, ptr, fixed bin, fixed bin, fixed bin (35));
145 dcl ipc_$create_ev_chn   entry (fixed bin (71), fixed bin (35));
146 dcl ipc_$decl_ev_call_chn entry (fixed bin (71), entry, ptr, fixed bin, fixed bin (35));
147 dcl (dmpr_report_$error_output, dmpr_report_$online_output) entry options (variable);
148 
149 dcl (cleanup, finish)    condition;
150 
151 
152 dcl (after, before, bit, rtrim, addr, clock, fixed, hbound, length, null, substr, verify) builtin;
153 ^L
154 incremental_volume_dump: entry;
155 
156     call init (incr, "incremental_volume_dumper");
157     go to start;                                            /* Go get arguments. */
158 
159 consolidated_volume_dump: entry;
160 
161     call init (cons, "consolidated_volume_dump");
162     go to start;                                            /* Go get arguments. */
163 
164 complete_volume_dump: entry;                                /* Entry to do complete volume dump */
165 
166     call init (comp, "complete_volume_dump");
167 
168 start:
169     dmpr_data_.old_256K_switch = ""b;
170     call add_epilogue_handler_ (end_volume_dump, code);
171     if code ^= 0 then
172          call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to set epilogue handler");
173     on cleanup call dmpr_finish_ (ignore);
174     on finish call dmpr_finish_ (ignore);
175     call cu_$arg_list_ptr (argp);                           /* get arg list ptr */
176     call dmpr_arg_reader_ (argp, code);                     /* Get any other arguments */
177     if code ^= 0 then goto finale;
178 
179     call hcs_$set_256K_switch ("11"b, dmpr_data_.old_256K_switch, code);
180     if code ^= 0 then do;
181         call dmpr_report_$error_output (code, dmpr_data_.myname, "Could not enable 256KW segments.");
182         goto finale;
183       end;
184     dmpr_data_.arg_init = "1"b;
185     if (dmpr_data_.dump_type = incr) & (dmpr_data_.detach) & (dmpr_data_.pre_attach_vol ^= 0) then do;
186         call dmpr_report_$error_output (error_table_$inconsistent, dmpr_data_.myname,
187           "The -detach and -preattach control arguments are mutually exclusive");
188         goto finale;
189       end;
190 
191     if dmpr_data_.control_name = "" | dmpr_data_.operator = "" then do;
192         code = error_table_$bad_arg;                        /* Must have dump control file and operator */
193         call dmpr_report_$error_output (code, dmpr_data_.myname, "Missing control file or operator name");
194         goto finale;
195       end;
196     if dmpr_data_.auto_vol then do;
197         call manage_volume_pool_$set_pool_path (dmpr_report_$error_output,
198           rtrim (dmpr_data_.sys_dir) || ">Volume_Dumper", dmpr_data_.vpp, code);
199                                                             /* set the pool path to the standard one */
200         if code ^= 0 then do;
201             call dmpr_report_$online_output (code, dmpr_data_.myname, "Unable to locate volume pool");
202             goto finale;
203           end;
204 
205       end;
206                                                             /* setup temp segs */
207     call get_temp_segments_ ("dumper", tp, code);
208     if code ^= 0 then do;
209         call dmpr_report_$error_output (code, dmpr_data_.myname, "Temp seg init failure");
210         goto finale;
211       end;
212                                                             /* initialize static ptrs */
213     dmpr_data_.dirp = tp (1);
214     dmpr_data_.inputp = tp (2);
215     dmpr_data_.recordp = tp (3);
216     dmpr_data_.infop = tp (4);
217                                                             /* initialize info seg  - per dump info */
218     call dmpr_info_ (code);
219     if code ^= 0 then do;
220         call dmpr_report_$error_output (code, dmpr_data_.myname, "Error initing info seg ");
221         goto finale;
222       end;
223                                                             /* attach and open control file */
224     call iox_$attach_ioname ("dump_control", dmpr_data_.control_iocbp, "vfile_ " || dmpr_data_.control_name, code);
225     if code ^= 0 then do;
226         call dmpr_report_$error_output (code,
227           dmpr_data_.myname, "Unable to attach to ^a",
228           dmpr_data_.control_name);
229         goto finale;
230       end;
231     call iox_$open (dmpr_data_.control_iocbp, 1, "0"b, code);
232     if code ^= 0 then do;                                   /* Was an error encountered? */
233         call dmpr_report_$error_output (code, dmpr_data_.myname, "Open error on ^a", dmpr_data_.control_name);
234         goto finale;                                        /* Quit. */
235       end;
236     if dmpr_data_.dump_type = incr then do;                 /* Is this an incremental volume dump? */
237         call ipc_$create_ev_chn (dmpr_data_.incr_ev_chn, code); /* Create an event channel. */
238         if code ^= 0 then do;
239             call dmpr_report_$error_output (code, dmpr_data_.myname, "Error creating event channel");
240             goto finale;
241           end;                                              /* Make channel into call channel. */
242         call ipc_$decl_ev_call_chn (dmpr_data_.incr_ev_chn, restart_volume_dump, null, 1, code);
243         if code ^= 0 then do;                               /* OK? */
244             call dmpr_report_$error_output (code, dmpr_data_.myname, "Error make event call channel");
245             goto finale;                                    /* Give up. */
246           end;
247       end;
248                                                             /* initialize ring 0 part of dumper */
249     call hc_backup_$init_dmpr (dmpr_data_.dirp, dmpr_data_.segp, code);
250     if code ^= 0 then do;
251         call dmpr_report_$error_output (code, dmpr_data_.myname, "Ring 0 dmpr init failure");
252         goto finale;
253       end;
254     call dmpr_output_$init (code);
255     if code ^= 0 then do;
256         if code ^= -1 then                                  /* this code says that an attach/open failed      */
257              call dmpr_report_$error_output (code, dmpr_data_.myname, "Output volume init failure");
258         goto finale;
259       end;
260                                                             /* init input structure to ring 0 */
261     inputp = dmpr_data_.inputp;
262     dmpr_input.version = dmpr_input_version_1;
263     dmpr_input.type = dmpr_data_.dump_type;
264     dmpr_input.reset = dmpr_data_.reset;
265     dmpr_input.no_update = dmpr_data_.no_update;
266     dmpr_input.no_object = dmpr_data_.no_object;
267     dmpr_input.mod_after_time = dmpr_data_.mod_after_time;
268     dmpr_data_.dump_in_progress = "1"b;                     /* Set flag to prevent recursion. */
269     go to over;                                             /* Start dump pass. */
270 
271 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
272 ^L
273 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
274 
275 wakeup_volume_dump: entry;                                  /* Enter here on  operator wakeup. */
276     if dmprp = null then do;
277 no_dump: call com_err_ (0, "wakeup_volume_dump", "No dump to wakeup");
278         return;
279       end;
280     dmpr_data_.myname = "wakeup_volume_dump";
281 
282 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
283 
284 
285 restart_volume_dump: entry;                                 /* Enter here on alarm wakeup */
286 
287     if dmprp = null then do;
288         call com_err_ (0, "restart_volume_dump", "no dump to restart");
289         return;
290       end;
291     if dmpr_data_.dump_in_progress then do;                 /* Is a dump pass being done now? */
292         call dmpr_report_$online_output (0, dmpr_data_.myname,
293           "Dump pass presently in progress; this call ignored.");
294         return;
295       end;
296 
297     call timer_manager_$reset_alarm_wakeup (dmpr_data_.incr_ev_chn);
298     dmpr_data_.dump_in_progress = "1"b;                     /* Set flag. */
299     dmpr_data_.dmpr_asleep = "0"b;
300     new_control_seg = "0"b;
301     dmpr_data_already_locked = "0"b;
302     call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper waking up at ^a", time_now_ ());
303 
304 over:
305     time_pass_started = clock;
306                                                             /* position to front of control file */
307     call iox_$position (dmpr_data_.control_iocbp, -1, 0, code);
308     if code ^= 0 then do;                                   /* OK? */
309         call dmpr_report_$error_output (code, dmpr_data_.myname, "Error positioning on ^a",
310           dmpr_data_.control_name);
311         goto finale;                                        /* Give up. */
312       end;
313                                                             /* initialize local variables */
314     num_pv = 0;
315     lvname (*) = "";
316     pvname (*) = "";
317     pvid (*) = "0"b;
318     device_type (*) = 0;
319 
320 
321 /* This loop converts each line of the control file into a set(possibly one) of physical volume names and ids
322    and stores the entire result in a local array of 100 entries. This is a limit on the number of online
323    physical volumes that can be dumped by any one volume dumper. */
324 
325 read_line:
326     line = "";
327     call iox_$get_line (dmpr_data_.control_iocbp, addr (line), length (line), nelemt, code);
328     if code ^= 0 then do;
329         if code = error_table_$end_of_info then goto begin_vol_dump;
330         else do;
331             call dmpr_report_$error_output (code,
332               dmpr_data_.myname, "error reading ^a",
333               dmpr_data_.control_name);
334             goto finale;                                    /* Give up. */
335           end;
336       end;
337 
338     line = substr (line, 1, nelemt - 1);                    /* strip off new line at end */
339     if before (line, ",") = "lv" then do;
340         tlvname = after (line, ",");
341         call mdc_$lvname_info (tlvname, addr (pva), tnpv, code);
342         if code ^= 0 then do;
343             call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to convert ^a to physical volumes",
344               tlvname);
345             goto read_line;
346           end;
347         do idx = 1 to tnpv;
348           lvname (num_pv + idx) = tlvname;
349           pvname (num_pv + idx) = pva (idx).pvname;
350           pvid (num_pv + idx) = pva (idx).pvid;
351           device_type (num_pv + idx) = pva (idx).device_type;
352         end;
353         num_pv = num_pv + tnpv;
354       end;
355     else if before (line, ",") = "pv" then do;
356         num_pv = num_pv + 1;
357         pvname (num_pv) = after (line, ",");
358         call mdc_$pvname_info (pvname (num_pv), pvid (num_pv), lvname (num_pv), ignored_lvid,
359           device_type (num_pv), code);
360         if code ^= 0 then do;
361             call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to convert ^a to pvid",
362               pvname (num_pv));
363             num_pv = num_pv - 1;
364             goto read_line;
365           end;
366       end;
367     else call dmpr_report_$error_output (0, dmpr_data_.myname, "Unrecognized line ^a", line);
368     goto read_line;
369 
370 
371 /* This loop dumps each volid specified in the just constructed array. If we are in restart mode,
372    then we skip over all volumes until a match is found and start from there. If not we start with the first volume
373    in the list. In either case we process(dumped) each volume in turn reporting when we start and when we end
374    and what we did. */
375 
376 begin_vol_dump:
377     inputp = dmpr_data_.inputp;
378     first_pvx = 1;
379     if dmpr_data_.restart_pvname = "" /* no restart specified */
380       & ^new_control_seg
381       & ^was_asleep
382       & (dmpr_data_already_locked | (dmpr_data_.pvname ^= pvname (num_pv))) then do;
383         if dmpr_data_already_locked then do;
384             dmpr_data_.restart_pvname = dmpr_data_.pvname;
385             call dmpr_report_$online_output (0, dmpr_data_.myname, "Restarting with physical volume ^a.",
386               dmpr_data_.restart_pvname);
387           end;
388         else if dmpr_data_.dump_type ^= incr then do;       /* it must be cons or comp */
389             call command_query_ (addr (query_info), answer, dmpr_data_.myname, "^/^a",
390               "Previous dump cycle may not have completed. Do you want to restart ? ");
391             if answer = "yes" then
392                  dmpr_data_.restart_pvname = dmpr_data_.pvname;
393           end;
394       end;
395     if dmpr_data_.restart_pvname ^= "" then do;
396         if dmpr_data_.dump_type = incr then
397              dmpr_data_.cycle_uid = substr (bit (clock, 72), 20, 36);
398         do idx = 1 to num_pv while (pvname (idx) ^= dmpr_data_.restart_pvname);
399         end;
400         if idx > num_pv then do;
401             call dmpr_report_$error_output (0, dmpr_data_.myname,
402               "No match of restart pvname ^a in control seg",
403               dmpr_data_.restart_pvname);
404             goto finale;
405           end;
406         first_pvx = idx;
407       end;
408     else dmpr_data_.cycle_uid = substr (bit (clock, 72), 20, 36);
409 
410 
411     do idx = first_pvx to num_pv;
412       dmpr_data_.pvid = pvid (idx);
413       dmpr_data_.lvname = lvname (idx);
414       dmpr_data_.pvname = pvname (idx);
415       call mdc_$check_mounted (dmpr_data_.lvname, code);
416       if code ^= 0 then do;
417           call dmpr_report_$online_output (code, dmpr_data_.myname,
418             "Skipping logical volume ^a", dmpr_data_.lvname);
419           do while (lvname (idx) = dmpr_data_.lvname);
420             idx = idx + 1;
421           end;
422           idx = idx - 1;
423         end;
424       else do;
425           dmpr_data_.disk_type = device_type (idx);         /* set for the volume log                         */
426           call hcs_$force_write (dmprp, force_write_bits, ignore);
427                                                             /* save changed dmpr_data_                        */
428           if (dmpr_data_.dump_type = cons) | (dmpr_data_.dump_type = comp) then call dmpr_report_$online_output (0,
429                  dmpr_data_.myname, "Begin dump of physical volume ^a", dmpr_data_.pvname);
430           call dump_volume_ (code);
431           if code = 0 then do;
432               call dmpr_report_$online_output (0, dmpr_data_.myname,
433                 "Processed ^a: ^d ^d ^d ^d ^d",
434                 dmpr_data_.pvname,
435                 dmpr_data_.physical_volume_dir_rec, dmpr_data_.physical_volume_dir_num,
436                 dmpr_data_.physical_volume_seg_rec, dmpr_data_.physical_volume_seg_num,
437                 dmpr_data_.num_null_vtoce);
438 
439 
440               if dmpr_input.no_object then
441                    call dmpr_report_$online_output (0, dmpr_data_.myname,
442                      "Dumped ^d non null vtoces and ^d null vtoces",
443                      dmpr_data_.num_vtoce_only, dmpr_data_.num_null_vtoce);
444 
445 /* If this is a complete dump or the purge flag is on, then purge the volume log. This will release those dump
446    volumes that have been superseeded by this dump */
447 
448 
449               if (dmpr_data_.dump_type = cons & dmpr_data_.incr_skip_count ^= -1)
450                 | dmpr_data_.dump_type = comp then do;
451                   call purge_volume_log_ (dmpr_data_.sys_dir, dmpr_data_.pvname, dmpr_data_.incr_skip_count,
452                     dmpr_data_.manual_free & dmpr_data_.auto_vol, code);
453                   if code ^= 0 then
454                        call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to purge volume log ^a",
455                          dmpr_data_.pvname);
456                 end;
457             end;
458           else if code = -1 then goto finale;               /* Operator abort                                 */
459           else do;
460               call dmpr_report_$error_output (code, dmpr_data_.myname,
461                 "Error dumping volume ^a", dmpr_data_.pvname);
462             end;
463         end;
464     end;
465 
466 
467     dmpr_data_.restart_pvname = "";                         /* only do it once */
468 
469     call dmpr_report_$online_output (0, dmpr_data_.myname, "Dump finished at ^a", time_now_ ());
470 
471 /* If an incremental dump then setup alarm clock for wakeup */
472     if dmpr_data_.dump_type = incr then do;
473         call iox_$control (dmpr_data_.outputvol_iocbp, "error_count", addr (ignore), ignore);
474         if dmpr_data_.detach then call dmpr_output_$end_pass_detach (ignore);
475                                                             /* detach if we are supposed too.                 */
476         call timer_manager_$alarm_wakeup (time_pass_started + dmpr_data_.wakeup_interval, "00"b,
477           dmpr_data_.incr_ev_chn);
478         call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper going to sleep");
479         call iox_$control (iox_$user_io, "start", null, code);
480         if code ^= 0 then                                   /* OK? */
481              call dmpr_report_$error_output (code, dmpr_data_.myname, "iox_$control on user_i/o");
482         dmpr_data_.dump_in_progress = ""b;                  /* Indicate dump no longer active. */
483         dmpr_data_.dmpr_asleep = "1"b;
484         dmpr_data_.myname = "incremental_volume_dumper";    /* could have been invoked as wakeup_volume_dumper*/
485         call hcs_$force_write (dmprp, force_write_bits, ignore);
486                                                             /* TRY and get it written now                     */
487 
488         return;                                             /* all done for this pass */
489       end;
490     goto finale;
491 
492 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
493 ^L
494 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
495 
496 
497 end_volume_dump: entry;                                     /* Finish up dumping. */
498 
499     if dmprp = null then do;                                /* tell him there is no dump                      */
500         call com_err_ (0, "end_volume_dump", "No dump to end.");
501         return;
502       end;
503     dmpr_data_.myname = "end_volume_dump";
504     dmpr_data_.dump_in_progress = "1"b;                     /* let dmpr_finish_ turn it off                   */
505     dmpr_data_.disable_error_report = "1"b;
506     dmpr_data_.detach = "1"b;                               /* detach output volume when finished */
507 finale:
508     call dmpr_finish_ (ignore);
509 finale_nocleanup:
510     return;                                                 /* terminate processing */
511 
512 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
513 ^L
514 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
515 
516 preattach_dump_volumes: entry;
517 
518 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
519 /*                                                                                        */
520 /* Allow a running incremental dump to add volumes (just like the -preattach control      */
521 /* argument), without having to do an end_volume_dump and starting over.                  */
522 /*                                                                                        */
523 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
524 
525 dcl announce_vols        (nvols) char (32) based (addr (dmpr_data_.pre_attach_volname (dmpr_data_.pre_attach_vol + 1)));
526 
527 
528     call ipc_$mask_ev_calls (code);                         /* mask so we can do our work                     */
529     if code ^= 0 then do;
530         call com_err_ (code, "preattach_dump_volumes", "Unable to mask event calls, no preattachment performed.");
531         return;
532       end;
533 
534     if dmprp = null then do;                                /* no funny stuff...                              */
535         call com_err_ (0, "preattach_dump_volumes",
536           "No dump in progress, use the ""-preattach"" control argument to the incremental_volume_dump command.");
537         goto UNMASK_EV;
538       end;
539 
540     if dmpr_data_.dump_type ^= incr then do;
541         call com_err_ (0, "preattach_dump_volumes", "This command is only valid for incremental volume dumps.");
542         goto UNMASK_EV;
543       end;
544 
545     call cu_$arg_count (narg);
546     if narg ^= 1 then do;
547         call com_err_ (error_table_$wrong_no_of_args, "preattach_dump_volumes",
548           "Usage is: preattach_dump_volumes no_of_volumes");
549         goto UNMASK_EV;
550       end;
551     if dmpr_data_.detach then do;                           /* ok, let's ask him if we should turn off this   */
552         call command_query_$yes_no (YES, 0, "preattach_dump_volumes",
553           "In the invocation of the incremental_volume_dump command, -detach was specified.
554 This is used to detach  volumes after each pass of the dumper.  A ""yes"" answer will
555 turn this feature ""off"". A ""no"" answer will abort the preattachment of these volumes.",
556           "Do you wish to turn off the effect of the -detach control argument (type ""?"" for an explaination).");
557         if YES then dmpr_data_.detach = ""b;
558         else goto UNMASK_EV;
559       end;
560 
561     call cu_$arg_ptr (1, argp, argl, code);
562     if verify (arg, "0123456789") = 0 then do;              /* only numbers fellas                            */
563         nvols = fixed (arg, 17, 0);                         /* now, be sure we don't have too many            */
564 
565         if nvols = 0 then do;
566             call com_err_ (0, "preattach_dump_volumes", "The number of volumes must be greater than zero.");
567             goto UNMASK_EV;
568           end;
569 
570 
571         if ((dmpr_data_.pre_attach_vol + nvols) > hbound (dmpr_data_.pre_attach_volname, 1) |
572           (hbound (dmpr_data_.pre_attach_volname, 1) - (nvols + dmpr_data_.pre_attach_vol) < 0)) then do;
573             call com_err_ (error_table_$action_not_performed, "preattach_dump_volumes",
574               "Too many volumes to preattach. Space available for ^d more.",
575               (hbound (dmpr_data_.pre_attach_volname, 1) - dmpr_data_.pre_attach_vol));
576             goto UNMASK_EV;
577           end;
578       end;
579     else do;
580 
581         call com_err_ (error_table_$bad_conversion, "preattach_dump_volumes", "^a", arg);
582         goto UNMASK_EV;
583       end;
584 
585     on cleanup begin;
586         code = 0;
587         do while (code = 0);
588           call ipc_$unmask_ev_calls (code);
589         end;
590       end;
591 
592     call dmpr_output_$preattach_vols (nvols, (dmpr_data_.pre_attach_vol + nvols) - (nvols - 1), code);
593                                                             /* get the volume names from the user or the pool */
594     if code ^= 0 then goto UNMASK_EV;
595     call dmpr_report_$online_output (0, "preattach_dump_volumes", "Please get the following volume^[s^]: ^v(^a ^)",
596                                                             /* announce which volumes to get                  */
597       (nvols > 1), nvols, announce_vols (*));
598 
599     call dmpr_output_$preattach_ioname (nvols, (dmpr_data_.pre_attach_vol + nvols) - (nvols - 1), code);
600                                                             /* do the attach                                  */
601     if code = 0 then dmpr_data_.pre_attach_vol = dmpr_data_.pre_attach_vol + nvols;
602 UNMASK_EV:
603     code = 0;
604     do while (code = 0);
605       call ipc_$unmask_ev_calls (code);
606     end;
607     return;
608 
609 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
610 ^L
611 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
612 
613 
614 set_volume_wakeup_interval: entry;
615 
616 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
617 /*                                                                                        */
618 /* This entry allows the changing of the wakeup interval for a running incremental dump.  */
619 /*                                                                                        */
620 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
621 
622 dcl i                                   fixed bin (35),
623     my_interval                         fixed bin (71);
624 
625     call ipc_$mask_ev_calls (code);
626     if code ^= 0 then do;
627         call com_err_ (code, "set_volume_wakeup_interval", "Unable to mask event calls, interval not changed.");
628         return;
629       end;
630     areap, schedule_ptr = null ();
631     areap = get_system_free_area_ ();
632     on cleanup begin;
633         if schedule_ptr ^= null () then free schedule in (Area);
634         code = 0;
635         do while (code = 0);
636           call ipc_$unmask_ev_calls (code);
637         end;
638       end;
639     if dmprp = null then do;
640         call com_err_ (0, "set_volume_wakeup_interval", "No dump in progress.");
641         goto UNMASK_EV;
642       end;
643     if dmpr_data_.dump_type ^= incr then do;
644         call com_err_ (0, "set_volume_wakeup_interval", "This command is valid only for incremental volume dumps.");
645         goto UNMASK_EV;
646       end;
647     call cu_$arg_count (narg);
648     if narg ^= 1 then do;
649         call com_err_ (error_table_$wrong_no_of_args, "set_volume_wakeup_interval",
650           "Usage is: set_volume_wakeup_interval no_of_minutes");
651         goto UNMASK_EV;
652       end;
653     call cu_$arg_ptr (1, argp, argl, code);
654     if code ^= 0 then do;
655         call com_err_ (code, "set_volume_wakeup_interval");
656         goto UNMASK_EV;
657       end;
658     my_interval = cv_dec_check_ (arg, code);
659     if code ^= 0 then do;
660 badint: call com_err_ (0, "set_volume_wakeup_interval", "The interval must be in minutes (1 to 1440).");
661         goto UNMASK_EV;
662       end;
663     if (my_interval < 1) | (my_interval > 1440) then goto badint;
664                                                             /* make sure it's in the range                    */
665     my_interval = my_interval * 60000000;                   /* make it microseconds                           */
666     call timer_manager_$get_schedule (areap, schedule_ptr, code);
667     if code ^= 0 then do;
668         call com_err_ (code, "set_volume_wakeup_interval", "Getting the event schedule.");
669         goto UNMASK_EV;
670       end;
671     do i = 1 to schedule.n_timers;                          /* now, find the right event channel              */
672       if schedule.timer (i).channel = dmpr_data_.incr_ev_chn then do;
673                                                             /* here it is                                     */
674           old_time = (schedule.timer (i).time - dmpr_data_.wakeup_interval);
675                                                             /* this was the *base* time for the wakeup        */
676           call timer_manager_$reset_alarm_wakeup (dmpr_data_.incr_ev_chn);
677                                                             /* reset the *old* one                            */
678           dmpr_data_.wakeup_interval = my_interval;         /* set the new one                                */
679           call timer_manager_$alarm_wakeup (old_time + dmpr_data_.wakeup_interval, "00"b,
680             dmpr_data_.incr_ev_chn);                        /* and set the new wakeup                         */
681           call hcs_$force_write (dmprp, force_write_bits, ignore);
682                                                             /* and get it written                             */
683           free schedule in (Area);                          /* be clean                                       */
684           goto UNMASK_EV;                                   /* let 'er rip                                    */
685         end;
686     end;
687     call com_err_ (0, "set_volume_wakeup_interval", "Unable to find the interval timer, no action performed.");
688     free schedule in (Area);
689     goto UNMASK_EV;
690 
691 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
692 ^L
693 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
694 
695 volume_dump_trace_on: entry;
696 
697     trace = "1"b;                                           /* turn on tracing...                             */
698     mname = "volume_dump_trace_on";
699     goto trace_join;
700 
701 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
702 
703 volume_dump_trace_off: entry ();
704     mname = "volume_dump_trace_off";
705     trace = "0"b;
706 
707 trace_join:
708     if dmprp = null () then                                 /* no dump to trace yet...                        */
709          call com_err_ (0, mname, "No dump in progress.");
710     else do;
711         call cu_$arg_count (narg);
712         if narg > 0 then call com_err_ (error_table_$wrong_no_of_args, mname,
713                "This command accepts no arguments.");
714         else if dmpr_data_.trace = trace then call com_err_ (error_table_$action_not_performed, mname,
715                "Tracing is already in the state requested, ^[on^;^off^]", trace);
716         else dmpr_data_.trace = trace;
717       end;
718     return;
719 
720 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
721 ^L
722 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
723 
724 
725 init: proc (type, myname);
726 
727 dcl type                 fixed bin;
728 dcl myname               char (*);
729 dcl (volname, pvname, prev_volname) char (32);
730 dcl (dir_rec, dir_num, seg_num, seg_rec) fixed bin;
731 
732 /* This proc initializes the dumper's external static data base */
733 
734     call cu_$arg_count (narg);
735     if narg < 2 then do;
736         call dmpr_report_$error_output (error_table_$bad_arg, myname, "Required control args not specified");
737         goto finale;
738       end;
739     if dmprp ^= null () then do;
740         call com_err_ (0, myname, "Recursive invocations of the dumper are not allowed.^[^/Use end_volume_dump first.^]",
741           type = incr);
742         goto finale_nocleanup;
743       end;
744     do ac = 1 to narg;
745       call cu_$arg_ptr (ac, argp, argl, code);
746       if arg = "-control" then do;
747           call cu_$arg_ptr (ac + 1, argp, argl, code);
748           if code ^= 0 then do;
749               call dmpr_report_$error_output (code, myname,
750                 "No control segment specified after -control.");
751               goto finale;
752             end;
753           call suffixed_name_$make (arg, "dump", dump_control_name, code);
754           if code ^= 0 then do;
755               call dmpr_report_$online_output (code, myname,
756                 "Unable to create dump control seg name from ^a", arg);
757               goto finale;
758             end;
759           call hcs_$status_minf (get_wdir_ (), dump_control_name, 0, (0), (0), code);
760           if code ^= 0 then do;
761               call dmpr_report_$online_output (code, myname, "Unable to locate ^a>^a",
762                 get_wdir_ (), dump_control_name);
763               goto finale;
764             end;
765           call ioa_$rsnnl ("^a.^a.^a", control_seg_name, (0), arg, type_char (type), "control");
766           call hcs_$make_seg (get_wdir_ (), control_seg_name, "", 01010b, dmprp, code);
767           if code = 0 then do;                              /* new control seg */
768 new_control:  call dmpr_report_$online_output (0, myname, "^/Creating new control seg ^a>^a",
769                 get_wdir_ (), control_seg_name);
770               new_control_seg = "1"b;
771               dmpr_data_.version = dmpr_data_version_2;
772               prev_volname, volname, pvname = "";
773               cycle_uid = substr (bit (clock, 72), 20, 36);
774               dir_rec, dir_num, seg_rec, seg_num = 0;
775               call lock_dmpr_data;
776             end;
777           else if dmprp ^= null then do;                    /* already existed */
778               new_control_seg = "0"b;
779               if dmpr_data_.version ^= dmpr_data_version_3 then do;
780                   if dmpr_data_.version = dmpr_data_version_2 then do;
781                       dmpr_data_.version = dmpr_data_version_3;
782                       dmpr_data_.disk_type = 0;             /* totally invisible                              */
783                     end;
784                   else do;
785                       call dmpr_report_$online_output (0, myname, "Invalid control seg found");
786                       goto new_control;
787                     end;
788                 end;
789               call lock_dmpr_data;
790               if (dmpr_data_.not_reported & dmpr_data_.cur_vol_open) then
791                                                             /* do only if the volume was opened.              */
792                    call dmpr_report_$online_output (0, myname,
793                      "Finished volume ^a: ^d ^d ^d ^d", dmpr_data_.volname,
794                      dmpr_data_.dump_volume_dir_rec, dmpr_data_.dump_volume_dir_num,
795                      dmpr_data_.dump_volume_seg_rec,
796                      dmpr_data_.dump_volume_seg_num);
797               cycle_uid = dmpr_data_.cycle_uid;
798               if dmpr_data_.cur_vol_open then do;           /* if it was opened successfully                  */
799                   volname = dmpr_data_.volname;
800                   prev_volname = dmpr_data_.volname;
801                 end;
802               else do;                                      /* nope, use the previous one                     */
803                   volname = dmpr_data_.prev_volname;
804                   prev_volname = dmpr_data_.prev_volname;
805                 end;
806               pvname = dmpr_data_.pvname;
807               dir_rec = dmpr_data_.physical_volume_dir_rec;
808               dir_num = dmpr_data_.physical_volume_dir_num;
809               seg_rec = dmpr_data_.physical_volume_seg_rec;
810               seg_num = dmpr_data_.physical_volume_seg_num;
811             end;
812           else do;                                          /* couldn't create it, so punt */
813               call dmpr_report_$online_output (code, myname, "Unable to initialize control seg");
814               goto finale;
815             end;
816         end;
817     end;
818     if dmprp = null then do;
819         call dmpr_report_$online_output (0, myname,
820           "Control seg initialization failed - control seg not specified.");
821         goto finale;
822       end;
823     dmpr_data_.ptrs = null;
824     if type = incr then was_asleep = dmpr_data_.dmpr_asleep;
825     else was_asleep = "0"b;                                 /* save or set for restart processing             */
826     dmpr_data_.bits = "0"b;
827     dmpr_data_.fixed_bin = 0;
828     dmpr_data_.disk_type = 0;
829     dmpr_data_.chars = "";
830     if type = incr then dmpr_data_.detach = "0"b;           /* default for incrs                              */
831     else dmpr_data_.detach = "1"b;
832     dmpr_data_.cycle_uid = cycle_uid;
833     dmpr_data_.wakeup_interval = 3600000000;                /* Default, one hour (in micro seconds) */
834     dmpr_data_.data_init = "1"b;
835     dmpr_data_.incr_skip_count = -1;
836     dmpr_data_.pre_attach_vol = 0;
837     dmpr_data_.dump_type = type;
838     dmpr_data_.sys_dir = ">daemon_dir_dir>volume_backup";
839     dmpr_data_.myname = myname;
840     dmpr_data_.pvname = pvname;
841     dmpr_data_.volname = volname;
842     dmpr_data_.prev_volname = prev_volname;
843     dmpr_data_.physical_volume_dir_rec = dir_rec;
844     dmpr_data_.physical_volume_dir_num = dir_num;
845     dmpr_data_.physical_volume_seg_rec = seg_rec;
846     dmpr_data_.physical_volume_seg_num = seg_num;
847     code = 0;
848   end init;
849 ^L
850 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
851 
852 
853 time_now_: proc returns (char (6));
854 
855 /* This proc returns a time string suitable for printing of the present time */
856 
857     call date_time_ (clock, time_string);
858     return (substr (time_string, 11, 6));
859   end time_now_;
860 
861 /*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *   */
862 
863 
864 lock_dmpr_data: proc;
865     call set_lock_$lock (dmpr_data_.lock, lock_wait_time, code);
866     if code ^= 0 then do;
867         if code = error_table_$invalid_lock_reset then do;
868             code = 0;
869             dmpr_data_already_locked = "1"b;
870           end;
871         else do;
872             if dmpr_data_.dump_in_progress then do;
873                 call dmpr_report_$online_output (0, dmpr_data_.myname,
874                   "Dump pass presently in progress; this call ignored");
875                 goto finale_nocleanup;
876               end;
877             else if dmpr_data_.dmpr_asleep then do;
878                 call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper asleep. Use wakeup_volume_dump");
879                 goto finale_nocleanup;
880               end;
881             else do;
882                 call dmpr_report_$online_output (code, dmpr_data_.myname,
883                   "Dumper invoked recursively. Use end_volume_dump");
884                 goto finale_nocleanup;
885               end;
886           end;
887       end;
888     else dmpr_data_already_locked = "0"b;
889   end lock_dmpr_data;
890 ^L
891 %include dmpr_data_;
892 ^L
893 %include dmpr_input;
894 %include backup_static_variables;
895 ^L
896 %include backup_volume_header;
897 ^L
898 %include timer_manager_schedule;
899 
900 
901   end dumper;