



		    dmpr_arg_reader_.pl1            10/10/89  1422.4rew 10/10/89  1359.2       66024



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) BULL HN Information Systems Inc., 1989   *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */

/****^  HISTORY COMMENTS:
  1) change(85-12-04,GWMay), approve(), audit(), install():
     old history comments -
     Written: In antiquity, probably by Dave Vinograd.
     Modified: April 1983 by GA Texada for -trace -no_trace.
     Modified: May 1983 by GA Texada to add -preattach.
     Modified: August 1983 by GA Texada to redefine -detach & -no_detach.
  2) change(85-12-04,GWMay), approve(85-12-04,MCR7310), audit(85-12-05,Dupuis),
     install(85-12-16,MR12.0-1001):
     Modified wakeup interval to allow a maximum of 1440 minutes. It
     previously allowed 480 minutes.
  3) change(89-08-31,GWMay), approve(89-10-03,MCR8135),
     audit(89-10-04,Beattie), install(89-10-10,MR12.3-1089):
     Disabled the -incr_skip_count argument.  Used the value
     dmpr_data_.incr_skip_count as a switch for a new control argument set.
     Added -purge_volume_log, -pvl, -no_purge_volume_log, -npvl arguments.
                                                   END HISTORY COMMENTS */

/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/

dmpr_arg_reader_: proc (a_alp, a_code);

/* This routine reads and handles the arguments
   *   for the volume dumper.
   *
   *  Usage:  dcl dmpr_arg_reader_ entry ( pointer, fixed bin (35));
   *
   *	call dmpr_arg_reader_ (a_alp, a_code);
   *
   *	where
   *
   *
   *	1) a_alp		is a pointer to the argument list (Input).
   *
   *	2) a_code		is a standard status code (Output).
   *
*/

dcl (ac, al)	     fixed bin;
dcl pre_attach_vol	     fixed bin;
dcl (a_code, code)	     fixed bin (35);
dcl (a_alp, alp, ap)     ptr;
dcl arg		     char (al) based (ap);
dcl myname	     char (16) int static init ("dmpr_arg_reader_") options (constant);

dcl error_table_$bad_arg ext fixed bin (35);
dcl error_table_$noarg   ext fixed bin (35);
dcl error_table_$badopt  ext fixed bin (35);

dcl get_wdir_	     entry returns (char (168));
dcl suffixed_name_$make  entry (char (*), char (*), char (*) aligned, fixed bin (35));
dcl dmpr_report_$error_output entry options (variable);
dcl convert_date_to_binary_ entry (char (*), fixed bin (71), fixed bin (35));
dcl cu_$arg_ptr_rel	     entry (fixed bin, ptr, fixed bin, fixed bin (35), ptr);
dcl cv_dec_check_	     entry (char (*), fixed bin (35)) returns (fixed bin);

dcl hbound	     builtin;

    a_code = 0;					/* set up and copy args */
    alp = a_alp;					/* arg list pointer */
    do ac = 1 by 1;					/* scan the arg list */
      call cu_$arg_ptr_rel (ac, ap, al, code, alp);
      if code ^= 0 then
	 if code = error_table_$noarg then return;
	 else go to err;				/* error if code other than noargs */
      if arg = "-control" then do;
	call suffixed_name_$make (get_arg (), "dump", dmpr_data_.control_name, code);
	if code ^= 0 then goto bad_arg;
        end;
      else if arg = "-operator" then
	 dmpr_data_.operator = get_arg ();
      else if arg = "-output_volume_desc" then		/* this must be attach description  */
	 dmpr_data_.att_desc = get_arg ();
      else if arg = "-wakeup" then do;			/* this must be wakeup interval in minutes */
	dmpr_data_.wakeup_interval = cv_dec_check_ (get_arg (), code);
	if code ^= 0 then do;
bad_intr:	    call dmpr_report_$error_output (0, myname, "Invalid interval ^a specified", arg);
	    goto bad_arg;
	  end;
	if dmpr_data_.wakeup_interval < 1 | dmpr_data_.wakeup_interval > 1440 then goto bad_intr;
	dmpr_data_.wakeup_interval = dmpr_data_.wakeup_interval * 60000000;
						/* interval converted to microseconds */
        end;
      else if arg = "-restart" then			/* restart at pvname given */
	 dmpr_data_.restart_pvname = get_arg ();
      else if arg = "-mod_after" then do;
	call convert_date_to_binary_ (get_arg (), dmpr_data_.mod_after_time, code);
	if code ^= 0 then do;
	    call dmpr_report_$error_output (0, myname, "Invalid time ^a specified",
	      arg);
	    goto bad_arg;
	  end;
        end;
      else if arg = "-incr_skip_count" then do;
	  call dmpr_report_$error_output (error_table_$bad_arg, myname, "
The -incr_skip_count function has been replaced by -purge_volume_log.", arg);
	  goto bad_arg;
	  end;
      else if arg = "-purge_volume_log" | arg = "-pvl" then
	  dmpr_data_.incr_skip_count = 0; /* use the old value as a switch */
      else if arg = "-no_purge_volume_log" | arg = "-npvl" then
	  dmpr_data_.incr_skip_count = -1; /* use the old value as a switch */
      else if arg = "-pre_attach" | arg = "-preattach" then do;
	pre_attach_vol = cv_dec_check_ (get_arg (), code);
	if code ^= 0 then do;
bad_mv:	    call dmpr_report_$error_output (0, myname,
	      "Invalid preattach vol number ^a specified", arg);
	    goto bad_arg;
	  end;
	if pre_attach_vol > hbound (dmpr_data_.pre_attach_volname, 1) then goto bad_mv;
	dmpr_data_.pre_attach_vol = pre_attach_vol;
        end;
      else if arg = "-working_dir" | arg = "-wd" then
	 dmpr_data_.sys_dir = get_wdir_ ();
      else if arg = "-accounting" then dmpr_data_.accounting = "1"b;
      else if arg = "-auto" then dmpr_data_.auto_vol = "1"b;/* enable auto volume selection */
      else if arg = "-error_on" then dmpr_data_.err_online = "1"b; /* output errors online */
      else if arg = "-names" then dmpr_data_.names = "1"b;	/* collect all names */
      else if arg = "-detach" then do;			/* only valid for incrementals		*/
	 if dmpr_data_.dump_type ^= incr then goto bad_arg;
	 dmpr_data_.detach = "1"b;
	 end;
      else if arg = "-no_detach" then do;		/* only for incr's				*/
	 if dmpr_data_.dump_type ^= incr then goto bad_arg;
	 dmpr_data_.detach = ""b; /* don't detach */
	 end;
      else if arg = "-no_object" then dmpr_data_.no_object = "1"b; /* don't activate object */
      else if arg = "-cumulative" then dmpr_data_.reset = "1"b; /* reset bit map. */
      else if arg = "-manual_free" then dmpr_data_.manual_free = "1"b;
      else if arg = "-no_update" then dmpr_data_.no_update = "1"b; /* don't modify vtoce */
      else if arg = "-trace" then dmpr_data_.trace = "1"b;
      else if arg = "-no_trace" then dmpr_data_.trace = "0"b;
      else do;
	code = error_table_$badopt;
	goto err;
        end;
    end;

bad_arg: code = error_table_$bad_arg;
err: call dmpr_report_$error_output (code, myname, "^a", arg);
    a_code = code;					/* return an error code */
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


get_arg: proc returns (char (*));
    ac = ac + 1;
    call cu_$arg_ptr_rel (ac, ap, al, code, alp);
    if code ^= 0 then goto err;

    return (arg);
  end get_arg;

%include dmpr_data_;

%include backup_static_variables;
%include backup_volume_header;
  end dmpr_arg_reader_;




		    dmpr_finish_.pl1                10/10/89  1422.4r w 10/10/89  1359.7       84150



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1989                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */




/****^  HISTORY COMMENTS:
  1) change(86-08-12,GWMay), approve(86-08-12,MCR7445), audit(86-11-20,GDixon),
     install(86-11-21,MR12.0-1223):
     changed to set bit count on the segment <volname>.contents_names.
  2) change(89-01-06,GWMay), approve(89-01-06,MCR8039), audit(89-01-09,Farley),
     install(89-01-17,MR12.3-1002):
     Changed to call msf_mgr_$adjust to correctly set the size of the
     <volname>.contents_names segments.
                                                   END HISTORY COMMENTS */


/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/

dmpr_finish_: proc (code);

/* This routine provides a centralized cleanup function for the volume dumper. It closes the account segment, unlocks
   any logs that may have been left locked, detachs a switches that may have been left attached,
   releases any temp segs, clears any pending alarms by deleting the event channel, and resets the ring 0
   dumper and its data. This routine is used to clean up  both in the normal case and after a dumper abort when
   the state of the world is not well understood. */

/* Modified: 8/82 by GA Texada to fix phx13662, phx13708						*/
/* Modified: 3/83 by E. N. Kittlitz for 256K segments.					          */
/* Modified: 8/01/83 by GA Texada to call manage_volume_pool_$check_reserved
		 to free any reserved volumes not in valid use.				          */

dcl code		     fixed bin (35);
dcl i		     fixed bin;
dcl attach_name	     char (32);
dcl bit_count	     fixed bin (24);
dcl ignore	     fixed bin (35);
dcl tp		     (4) ptr;

dcl msf_manager_$adjust  entry (ptr, fixed bin, fixed bin (24), bit (3), fixed bin (35));
dcl msf_manager_$close   entry (ptr);
dcl manage_volume_pool_$check_reserved entry (ptr, entry, fixed bin (35));
dcl manage_volume_pool$free entry (ptr, entry options (variable), char (*) aligned, fixed bin (35));
dcl ioa_$rsnnl	     entry options (variable);
dcl hcs_$fs_get_path_name entry (ptr, char (*), fixed bin, char (*), fixed bin (35));
dcl adjust_bit_count_    entry (char (*), char (*), bit (1), fixed bin, fixed bin (35));
dcl hcs_$delentry_seg    entry (ptr, fixed bin (35));
dcl hcs_$terminate_seg   entry (ptr, fixed bin, fixed bin (35));
dcl release_temp_segments_ entry (char (*), (*) ptr, fixed bin (35));
dcl dmpr_report_$error_output entry options (variable);
dcl dmpr_report_$online_output entry options (variable);
dcl dmpr_log_$close_volume_log entry (fixed bin (35));
dcl set_lock_$unlock     entry (bit (36) aligned, fixed bin (35));
dcl ipc_$delete_ev_chn   entry (fixed bin (71), fixed bin (35));
dcl hc_backup_$dmpr_unlock_pv entry (bit (36) aligned, fixed bin, fixed bin (35));
dcl hc_backup_$revert_dmpr entry (fixed bin);
dcl hcs_$set_256K_switch entry (bit (2) aligned, bit (2) aligned, fixed bin (35));
dcl iox_$close	     entry (ptr, fixed bin (35));
dcl iox_$find_iocb	     entry (char (*), ptr, fixed bin (35));
dcl iox_$detach_iocb     entry (ptr, fixed bin (35));

dcl set_bc_n_truncate    bit (3) int static init ("110"b) options (constant);

dcl null		     builtin;
%page;
    code = 0;
    if dmprp = null then return;
    if ^dmpr_data_.data_init then return;		/* reject calls if dmpr_data_ not inited */


    if dmpr_data_.bvlp ^= null then do;
        bvlp = dmpr_data_.bvlp;
        call unlock_volume_log;
        call setbc_term (dmpr_data_.bvlp);
      end;


    if dmpr_data_.fcbp ^= null then do;
        if dmpr_data_.contents_namesp ^= null then do;
	  contents_namesp = dmpr_data_.contents_namesp;
	  bit_count = backup_volume_contents_names.offset * BITS_PER_WORD;
	  call msf_manager_$adjust (dmpr_data_.fcbp, dmpr_data_.component,
	       bit_count, set_bc_n_truncate, ignore);
	  call msf_manager_$close (dmpr_data_.fcbp);
	end;
      end;

    if dmpr_data_.pvlp ^= null then do;
        pvlp = dmpr_data_.pvlp;
        call unlock_pvolog;
        call setbc_term (dmpr_data_.pvlp);
      end;

    if dmpr_data_.contentsp ^= null then
      call setbc_term (dmpr_data_.contentsp);

    if dmpr_data_.control_iocbp ^= null () then
      call detach ("dump_control", dmpr_data_.control_iocbp); /* detach control seg */

    if dmpr_data_.account_iocbp ^= null () then
      call detach ("account_file", dmpr_data_.account_iocbp); /* and account file */

    if dmpr_data_.detach then do;
        if dmpr_data_.outputvol_iocbp ^= null then
	call dmpr_report_$online_output (0, myname,
	     "Finished volume ^a: ^d ^d ^d ^d", dmpr_data_.volname,
	     dmpr_data_.dump_volume_dir_rec, dmpr_data_.dump_volume_dir_num, dmpr_data_.dump_volume_seg_rec,
	     dmpr_data_.dump_volume_seg_num);
        dmpr_data_.not_reported = "0"b;
        if dmpr_data_.pre_attach_vol = 0 then
	call detach ("dump_volume", dmpr_data_.outputvol_iocbp); /* and output volume */
        else do;
	  do i = dmpr_data_.vol_idx + 1 to dmpr_data_.pre_attach_vol
	       while (dmpr_data_.pre_attach_pvlp (i) ^= null ());
	    if dmpr_data_.auto_vol then
	      call manage_volume_pool$free (dmpr_data_.vpp, dmpr_report_$error_output,
		 dmpr_data_.pre_attach_volname (i), ignore);
	    call hcs_$delentry_seg (dmpr_data_.pre_attach_pvlp (i), ignore);
	  end;
	  do i = 1 to dmpr_data_.pre_attach_vol while (dmpr_data_.pre_attach_iocbp (i) ^= null ());
	    call ioa_$rsnnl ("^a.^d", attach_name, ignore, "dump_volume", i);
	    call detach (attach_name, dmpr_data_.pre_attach_iocbp (i));
	  end;
	  dmpr_data_.pre_attach_vol = 0;
	end;
      end;

    if dmpr_data_.vpp ^= null () then			/* free ANY old reserved volumes		*/
      call manage_volume_pool_$check_reserved (dmpr_data_.vpp, dmpr_report_$error_output, (0));
						/* don't care about code here			*/
    if dmpr_data_.error_iocbp ^= null () then
      call detach ("error_file", dmpr_data_.error_iocbp);	/* and error file */
    if dmpr_data_.dump_type = incr & dmpr_data_.incr_ev_chn ^= 0 then do; /* incremental case */
        call ipc_$delete_ev_chn (dmpr_data_.incr_ev_chn, code);
        dmpr_data_.incr_ev_chn = 0;
      end;

    call hc_backup_$dmpr_unlock_pv (dmpr_data_.pvid, dmpr_data_.dump_type, ignore);

    call hc_backup_$revert_dmpr (dmpr_data_.dump_type);

    tp (1) = dmpr_data_.dirp;
    tp (2) = dmpr_data_.inputp;
    tp (3) = dmpr_data_.recordp;
    tp (4) = dmpr_data_.infop;

    call release_temp_segments_ ("dumper", tp, code);
    call hcs_$set_256K_switch (dmpr_data_.old_256K_switch, (""b), (0));

    dmpr_data_.dump_in_progress = "0"b;			/* finished				*/
    call set_lock_$unlock (dmpr_data_.lock, ignore);

    dmprp = null;					/* vanish the control seg */
    return;


/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


detach: proc (iocb_name, iocbp);

/* This proc detachs the switch specified . It ignores all errors */

dcl iocb_name	     char (*);
dcl tiocbp	     ptr;
dcl iocbp		     ptr;

    call iox_$find_iocb (iocb_name, tiocbp, ignore);

    call iox_$close (tiocbp, ignore);

    call iox_$detach_iocb (tiocbp, ignore);

    iocbp = null ();

    return;

  end detach;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


unlock_volume_log: proc;

/* This proc unlocks the backup_volume_log, which may be locked. It also closes the volume log. */

    call set_lock_$unlock (backup_volume_log.lock, ignore);
    call dmpr_log_$close_volume_log (code);
    return;
  end unlock_volume_log;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


unlock_pvolog: proc;

/* This proc unlocks the output volume log */

    call set_lock_$unlock (pvolog.lock, ignore);
    return;
  end unlock_pvolog;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


setbc_term: proc (p);

/* This proc terminates the specified segment and sets the ptr to it to null */

dcl p		     ptr;
dcl dn		     char (168);
dcl en		     char (32);
dcl ldn		     fixed bin;
    call hcs_$fs_get_path_name (p, dn, ldn, en, ignore);
    call adjust_bit_count_ (dn, en, "0"b, (0), ignore);
    call hcs_$terminate_seg (p, 0, ignore);
    p = null;

  end setbc_term;
%page;
%include dmpr_data_;
%page;
%include backup_static_variables;
%page;
%include backup_volume_log;
%page;
%include backup_pvol_info;
%page;
%include fs_vol_label;
%page;
%include backup_volume_header;
%page;
%include backup_volume_contents;
%page;
%include pvolog;
%page;
%include system_constants;
%page;
%include terminate_file;


  end dmpr_finish_;
  



		    dmpr_info_.pl1                  10/22/84  0946.0rew 10/22/84  0902.2       17118



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */


dmpr_info_: proc (code);

/* This routine initializes the info segment that is written as the first object on each output
   volume. The info segment describes the dump pass and defines what system it came from by means
   of the rpv uid, which will be different from site to site.  This infomation is used by the volume reloader. */


dcl  code fixed bin (35);
dcl  lvname char (32) aligned;

dcl  clock_ entry returns (fixed bin (71));
dcl  mdc_$pvname_info entry (char (*) aligned, bit (36) aligned, char (*) aligned,
     bit (36) aligned, fixed bin, fixed bin (35));

%include backup_info;
%include dmpr_data_;
%include backup_volume_header;

	infop = dmpr_data_.infop;

	backup_info.pattern1 = pattern1;
	backup_info.pattern2 = pattern2;
	backup_info.pattern3 = pattern3;

	backup_info.rec1_type = info_type;
	backup_info.rec1_len = 4 * size (backup_info);

	backup_info.rec2_type = null_type;
	backup_info.rec2_len = 0;

	call mdc_$pvname_info ("rpv", backup_info.rpv_pvid, lvname, backup_info.rpv_lvid,
	     backup_info.rpv_disk_type, code);
	if code ^= 0 then return;
	dmpr_data_.rpv_pvid = backup_info.rpv_pvid;		/* because the label really doesn't have it	*/
	backup_info.version = backup_info_version_2;
	backup_info.control_file = dmpr_data_.control_name;
	backup_info.operator = dmpr_data_.operator;
	backup_info.dump_type = dmpr_data_.dump_type;
	return;

     end dmpr_info_;
  



		    dmpr_log_.pl1                   10/18/89  1038.4rew 10/18/89  1034.4      345537



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) BULL HN Information Systems Inc., 1989   *
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1989                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */

/****^  HISTORY COMMENTS:
  1) change(86-07-10,GWMay), approve(86-07-10,MCR7445), audit(86-11-20,GDixon),
     install(86-12-09,MR12.0-1238):
     modified the code which allocates the storage for the entrynames in a
     directory to check the number of names. If the names are <0 or greater
     than the calculated limit, the program will report the directory as having
     a problem.  Before this fix the dumper would try to allocate very large
     amounts of storage and blow up.
     
     Changed to use actual file storage for contents names vs allocated
     storage and then assignment.
     
     Changed to use pathname_ and expand_pathname_$add_suffix instead of
     an internal routine.
     
     Changed to check for available space in the .contents_names segment
     instead of using an out_of_bounds condition.
     
     Changed error messages to be more descriptive and fit within 80 chars.
  2) change(86-12-01,GWMay), approve(86-12-01,PBF7445), audit(86-12-01,GDixon),
     install(86-12-09,MR12.0-1238):
     moved call to msf_manager_$adjust after the call to msf_manager_$get_ptr.
     removed calls to terminate_file_ which msf_manager_$adjust was intended
     to replace.
  3) change(89-01-06,GWMay), approve(89-01-06,MCR8039), audit(89-01-09,Farley),
     install(89-01-17,MR12.3-1002):
     Changed to call msf_mgr_$adjust to correctly set the size of the
     <volname>.contents_names segments.
  4) change(89-08-31,GWMay), approve(89-10-03,MCR8135),
     audit(89-10-04,Beattie), install(89-10-12,MR12.3-1092):
     Added support for version 3 backup_volume_log.incl.pl1 structures.
     Initialized new structure values backup_volume_log.Nsaved_(cons
     incr)_sets.
  5) change(89-10-18,GWMay), approve(89-10-18,PBF1089),
     audit(89-10-18,Beattie), install(89-10-18,MR12.3-1094):	
     Fix bug where the values of the new variables were not copied to the
     new log.
                                                   END HISTORY COMMENTS */

/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/

dmpr_log_: proc;

/* This routine provides all the record keeping functions that the volume dumper subsystem requires. It creates
   in use, and the prev output log. In addition this routine creates and updates the contents segment one of
   which exists for each dump volume and the account segment, one of which exists for each dump volume.  The volume log
   contains a record of all dump volumes that contain information taken from that physical volume, the times during
   which the dump volume was written, and some statistics about what was written. The output volume log contains
   a record  of each physical volume written on this  dump volume and a count of how many times it was done.
   The prev volume log contains a record of the last/previous dump volumes that have been written. The contents segment
   contains a uid of every object that was written on a dump volume. The volume log is used by the
   volume reloader and retriever to determine which dump volumes should be read to recover the data. The
   output log is used by the dumper to protect dump volumes from destruction while they still have useful
   information on them. The contents segment is used by the volume retriever to save time by searching the online
   contents segment rather then having to search the dump volume. */
/* Modified:  11/16/81 by GA Texada to not lock the volume log in open_volume_log
	    if the previous volume log wasn't closed before returning.
   Modified:  11/24/81 by GAT to not make a "names" seg unless -names was 
	    specified.
   Modified:  04/05/83 by GA Texada to add a trace capability.
   Modified:  04/84 by GA Texada for version 2 volume logs.

*/
dcl Lall_entry_names     fixed bin (21);
dcl Pall_entry_names     ptr;
dcl all_entry_names	     char (Lall_entry_names) based (Pall_entry_names);
dcl accountp	     ptr;
dcl bit_count	     fixed bin (24);
dcl code		     fixed bin (35);
dcl counted_number_of_entries
		     fixed bin;
dcl counted_number_of_entry_names
		     fixed bin;
dcl dname		     char (168);
dcl ename		     char (32);
dcl found		     bit (1);
dcl i		     fixed bin;
dcl pname		     char (168);
dcl stored_number_of_entry_names
		     fixed bin;
dcl uid_path	     (0:16) bit (36);

dcl account_dir	     char (168) static init (">system_control_1>volume_backup_accounts") options (constant);
dcl dump_idx	     fixed bin int static init (-1);
dcl lock_wait_time	     fixed bin static init (60) options (constant);
dcl max_entry_names	     fixed bin internal static;
dcl max_dir_entries	     fixed bin internal static;
dcl myname	     char (32) static init ("dmpr_log_") options (constant);
dcl set_bc_n_truncate    bit (3) int static init ("110"b) options (constant);
dcl truncate_only	     bit (3) int static init ("010"b) options (constant);

dcl out_of_bounds	     condition;

dcl (addr, bin, clock, divide, fixed, hbound, lbound, length,
  null, ptr, unspec, rel, rtrim, size, substr)
		     builtin;

dcl 1 add_key	     aligned,
    2 flags,
    ( 3 input_key	     bit (1),
      3 input_desc	     bit (1),
      3 mbz	     bit (34)) unal,
    2 desc,
    ( 3 type	     fixed bin (2),
      3 records	     fixed bin (9),
      3 mbz1	     bit (23)) unal,
    2 key_len	     fixed bin,
    2 key		     char (68);

dcl error_table_$action_not_performed ext fixed bin (35);
dcl error_table_$bad_dir fixed bin (35) ext static;
dcl error_table_$bad_index fixed bin (35) ext static;
dcl error_table_$bad_segment fixed bin (35) ext;
dcl error_table_$bad_volid ext fixed bin (35);
dcl error_table_$invalid_lock_reset ext fixed bin (35);
dcl error_table_$namedup fixed bin (35) external;
dcl error_table_$noentry ext fixed bin (35);

dcl sys_info$default_dir_max_length fixed bin (17) ext static;

dcl adjust_bit_count_    entry (char (*), char (*), bit (1), fixed bin, fixed bin (35));
dcl dmpr_report_$online_output entry options (variable);
dcl dmpr_report_$error_output entry options (variable);
dcl expand_pathname_     entry (char (*), char (*), char (*), fixed bin (35));
dcl expand_pathname_$add_suffix entry (char (*), char (*), char (*), char (*), fixed bin (35));
dcl hcs_$chname	     entry (char (*), char (*), char (*), char (*), fixed bin (35));
dcl hcs_$fs_get_path_name entry (ptr, char (*), fixed bin, char (*), fixed bin (35));
dcl hcs_$make_seg	     entry (char (*), char (*), char (*), fixed bin (5), ptr, fixed bin (35));
dcl hcs_$truncate_seg    entry (ptr, fixed bin, fixed bin (35));
dcl ioa_$rsnnl	     entry options (variable);
dcl iox_$attach_ioname   entry (char (*), ptr, char (*), fixed bin (35));
dcl iox_$close	     entry (ptr, fixed bin (35));
dcl iox_$control	     entry (ptr, char (*), ptr, fixed bin (35));
dcl iox_$detach_iocb     entry (ptr, fixed bin (35));
dcl iox_$open	     entry (ptr, fixed bin, bit (36), fixed bin (35));
dcl msf_manager_$adjust  entry (ptr, fixed bin, fixed bin (24), bit (3), fixed bin (35));
dcl msf_manager_$close   entry (ptr);
dcl msf_manager_$get_ptr entry (ptr, fixed bin, bit (1), ptr, fixed bin, fixed bin (35));
dcl msf_manager_$open    entry (char (*), char (*), ptr, fixed bin (35));
dcl pathname_	     entry (char (*), char (*)) returns (char (168));
dcl set_lock_$lock	     entry (bit (36) aligned, fixed bin, fixed bin (35));
dcl set_lock_$unlock     entry (bit (36) aligned, fixed bin (35));
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


create_pvolog: entry (a_volname, code);

dcl a_volname	     char (*);

/* This entry creates the output log , and if successful initializes it */

    code = 0;
    dmpr_data_.pvlp = null;
    dname = "";
    ename = "";
    pname = "";

    pname = rtrim (dmpr_data_.sys_dir) || ">pvolog";
    pname = pathname_ (pname, a_volname);
    call expand_pathname_$add_suffix (pname, "pvolog", dname, ename, code);
    if code ^= 0 then goto log_err;

    pname = pathname_ (dname, ename);
    call hcs_$make_seg (dname, ename, "", 01010b, pvlp, code);
    if code ^= 0 then do;
log_err: call dmpr_report_$error_output (code, myname,
	   "Error creating: ^/^a^/reason",
	   pname);
        code = error_table_$bad_volid;
        return;
      end;

    pvolog.version = pvolog_version_1;
    pvolog.dump_type = dmpr_data_.dump_type;
    pvolog.volid = dmpr_data_.volid;
    pvolog.mount_time = clock;

    dmpr_data_.pvlp = pvlp;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


update_pvolog: entry (code);

/* This entry adds a physical volume name to an output log, if not there already, and increases the usage count
   associated with that physical volume name by one */

    code = 0;
    pvlp = dmpr_data_.pvlp;

    call lock_pvolog;
    if code ^= 0 then return;

    found = "0"b;
    do i = 1 to pvolog.next while (^found);
      pvlep = addr (pvolog.array (i));
      if pvle.pvname = dmpr_data_.pvname then do;
	found = "1"b;
	pvle.invocation_count = pvle.invocation_count + 1;
        end;
    end;
    if ^found then do;
        pvolog.next = pvolog.next + 1;
        pvolog.in_use = pvolog.in_use + 1;
        pvlep = addr (pvolog.array (pvolog.next));
        pvle.invocation_count = 1;
        pvle.pvname = dmpr_data_.pvname;
      end;
    call unlock_pvolog;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


log_object: entry (code);

/* This entry adds the uid of the object to the contents segment and
   the uid pathname of the object to the account segment. */

    code = 0;
    if dmpr_data_.contentsp = null then do;
        code = error_table_$noentry;
        return;
      end;

    contentsp = dmpr_data_.contentsp;
    recordp = dmpr_data_.recordp;

    backup_volume_contents.next = backup_volume_contents.next + 1;
    backup_volume_contents.uid (backup_volume_contents.next) =
         backup_volume_record.uid;
    backup_volume_contents.tape_loc (backup_volume_contents.next) = 0;
    backup_volume_contents.pad1 (backup_volume_contents.next) = "0"b;
    backup_volume_contents.offset (backup_volume_contents.next) = 0;
    backup_volume_contents.component (backup_volume_contents.next) = 0;

    if dmpr_data_.names & backup_volume_record.dirsw then do;

        dp = dmpr_data_.dirp;

        if able_to_count_entry_names () then
	if entry_names_are_ok () then
	  if entry_names_fit_in_contents_seg (Pall_entry_names) then
	    call put_entry_names_in_contents_seg ();
      end;

    if dmpr_data_.accounting then
      call update_accounting_info ();

    if dmpr_data_.trace then
      call dmpr_report_$online_output (0, myname,
	 "Dumping ^12.3b: ^a.",
	 backup_volume_record.uid, convert_puid_ ());

    return;
%page;
/* ************************************************************************* */

able_to_count_entry_names: proc () returns (bit (1) aligned);

/* ************************************************************************* */

    on out_of_bounds begin;
        call dmpr_report_$error_output (error_table_$bad_index, myname,
	   "Due to an out_of_bounds condition,
the names of the entries in the following directory cannot be logged or added
to the contents names segment.
directory uid: ^o
 primary name: ^a
       pvname: ^a
        vtocx: ^o
       reason",
	   dir.uid, backup_volume_record.primary_name,
	   dmpr_data_.pvname, backup_volume_record.vtocx);

        goto exit_count;
      end;

    Lall_entry_names = 0;
    counted_number_of_entry_names = 0;
    counted_number_of_entries = 0;
    stored_number_of_entry_names = 0;

    do ep = ptr (dp, dir.entryfrp) repeat ptr (ep, entry.efrp) while
         (rel (ep) ^= "0"b & counted_number_of_entries <= max_dir_entries);

      stored_number_of_entry_names = stored_number_of_entry_names
	 + entry.nnames;
      counted_number_of_entries = counted_number_of_entries + 1;

      do np = ptr (ep, entry.name_frp) repeat ptr (ep, np -> names.fp)
	 while (rel (np) ^= "0"b & counted_number_of_entry_names <= max_entry_names);

        counted_number_of_entry_names = counted_number_of_entry_names + 1;
        Lall_entry_names = Lall_entry_names
	   + length (rtrim (np -> names.name)) + length (">");

      end;
    end;

    Lall_entry_names = Lall_entry_names + length (">");
    return ("1"b);

exit_count:
    return ("0"b);

  end able_to_count_entry_names;
%page;
/* ************************************************************************* */

entry_names_are_ok: proc () returns (bit (1) aligned);

/* ************************************************************************* */

dcl Serror	     bit (1) aligned;

    Serror = "1"b;

    if stored_number_of_entry_names ^= counted_number_of_entry_names
    then do;
        call dmpr_report_$error_output (error_table_$bad_dir, myname,
	   "The actual number of entry names in the directory does not match
the number of entry names stored in the directory entries.
counted: ^d   stored: ^d
directory uid: ^o
 primary name: ^a
       pvname: ^a
        vtocx: ^o
       reason",
	   counted_number_of_entry_names, stored_number_of_entry_names,
	   dir.uid, backup_volume_record.primary_name,
	   dmpr_data_.pvname, backup_volume_record.vtocx);
        Serror = "0"b;
      end;

    if stored_number_of_entry_names < 0
         | stored_number_of_entry_names > max_entry_names then do;

        call dmpr_report_$error_output (error_table_$bad_dir, myname,
	   "The total number of names referenced by directory entries is
negative or exceeds the maximum number of names a directory will hold.
         value: ^d
 directory uid: ^o
  primary name: ^a
        pvname: ^a
         vtocx: ^o
        reason",
	   stored_number_of_entry_names, dir.uid,
	   backup_volume_record.primary_name, dmpr_data_.pvname,
	   backup_volume_record.vtocx);
        Serror = "0"b;
      end;
    return (Serror);
  end entry_names_are_ok;
%page;
/* ************************************************************************* */

entry_names_fit_in_contents_seg: proc (Pentry_name_storage)
       returns (bit (1) aligned);

/* ************************************************************************* */

dcl Pentry_name_storage  ptr,
  return_bit	     bit (1) aligned;

dcl next_word_offset     fixed bin (19);

dcl sys_info$max_seg_size fixed bin (35) ext static;

    Pentry_name_storage = null;
    return_bit = "0"b;
    next_word_offset = 0;
    contents_namesp = dmpr_data_.contents_namesp;

    next_word_offset = backup_volume_contents_names.offset
         + divide (Lall_entry_names + (CHARS_PER_WORD - 1),
         CHARS_PER_WORD, 18, 0);

    if next_word_offset > sys_info$max_seg_size then do;
        bit_count = backup_volume_contents_names.offset * BITS_PER_WORD;
        call msf_manager_$adjust (dmpr_data_.fcbp, dmpr_data_.component,
	   bit_count, set_bc_n_truncate, code);

        if code ^= 0 then do;
	  dmpr_data_.names = "0"b;
	  call dmpr_report_$online_output (code, dmpr_data_.myname,
	       "Unable to truncate component in multisegment file:
^a>contents>^a.contents,
Attempting to truncate and set bit count for component ^d.
Names collection turned OFF.^/reason",
	       dmpr_data_.sys_dir, dmpr_data_.volname,
	       dmpr_data_.component);
	  return ("0"b);
	end;

        dmpr_data_.component = dmpr_data_.component + 1;
        call msf_manager_$get_ptr (dmpr_data_.fcbp, dmpr_data_.component,
	   "1"b, contents_namesp, 0, code);

        if code ^= 0 then do;
	  dmpr_data_.names = "0"b;
	  call dmpr_report_$online_output (code, dmpr_data_.myname,
	       "Unable to get next component in multisegment file:
^a>contents>^a.contents,
Attempting to get component ^d. Names collection turned OFF.^/reason",
	       dmpr_data_.sys_dir, dmpr_data_.volname,
	       dmpr_data_.component);
	  return ("0"b);
	end;

        else do;
	  dmpr_data_.contents_namesp = contents_namesp;
	  backup_volume_contents_names.version =
	       backup_volume_contents_version_3;
	  backup_volume_contents_names.offset =
	       bin (rel (addr (backup_volume_contents_names.begin)));
	  backup_volume_contents_names.pad (*) = "0"b;

	  next_word_offset = backup_volume_contents_names.offset
	       + divide (Lall_entry_names + (CHARS_PER_WORD - 1),
	       CHARS_PER_WORD, 18, 0);
	end;
      end;

    Pentry_name_storage =
         ptr (contents_namesp, backup_volume_contents_names.offset);

    backup_volume_contents.offset (backup_volume_contents.next) =
         backup_volume_contents_names.offset;

    backup_volume_contents.component (backup_volume_contents.next) =
         dmpr_data_.component;

    backup_volume_contents_names.offset = next_word_offset;

    return ("1"b);
  end entry_names_fit_in_contents_seg;
%page;
/* ************************************************************************* */

put_entry_names_in_contents_seg: proc ();

/* ************************************************************************* */

dcl Lcurrent_name	     fixed bin,
  current_position	     fixed bin;

    Lcurrent_name = 0;
    all_entry_names = "";
    current_position = 1;

    do ep = ptr (dp, dir.entryfrp) repeat ptr (ep, entry.efrp)
         while (rel (ep) ^= "0"b);

      do np = ptr (ep, entry.name_frp)
	 repeat ptr (ep, np -> names.fp) while (rel (np) ^= "0"b);

        Lcurrent_name = length (rtrim (np -> names.name));
        substr (all_entry_names, current_position, Lcurrent_name)
	   = substr (np -> names.name, 1, Lcurrent_name);

        current_position = current_position + Lcurrent_name;
        Lcurrent_name = length (">");
        substr (all_entry_names, current_position, Lcurrent_name) = ">";

        current_position = current_position + Lcurrent_name;
      end;
    end;

    Lcurrent_name = length (">");
    substr (all_entry_names, current_position, Lcurrent_name) = ">";
    return;

  end put_entry_names_in_contents_seg;
%page;
/* ************************************************************************* */

update_accounting_info: proc ();

/* ************************************************************************* */

    do i = lbound (backup_volume_record.uid_path, 1) to
         hbound (backup_volume_record.uid_path, 1)
         while (backup_volume_record.uid_path (i) ^= "0"b);

      uid_path (i) = backup_volume_record.uid_path (i);
    end;
    i = i + 1;
    uid_path (i) = backup_volume_record.uid;
    add_key.input_key = "1"b;
    add_key.input_desc = "1"b;
    add_key.key_len = i * 4;
    unspec (add_key.key) = unspec (uid_path);
    add_key.records = fixed (backup_volume_record.records, 9);
    add_key.type = dmpr_data_.dump_type;
    call iox_$control (dmpr_data_.account_iocbp, "add_key", addr (add_key),
         code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Error adding key to account file:^/^a>^a.account^/reason",
	 account_dir, dmpr_data_.volname);

    return;
  end update_accounting_info;

/*  end dmpr_log_$log_object */

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


close_account_file: entry (code);

/* This entry closes down an account file */

    if dmpr_data_.account_iocbp = null then return;
    call iox_$close (dmpr_data_.account_iocbp, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname,
	   "Unable to close account file:^/^a>^a^/reason",
	   account_dir, dmpr_data_.volname);
        return;
      end;
    call iox_$detach_iocb (dmpr_data_.account_iocbp, code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Unable to detach account file:^/^a>^a^/reason",
	 account_dir, dmpr_data_.volname);
    dmpr_data_.account_iocbp = null;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


init_account_file: entry (code);

/* This entry creates the account segment in a specified directory and if successful initializes it and
   sets a pointer to in static. */

    code = 0;
    dname = "";
    ename = "";
    pname = "";

    pname = pathname_ (account_dir, (dmpr_data_.volname));
    call expand_pathname_$add_suffix (pname, "account", dname, ename, code);
    if code ^= 0 then goto acct_err;

    pname = pathname_ (dname, ename);
retry_acc: call hcs_$make_seg (dname, ename, "", 01010b, accountp, code);
    if code ^= 0 then do;
        if code = error_table_$namedup then do;
	  call rename_account_file (dname, ename, ename, 1, code);
	  if code = 0 then goto retry_acc;
	end;
acct_err: call dmpr_report_$error_output (code, myname,
	   "Error creating:^/^a^/reason",
	   pname);
        return;
      end;

    call iox_$attach_ioname ("account_file", dmpr_data_.account_iocbp,
         "vfile_ " || rtrim (pname) || " -dup_ok", code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname,
	   "Error attaching account file:^/^a^/reason",
	   pname);
        return;
      end;
    call iox_$open (dmpr_data_.account_iocbp, Direct_update, "0"b, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname,
	   "Error opening account file:^/^a^/reason",
	   pname);
        return;
      end;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


open_volume_log: entry (code);

/* This entry creates a volume log entry. It also takes care to close off any old entries
   which this entries superceeds. This must be done as the volume retriever will not use an entry that
   is not closed. If it were to do so the first entry it would use would be the volume presently mounted.  This,
   of course restricts the volume dumper such that now two dumper processes should dump the same physical volume
   in the same mode of operation */

    code = 0;
    if dump_idx ^= -1 then return;			/* two updates without a close */
    bvlp = dmpr_data_.bvlp;

    call lock_volume_log;				/* protect against two updates */
    if code ^= 0 then return;


    do i = backup_volume_log.next to 1 by -1;
      bvlep = addr (backup_volume_log.array (i));
      if bvle.close_time = 0 & bvle.dump_type = dmpr_data_.dump_type then do;
	bvle.close_time = clock;
	if dmpr_data_.restart_pvname ^= "" then
	  dmpr_data_.cycle_uid = bvle.cycle_uid;
        end;
    end;

    backup_volume_log.next = backup_volume_log.next + 1;
    backup_volume_log.rpv_pvid = dmpr_data_.rpv_pvid;
    dump_idx = backup_volume_log.next;
    bvlep = addr (backup_volume_log.array (dump_idx));

    bvle.dump_type = dmpr_data_.dump_type;		/* update new record */
    bvle.volid = dmpr_data_.volid;
    bvle.volname = dmpr_data_.volname;
    bvle.open_time = clock;
    bvle.cycle_uid = dmpr_data_.cycle_uid;
    bvle.close_time = 0;
    bvle.io_module = dmpr_data_.io_module;
    bvle.dir_num, bvle.dir_rec = -1;
    bvle.seg_num, bvle.seg_rec = -1;
    dmpr_data_.vol_log_dir_num = 0;
    dmpr_data_.vol_log_dir_rec = 0;
    dmpr_data_.vol_log_seg_num = 0;
    dmpr_data_.vol_log_seg_rec = 0;
open_ret:
    call unlock_volume_log;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


close_volume_log: entry (code);

/* This entry closes a volume log entry. The internal static variable dump_indx is used in attemp to remenber
   what entry was in use, but it must be checked as a purge of the volume log can shift entries. If things have moved
   a linear search is made for the previous entry. In either case the entry is closed. */

    code = 0;
    if dump_idx = -1 then return;			/* its closed already */

    bvlp = dmpr_data_.bvlp;

    call lock_volume_log;
    if code ^= 0 then return;

    bvlep = addr (backup_volume_log.array (dump_idx));

    if (bvle.volname = dmpr_data_.volname
         & bvle.dump_type = dmpr_data_.dump_type
         & bvle.cycle_uid = dmpr_data_.cycle_uid
         & bvle.close_time = 0) then ;
    else do;
        do dump_idx = 1 to backup_volume_log.next;	/* it may have moved */
	bvlep = addr (backup_volume_log.array (dump_idx));
	if (bvle.volname = dmpr_data_.volname
	     & bvle.dump_type = dmpr_data_.dump_type
	     & bvle.cycle_uid = dmpr_data_.cycle_uid
	     & bvle.close_time = 0) then goto close_log_entry;
        end;
        code = error_table_$action_not_performed;
        call dmpr_report_$error_output (code, myname,
	   "Unable to close:^/^a.volog^/reason",
	   dmpr_data_.pvname);
        goto reset_log_data;
      end;
close_log_entry:
    bvle.close_time = clock;
    bvle.dir_num = dmpr_data_.vol_log_dir_num;
    bvle.dir_rec = dmpr_data_.vol_log_dir_rec;
    bvle.seg_num = dmpr_data_.vol_log_seg_num;
    bvle.seg_rec = dmpr_data_.vol_log_seg_rec;
reset_log_data:
    dmpr_data_.vol_log_dir_num = 0;
    dmpr_data_.vol_log_dir_rec = 0;
    dmpr_data_.vol_log_seg_num = 0;
    dmpr_data_.vol_log_seg_rec = 0;
    call set_bc (bvlp);
    call unlock_volume_log;
    dump_idx = -1;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


init_contents_seg: entry (code);

/* This entry create a contents segment and, if successful, initializes it. Note that since contents are written
   out they must contain a logical record header. */

    code = 0;

    dname = "";
    ename = "";
    pname = "";

    pname = rtrim (dmpr_data_.sys_dir) || ">contents";
    pname = pathname_ (pname, (dmpr_data_.volname));
    call expand_pathname_$add_suffix (pname, "contents", dname, ename, code);
    if code ^= 0 then goto cont_err;

    pname = pathname_ (dname, ename);
    call hcs_$make_seg (dname, ename, "", 01010b, contentsp, code);
    if contentsp ^= null then do;
        call hcs_$truncate_seg (contentsp, 0, code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, myname,
	       "Unable to truncate:^/^a^/reason",
	       pname);
	  code = 0;
	  return;
	end;
      end;
    else do;
cont_err: call dmpr_report_$error_output (code, myname,
	   "Error creating:^/^a^/reason",
	   pname);
        return;
      end;
    call init_header (contentsp, contents_type);
    dmpr_data_.contentsp = contentsp;
    backup_volume_contents.version = backup_volume_contents_version_3;
    backup_volume_contents.volname = dmpr_data_.volname;
    backup_volume_contents.volid = dmpr_data_.volid;
    backup_volume_contents.next = 0;
    backup_volume_contents.pad (*) = "0"b;

    if dmpr_data_.names then do;
        if dmpr_data_.contents_namesp ^= null then do;
	  bit_count = backup_volume_contents_names.offset * BITS_PER_WORD;
	  call msf_manager_$adjust (dmpr_data_.fcbp, dmpr_data_.component,
	       bit_count, set_bc_n_truncate, code);
	  call msf_manager_$close (dmpr_data_.fcbp);
	end;

        dmpr_data_.fcbp = null;
        dmpr_data_.contents_namesp = null;
        pname = rtrim (dmpr_data_.sys_dir) || ">contents>" ||
	   rtrim (dmpr_data_.volname) || ".contents_names";

        call expand_pathname_ (pname, dname, ename, code);

        if code ^= 0 then do;
name_err:	  dmpr_data_.names = "0"b;
	  call dmpr_report_$error_output (code, myname,
	       "Error creating:^/^a^/- names collection aborted.^/reason",
	       pname);
	  return;
	end;
        dmpr_data_.component = 0;
        call msf_manager_$open (dname, ename, dmpr_data_.fcbp, code);
        if code ^= 0 & code ^= error_table_$noentry then do;
	  call dmpr_report_$error_output (code, myname,
	       "Unable to open:^/^a^/- names collection aborted.^/reason",
	       pname);
	  dmpr_data_.names = "0"b;
	  code = 0;
	  return;
	end;
        call msf_manager_$get_ptr (dmpr_data_.fcbp, dmpr_data_.component, "1"b, contents_namesp, 0, code);
        if code ^= 0 then go to name_err;

        call msf_manager_$adjust (dmpr_data_.fcbp, dmpr_data_.component, 0, truncate_only, code);

        dmpr_data_.contents_namesp = contents_namesp;
        backup_volume_contents_names.version = backup_volume_contents_version_3;
        backup_volume_contents_names.offset =
	   bin (rel (addr (backup_volume_contents_names.begin)));
        backup_volume_contents_names.pad (*) = "0"b;

        max_entry_names = divide (sys_info$default_dir_max_length - size (dir)
	   - size (entry), size (names), 17);

        max_dir_entries = divide (sys_info$default_dir_max_length - size (dir),
	   size (entry), 17);
      end;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


init_volume_log: entry (code);

/* This entry locates the volume log. If one does not exist it is created and initialized. Note that since volume
   logs are written out they must have a logical record header. */

    code = 0;
    dmpr_data_.bvlp = null;
    dname = "";
    ename = "";
    pname = "";
    pname = pathname_ ((dmpr_data_.sys_dir), (dmpr_data_.pvname));
    call expand_pathname_$add_suffix (pname, "volog", dname, ename, code);
    if code ^= 0 then goto vol_err;

    pname = pathname_ (dname, ename);
    call hcs_$make_seg (dname, ename, "", 01010b, bvlp, code);
    if code = 0 then do;
        call dmpr_report_$online_output (0, myname,
	   "new volume log created:^/^a",
	   pname);
        backup_volume_log.pvname = dmpr_data_.pvname;
        backup_volume_log.pvid = dmpr_data_.pvid;
        backup_volume_log.reload_groups = 2;		/* default value */
        backup_volume_log.version = backup_volume_log_version_3;
        backup_volume_log.disk_type = dmpr_data_.disk_type;
        backup_volume_log.rpv_pvid = dmpr_data_.rpv_pvid;
        backup_volume_log.Nsaved_cons_sets = -1;
        backup_volume_log.Nsaved_incr_sets = -1;
      end;
    else if bvlp ^= null then do;
        code = 0;
        if (backup_volume_log.pvname = dmpr_data_.pvname
	   & backup_volume_log.pvid = dmpr_data_.pvid) then do;
	  if backup_volume_log.version = backup_volume_log_version_1 |
	     backup_volume_log.version = backup_volume_log_version_2 |
	     backup_volume_log.version = backup_volume_log_version_3 then do;
	     backup_volume_log.version = backup_volume_log_version_3;
	     backup_volume_log.disk_type = dmpr_data_.disk_type;
	     backup_volume_log.rpv_pvid = dmpr_data_.rpv_pvid;
	     end;
	  else goto invalid_volog;
	end;
        else do;
invalid_volog: code = error_table_$bad_segment;
	  call dmpr_report_$error_output (code, myname,
	       "Invalid ^a.volog^/reason",
	       dmpr_data_.pvname);
	  return;
	end;
      end;
    else do;
vol_err: call dmpr_report_$error_output (code, myname,
	   "Error getting ptr to:^/^a^/reason",
	   pname);
        return;
      end;

    if backup_volume_log.pattern1 ^= pattern1
         | backup_volume_log.pattern2 ^= pattern2
         | backup_volume_log.pattern3 ^= pattern3 then
      call init_header (bvlp, volume_log_type);
    dmpr_data_.bvlp = bvlp;
    return;
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


/* The following six internal proc lock and unlock the various logs. They are all very similar except
   that they deal with different logs. They all assume that the local pointer has been set from its static
   value.  */

lock_pvolog: proc;
    call set_lock_$lock (pvolog.lock, lock_wait_time, code);
    if code ^= 0 then do;
        if code = error_table_$invalid_lock_reset then code = 0;
        else call dmpr_report_$error_output (code, myname,
	        "Unable to lock ^a.pvolog^/reason",
	        dmpr_data_.volname);
      end;
    return;

  end lock_pvolog;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


unlock_pvolog: proc;
    call set_lock_$unlock (pvolog.lock, code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Error unlocking ^a.pvolog^/reason",
	 dmpr_data_.volname);
    return;

  end unlock_pvolog;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


lock_volume_log: proc;
    call set_lock_$lock (backup_volume_log.lock, lock_wait_time, code);
    if code ^= 0 then do;
        if code = error_table_$invalid_lock_reset then code = 0;
        else call dmpr_report_$error_output (code, myname,
	        "Unable to lock ^a.volog^/reason",
	        dmpr_data_.pvname);
      end;
    return;

  end lock_volume_log;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


unlock_volume_log: proc;
    call set_lock_$unlock (backup_volume_log.lock, code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Error unlocking ^a.volog^/reason",
	 dmpr_data_.pvname);
    return;

  end unlock_volume_log;
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


init_header: proc (tp, type);

/* This proc initializes the logical volume header that is a part of all objects, except segments
   and directories, which it preceeds, which are written out. */

dcl tp		     ptr;
dcl type		     fixed bin;

    tp -> backup_volume_log.pattern1 = pattern1;
    tp -> backup_volume_log.pattern2 = pattern2;
    tp -> backup_volume_log.pattern3 = pattern3;

    tp -> backup_volume_log.rec1_type = type;
    tp -> backup_volume_log.rec2_len = 0;
    tp -> backup_volume_log.rec2_type = null_type;
    return;

  end init_header;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


set_bc: proc (p);
dcl p		     ptr;
dcl dn		     char (168);
dcl en		     char (32);
dcl ldn		     fixed bin;
    call hcs_$fs_get_path_name (p, dn, ldn, en, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname,
	   "Unable to convert ptr to pathname for bit count setting^/reason");
        code = 0;
        return;
      end;
    call adjust_bit_count_ (dn, en, "0"b, (0), code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Unable to set bit count of ^a>^a^/reason",
	 dn, en);
    code = 0;
  end set_bc;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


rename_account_file: proc (dn, prefix, en, a_suffix, ec);

/* This proc recursively renames account segs with a numeric suffix utile a namedup is not encountered. This
   preserves the account segs in reverse numeric order for later processing. */

dcl dn		     char (*);
dcl prefix	     char (*);
dcl en		     char (*);
dcl new_en	     char (32);
dcl suffix	     fixed bin;
dcl a_suffix	     fixed bin;
dcl ec		     fixed bin (35);
    suffix = a_suffix;
    call ioa_$rsnnl ("^a.^d", new_en, (0), prefix, suffix);
retry_rn: call hcs_$chname (dn, en, en, new_en, ec);
    if ec = error_table_$namedup then do;
        call rename_account_file (dn, prefix, new_en, suffix + 1, ec);
        if ec = 0 then goto retry_rn;
      end;

  end rename_account_file;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/* This proc is used to convert a unique id pathname to an ascii pathname  */

convert_puid_: proc returns (char (168));

dcl (dn, ret_dn)	     char (168);
dcl en		     char (32);
dcl ec		     fixed bin (35);
dcl seg_fault_error	     condition;
dcl error_table_$root    ext fixed bin (35);
dcl hc_backup_$decode_uidpath entry options (variable);
    on seg_fault_error goto ret_unk;

    call hc_backup_$decode_uidpath (backup_volume_record.uid_path, dn, en, ec);
    if ec = error_table_$root then ;
    else if ec ^= 0 then
ret_unk: return ("UNKNOWN_PATH>" || rtrim (backup_volume_record.primary_name, "  "));
    call ioa_$rsnnl ("^a^[>^]^[^a>^;^s^]^a", ret_dn, (0), dn, dn ^= ">", en ^= "", en, backup_volume_record.primary_name);
    return (ret_dn);
  end convert_puid_;
%page;
%include backup_static_variables;
%page;
%include backup_volume_contents;
%page;
%include backup_volume_header;
%page;
%include backup_volume_record;
%page;
%include backup_volume_log;
%page;
%include backup_pvol_info;
%page;
%include dir_header;
%page;
%include dir_name;
%page;
%include dir_entry;
%page;
%include dmpr_data_;
%page;
%include fs_vol_label;
%page;
%include iox_modes;
%page;
%include pvolog;
%page;
%include system_constants;
%page;
%include vtoce;
  end dmpr_log_;
   



		    dmpr_output_.pl1                10/10/89  1422.4r w 10/10/89  1359.8      338508



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1988                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */




/****^  HISTORY COMMENTS:
  1) change(88-10-05,GWMay), approve(88-10-05,MCR8005), audit(88-10-12,Farley),
     install(88-10-17,MR12.2-1173):
     Changed to output a unique string to delimit each set of system data
     dumped.
                                                   END HISTORY COMMENTS */


/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/
dmpr_output_: proc;

/* This routine writes the objects that are being dumped through the specified switch. It controls
   error recovery and volume attachment for the switch. Any object written is preceeded by logical header which
   identifies its type and length and provides a unique pattern in case resynchronization is necessary. */

/* 1) Modified:	12/17/81 by GA Texada to add a query in the attach proc to enable a clean exit.	    */
/*			  and to fix phxXXXXX					    */
/* 2) Modified:	7/15/82 by GA Texada to fix hardcore 372 (phx01702).			    */
/* 3) Modified:	11/12/82 by GA Texada to implement phx14088,				    */
/*	implements preattach_(vols ioname)						    */
/* 4) Modified:	1/26/83 to set dmpr_data_.cur_vol_open					    */
/* 5) Modified:     August 1983 by GA Texada to add new_pass_attach and end_pass_detach.		    */
/* 6) Modified:	April 1985 by SGH (UNCA) to fix preattach cleanup -- phx17367,
		to complete fix for phx8938, and to synchronize output after
		non-null objects */

dcl dirname	     char (168);
dcl ename		     char (32);
dcl ldn		     fixed bin;
dcl current_length	     fixed bin;
dcl attach_name	     char (32);
dcl answer	     char (3) var;
dcl error_count	     fixed bin;
dcl prev_contentsp	     ptr;
dcl retry		     bit (1);
dcl new_tape	     bit (1);
dcl att_desc	     char (256);
dcl write_volume_log     bit (1);
dcl code		     fixed bin (35);
dcl ignore	     fixed bin (35);
dcl datap		     ptr;
dcl (prex, sprex)	     fixed bin;
dcl pagex		     fixed bin;
dcl pagep		     ptr;
dcl page_of_chars	     char (CHARS_PER_PAGE) based (pagep) aligned;
dcl page_by_page	     bit (1);
dcl start_numeric	     fixed bin;
dcl char_num	     char (32);
dcl num		     fixed bin;

dcl myname	     char (32) int static init ("dmpr_output_") options (constant);
dcl max_error_count	     fixed bin int static options (constant) init (64);
dcl zero_char	     char (1) int static init (" ") options (constant);
dcl ascii_type	     (3) char (4) int static init ("incr", "cons", "comp") options (constant);
dcl retry_explanation    char (143) init (
		     "The attachment of the dump volume has failed. 
A ""yes"" answer will attempt to reattach the same volume. 
A ""no"" answer will terminate the dump.") int static options (constant);
dcl delete_explanation   char (148) init (
		     "The open of the dump volume has failed.
A ""yes"" answer will delete the volume from the volume pool.
A ""no"" answer will leave the volume in the pool.") int static options (constant);
dcl continue_explanation char (141) init (
		     "The open of the dump volume has failed.
A ""yes"" answer will continue the dump with a different volume.
A ""no"" answer will terminate the dump.") int static options (constant);


dcl 1 volid	     aligned,
    2 char	     char (2) unaligned,
    2 num		     fixed bin unaligned;


dcl 1 local_status_branch like status_branch aligned;

dcl command_query_	     entry options (variable);
dcl continue_to_signal_  entry (fixed bin (35));
dcl suffixed_name_$make  entry (char (*), char (*), char (*), fixed bin (35));
dcl manage_volume_pool_$reserve entry (ptr, entry options (variable), char (*), char (*), char (*),
		     fixed bin (35));
dcl manage_volume_pool_$allocate entry (ptr, entry options (variable), char (*), char (*), char (*),
		     fixed bin (35));
dcl manage_volume_pool_$free entry (ptr, entry options (variable), char (*), fixed bin (35));
dcl manage_volume_pool_$delete entry (ptr, entry options (variable), char (*), fixed bin (35));
dcl manage_volume_pool_$set_volid entry (ptr, entry options (variable), char (*), bit (36), fixed bin (35));
dcl cv_dec_check_	     entry (char (*), fixed bin (35)) returns (fixed bin);
dcl iox_$attach_ioname   entry (char (*), ptr, char (*), fixed bin (35));
dcl iox_$control	     entry (ptr, char (*), ptr, fixed bin (35));
dcl iox_$modes	     entry (ptr, char (*), char (*), fixed bin (35));
dcl iox_$open	     entry (ptr, fixed bin, bit (36), fixed bin (35));
dcl iox_$put_chars	     entry (ptr, ptr, fixed bin, fixed bin (35));
dcl iox_$close	     entry (ptr, fixed bin (35));
dcl iox_$detach_iocb     entry (ptr, fixed bin (35));
dcl dmpr_output_$preattach_vols entry (fixed bin, fixed bin, fixed bin (35));
dcl dmpr_output_$preattach_ioname entry (fixed bin, fixed bin, fixed bin (35));
dcl dmpr_report_$error_output entry options (variable);
dcl dmpr_log_$init_account_file entry (fixed bin (35));
dcl dmpr_log_$close_account_file entry (fixed bin (35));
dcl dmpr_log_$open_volume_log entry (fixed bin (35));
dcl dmpr_log_$close_volume_log entry (fixed bin (35));
dcl dmpr_log_$init_contents_seg entry (fixed bin (35));
dcl dmpr_log_$update_pvolog entry (fixed bin (35));
dcl dmpr_log_$create_pvolog entry (char (*), fixed bin (35));
dcl hcs_$delentry_seg    entry (ptr, fixed bin (35));
dcl hcs_$initiate	     entry (char (*), char (*), char (*), fixed bin,
		     fixed bin, ptr, fixed bin (35));
dcl hcs_$terminate_seg   entry (ptr, fixed bin, fixed bin (35));
dcl hcs_$fs_get_path_name entry (ptr, char (*), fixed bin, char (*), fixed bin (35));
dcl adjust_bit_count_    entry (char (*), char (*), bit (1), fixed bin, fixed bin (35));
dcl hcs_$status_long     entry (char (*), char (*), fixed bin, ptr, ptr, fixed bin (35));
dcl dmpr_report_$online_output entry options (variable);
dcl ioa_$rsnnl	     entry options (variable);
dcl unique_bits_	     entry () returns (bit (70));
dcl tape_check	     bit (72);
dcl seg_fault_error	     condition;
dcl page_read_error	     condition;
dcl page_fault_error     condition;

dcl error_table_$segfault ext fixed bin (35);
dcl error_table_$bad_volid ext fixed bin (35);
dcl error_table_$action_not_performed ext fixed bin (35);
dcl error_table_$device_end ext fixed bin (35);
dcl error_table_$end_of_info ext fixed bin (35);
dcl error_table_$fatal_error ext fixed bin (35);
dcl error_table_$undefined_order_request ext fixed bin (35);
dcl error_table_$no_operation ext fixed bin (35);

dcl (addr, substr, null, size, fixed, ptr, search, unspec, length, rtrim, clock) builtin;
dcl (before, bit, divide) builtin;

init: entry (code);

/* This entry initializes the output routine.  It sets up the logical record header and attaches the
   number of output volumes requested */

dcl local_pre_attach_vol fixed bin;			/* for use in preattaching volumes		*/

    code = 0;
    write_volume_log = ""b;
    query_info.version = query_info_version_5;
    query_info.yes_or_no_sw = "1"b;
    recordp = dmpr_data_.recordp;
    backup_volume_record.version = backup_volume_record_version_2;
    backup_volume_record.pattern1 = pattern1;
    backup_volume_record.pattern2 = pattern2;
    backup_volume_record.pattern3 = pattern3;

    if dmpr_data_.pre_attach_vol > 0 then do;
        local_pre_attach_vol = dmpr_data_.pre_attach_vol;
        dmpr_data_.pre_attach_vol = 0;
        call dmpr_output_$preattach_vols (local_pre_attach_vol, 1, code);
        if code ^= 0 then return;
        call dmpr_report_$online_output (0, dmpr_data_.myname, "Please get the following volumes: ^v(^a ^)",
	   local_pre_attach_vol, dmpr_data_.pre_attach_volname (*));
        dmpr_data_.pvlp = null;
        dmpr_data_.volid = "0"b;
        dmpr_data_.volname = "";
        call dmpr_output_$preattach_ioname (local_pre_attach_vol, 1, code);
        if code ^= 0 then return;
        dmpr_data_.pre_attach_vol = local_pre_attach_vol;
      end;
    call attach;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

new_pass_attach: entry (code);

    write_volume_log = ""b;
    call attach ();					/* takes care of errors himself		*/
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

end_pass_detach: entry (code);

    write_volume_log = ""b;
    call detach ();
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


output_object: entry (datap, code);

/* This entry writes the vtoce and the object , if one exists, on the attached switch.  If the object has
   pages of zeros it is written out in a compacted form. The output strategy is to write the object
   untill the write succedes. Thus if an object spans a dump volume , it will be rewritten, in
   its entirity on the new dump volume */

    code = 0;
    write_volume_log = ""b;
    query_info.version = query_info_version_5;
    query_info.yes_or_no_sw = "1"b;
    recordp = dmpr_data_.recordp;
    bvlp = dmpr_data_.bvlp;
    page_by_page = "0"b;
    backup_volume_record.rec1_type = vtoce_type;
    backup_volume_record.rec1_len = CHARS_PER_WORD * size (backup_volume_record);

    if datap ^= null then do;
        if backup_volume_record.dirsw then backup_volume_record.rec2_type = dir_type;
        else backup_volume_record.rec2_type = seg_type;
        if fixed (backup_volume_record.csl, 9) ^= fixed (backup_volume_record.records, 9) then do;
	  page_by_page = "1"b;
	  backup_volume_record.rec2_len = CHARS_PER_PAGE * fixed (backup_volume_record.records, 9);
	end;
        else if fixed (backup_volume_record.csl, 9) = 0 then backup_volume_record.rec2_len = 0;
        else backup_volume_record.rec2_len = CHARS_PER_PAGE * (fixed (backup_volume_record.records, 9) - 1)
	        + CHARS_PER_WORD * last_page_length ();
      end;
    else do;
        backup_volume_record.rec2_type = null_type;
        backup_volume_record.rec2_len = 0;
      end;

start_io:
    retry = "1"b;
    do while (retry);				/* write the VTOCE for this seg/dir */
      call iox_$put_chars (dmpr_data_.outputvol_iocbp, recordp,
	 backup_volume_record.rec1_len, code);
      call check_output_error;
    end;

    on seg_fault_error, page_fault_error begin;
        if tape_check ^= ""b then do;
	  call iox_$put_chars (dmpr_data_.outputvol_iocbp,
	       addr (tape_check), size (tape_check) * CHARS_PER_WORD, code);
	  call check_output_error;
	end;
        call continue_to_signal_ (code);
      end;

    tape_check = ""b;				/* write the data from this seg/dir */
    if backup_volume_record.rec2_len ^= 0 then do;
        tape_check = dmpr_data_.volid || substr (unique_bits_ (), 35);
        call iox_$put_chars (dmpr_data_.outputvol_iocbp,
	   addr (tape_check), size (tape_check) * CHARS_PER_WORD, code);
        call check_output_error;
        if new_tape then goto start_io;

        if ^page_by_page then do;
	  retry = "1"b;
	  do while (retry);
	    call iox_$put_chars (dmpr_data_.outputvol_iocbp, datap,
	         backup_volume_record.rec2_len, code);
	    call check_output_error;
	    if new_tape then goto start_io;
	  end;
	end;
        else call page_by_page_write;

        call iox_$put_chars (dmpr_data_.outputvol_iocbp,
	   addr (tape_check), size (tape_check) * CHARS_PER_WORD, code);
        call check_output_error;
        if new_tape then goto start_io;
        tape_check = ""b;				/* back to "" so it doesn't get written below */

        call iox_$control (dmpr_data_.outputvol_iocbp, "error_count", addr (error_count), code); /* force output synchronization */
        if ^(code = error_table_$undefined_order_request | code = error_table_$no_operation) then do;
	  if code = 0 then
	    if error_count > max_error_count then
	      code = error_table_$fatal_error;		/* too many errors, abandon tape */
	  call check_output_error;
	  if new_tape then goto start_io;
	end;
      end;
non_local_return:
    if tape_check ^= ""b then do;
        call iox_$put_chars (dmpr_data_.outputvol_iocbp,
	   addr (tape_check), size (tape_check) * CHARS_PER_WORD, code);
        call check_output_error;
      end;

    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


preattach_vols:
  entry (nvols_to_get, begin_indx, mcode);

dcl (nvols_to_get, begin_indx) fixed bin,
  mcode		     fixed bin (35),
  safe_pvlp	     ptr,				/* use to save the current values		*/
  safe_volname	     char (32),			/* crucial variables from dmpr_data_		*/
  safe_volid	     bit (36);			/* when doing this routine			*/

    safe_volname = dmpr_data_.volname;
    safe_volid = dmpr_data_.volid;
    safe_pvlp = dmpr_data_.pvlp;
    write_volume_log = ""b;

    do prex = begin_indx to (dmpr_data_.pre_attach_vol + nvols_to_get);
      call get_volname (mcode);
      if mcode ^= 0 then goto restore_safe;
      dmpr_data_.pre_attach_volname (prex) = dmpr_data_.volname;
      dmpr_data_.pre_attach_volid (prex) = dmpr_data_.volid;
      dmpr_data_.pre_attach_pvlp (prex) = dmpr_data_.pvlp;
    end;
restore_safe:
    dmpr_data_.volname = safe_volname;			/* restore all these			*/
    dmpr_data_.volid = safe_volid;
    dmpr_data_.pvlp = safe_pvlp;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


preattach_ioname:
  entry (nvols_to_name, begin_indx, picode);

dcl nvols_to_name	     fixed bin,
  picode		     fixed bin (35);

    write_volume_log = ""b;
    do prex = begin_indx to (dmpr_data_.pre_attach_vol + nvols_to_name);
      call ioa_$rsnnl ("^a.^d", attach_name, (0), "dump_volume", prex);
      if dmpr_data_.att_desc ^= "" then
        call ioa_$rsnnl (dmpr_data_.att_desc, att_desc, (0), dmpr_data_.pre_attach_volname (prex));
      else call ioa_$rsnnl ("tape_mult_ ^a -write -system", att_desc, (0), dmpr_data_.pre_attach_volname (prex));
      dmpr_data_.io_module = before (att_desc, " ");
      call iox_$attach_ioname (attach_name, dmpr_data_.pre_attach_iocbp (prex), att_desc, picode);
      if picode ^= 0 then do;
	call dmpr_report_$error_output (picode, myname, "Unable to attach ^a via desc ^a", attach_name, att_desc);
	if (prex - begin_indx >= 1) then do;		/* if I got at least one attached, fake 'em out	*/
	    picode = 0;				/* so we don't quit				*/
	    sprex = prex - begin_indx;		/* this is how many we have */
	  end;
	else sprex = 0;
	do prex = prex to (dmpr_data_.pre_attach_vol + nvols_to_name); /* get rid of the pvolog segments for these 	*/
	  call hcs_$delentry_seg (dmpr_data_.pre_attach_pvlp (prex), ignore);
	  dmpr_data_.pre_attach_pvlp (prex) = null ();
	  if dmpr_data_.auto_vol then			/* and free the volumes in the pool		*/
	    call manage_volume_pool_$free (dmpr_data_.vpp, dmpr_report_$error_output,
	         (dmpr_data_.pre_attach_volname (prex)), ignore);
	  dmpr_data_.pre_attach_volname (prex) = "";	/* and clean up these...			*/
	  dmpr_data_.pre_attach_volid (prex) = "0"b;
	end;
	nvols_to_name = sprex;			/* now, tell him how many we really did		*/
        end;
    end;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


write_volume_log: entry (code);

/* This entry writes a volume log on the attached switch.  */

    code = 0;
    query_info.version = query_info_version_5;
    write_volume_log = "1"b;
    recordp = dmpr_data_.recordp;
    bvlp = dmpr_data_.bvlp;


    call get_seg_current_length (bvlp);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to find length of volume log ^a.volog", dmpr_data_.pvname);
        return;
      end;

    backup_volume_log.rec1_len = current_length * CHARS_PER_PAGE;
    backup_volume_record.rec2_type = null_type;
    backup_volume_record.rec2_len = 0;
    backup_volume_log.time_dumped = substr (bit (fixed (clock, 52), 52), 1, 36);

/* vologs have the header builtin so
				   we don't write one. */
/* Just write it as one big header */
    retry = "1"b;
    do while (retry);
      call iox_$put_chars (dmpr_data_.outputvol_iocbp, bvlp, backup_volume_log.rec1_len, code);
      call check_output_error;
    end;


    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


get_volname: proc (ec);

dcl volid		     bit (36);
dcl volname	     char (32);
dcl ec		     fixed bin (35);


/* This proc reads a dump volume name and converts it to a  volume id. Volume names are restricted to two or less
   acsii characters preceeding a numeric value(eg ic12345 is ok but inc12345 is not). It also creates an output log
   for the dump volume in which all the physical volumes that are dumped on this dump volume will be recorded.
   If the output log can not be created then it is assumed that the volume is alreay in use and another volume name
   is requested. */

request: volname = "*";
    if dmpr_data_.auto_vol then do;
get_vol: call manage_volume_pool_$reserve (dmpr_data_.vpp, dmpr_report_$error_output, volname,
	   ascii_type (dmpr_data_.dump_type), volname, ec);
        if ec ^= 0 then do;
	  if volname ^= "*" & ec = error_table_$action_not_performed then do;
	      call dmpr_report_$online_output (0, myname,
		 "Pool volume ^a already allocated", volname);
	      return;				/* let attach get us a new one		*/
	    end;
	  if ec = error_table_$action_not_performed then ec = 0;
	  call dmpr_report_$online_output (ec, myname,
	       "Unable to get next dump volume name from dump volume pool");
reread1:	  call get_volname_from_user (volname);
	  goto get_vol;				/* add to volume pool */
	end;
        call set_volid (volname, volid, ec);
        if ec ^= 0 then do;
	  call dmpr_report_$online_output (ec, myname, "Invalid volume id ^a",
	       volname);
bad_volid:  call manage_volume_pool_$free (dmpr_data_.vpp, dmpr_report_$error_output,
	       volname, ignore);
	  call manage_volume_pool_$delete (dmpr_data_.vpp, dmpr_report_$error_output,
	       volname, ignore);
	  goto request;
	end;
        call manage_volume_pool_$set_volid (dmpr_data_.vpp, dmpr_report_$error_output,
	   volname, volid, ec);
        if ec ^= 0 then do;
	  call dmpr_report_$error_output (ec, dmpr_data_.myname, "Unable to set volid for ^a",
	       volname);
	  goto bad_volid;
	end;
      end;
    else do;
reread2: call get_volname_from_user (volname);
        call set_volid (volname, volid, ec);
        if ec ^= 0 then do;
	  call dmpr_report_$online_output (ec, myname, "Invalid volume id ^a specified.", volname);
	  goto reread2;
	end;
      end;
    call dmpr_log_$create_pvolog (volname, ec);
    if ec ^= 0 then do;
        call dmpr_report_$online_output (0, myname,
	   "Dump volume ^a still contains pertinent information", volname);
        goto request;
      end;
    dmpr_data_.volid = volid;
    dmpr_data_.volname = volname;
    return;
  end get_volname;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


attach: proc;

/* This proc attaches an output volume through the specified attach description and opens it.
   It then create a contents segment and an account sgment for this volume.  It then attempts to determine the previous
   dump volume of this type and write its contents segment on the just attached dump volume.  Finally it
   updates the prev output log to reflect this dump volume is now the previous dump volume. 
    A return code of a -1 will indicate that the dump should be aborted by Operator request. */



    dmpr_data_.cur_vol_open = "0"b;
retry_attach:
    if dmpr_data_.pre_attach_vol > 0 then do;
        dmpr_data_.vol_idx = dmpr_data_.vol_idx + 1;
        if dmpr_data_.vol_idx > dmpr_data_.pre_attach_vol then do;
	  dmpr_data_.pre_attach_vol, dmpr_data_.vol_idx = 0;
	  goto non_pre_attach;			/* turn it off */
	end;
        dmpr_data_.volname = dmpr_data_.pre_attach_volname (dmpr_data_.vol_idx);
        dmpr_data_.volid = dmpr_data_.pre_attach_volid (dmpr_data_.vol_idx);
        dmpr_data_.outputvol_iocbp = dmpr_data_.pre_attach_iocbp (dmpr_data_.vol_idx);
        dmpr_data_.pvlp = dmpr_data_.pre_attach_pvlp (dmpr_data_.vol_idx);
      end;
    else do;
non_pre_attach:
        call get_volname (code);
        if code ^= 0 then return;

        if dmpr_data_.att_desc ^= "" then
	call ioa_$rsnnl (dmpr_data_.att_desc, att_desc, (0), dmpr_data_.volname);
        else call ioa_$rsnnl ("tape_mult_ ^a -write -system", att_desc, (0), dmpr_data_.volname);
        dmpr_data_.io_module = before (att_desc, " ");
reattach: call iox_$attach_ioname ("dump_volume", dmpr_data_.outputvol_iocbp, att_desc, code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, myname, "Unable to attach dump volume ^a.",
	       dmpr_data_.volname);
	  query_info.explanation_ptr = addr (retry_explanation);
	  query_info.explanation_len = length (retry_explanation);
	  call command_query_ (addr (query_info), answer, myname, "^/Do you wish to re-try the attachment?");

	  query_info.explanation_ptr = null ();		/* because its used elsewhere			*/
	  query_info.explanation_len = 0;		/* and we dont want to confuse anyone		*/
	  if answer = "yes" then goto reattach;
	  else do;
	      call hcs_$delentry_seg (dmpr_data_.pvlp, ignore);
	      call hcs_$terminate_seg (dmpr_data_.pvlp, 0, ignore);
	      dmpr_data_.pvlp = null ();
	      if dmpr_data_.auto_vol then
	        call manage_volume_pool_$free (dmpr_data_.vpp, dmpr_report_$error_output,
		   (dmpr_data_.volname), ignore);
	      code = -1;				/* flag for dumper				*/
	      return;
	    end;
	end;
      end;
    if dmpr_data_.auto_vol then do;
        call manage_volume_pool_$allocate (dmpr_data_.vpp, dmpr_report_$error_output, (dmpr_data_.volname),
	   ascii_type (dmpr_data_.dump_type),
	   (dmpr_data_.volname), code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, myname, "Unable to mark ^a allocated in volume pool",
	       dmpr_data_.volname);
	  call hcs_$delentry_seg (dmpr_data_.pvlp, ignore);
	  call hcs_$terminate_seg (dmpr_data_.pvlp, 0, ignore);
	  dmpr_data_.pvlp = null ();
	  call iox_$detach_iocb (dmpr_data_.outputvol_iocbp, (0));
	  goto retry_attach;
	end;
      end;
    call iox_$open (dmpr_data_.outputvol_iocbp, Stream_output, "0"b, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Error on opening dump volume ^a",
	   dmpr_data_.volname);
        call iox_$detach_iocb (dmpr_data_.outputvol_iocbp, ignore);
        call hcs_$delentry_seg (dmpr_data_.pvlp, ignore);
        call hcs_$terminate_seg (dmpr_data_.pvlp, 0, ignore);
        dmpr_data_.pvlp = null ();
        if dmpr_data_.auto_vol then do;
	  call manage_volume_pool_$free (dmpr_data_.vpp, dmpr_report_$error_output,
	       (dmpr_data_.volname), ignore);
	  if dmpr_data_.pre_attach_vol > 0 then goto retry_attach; /* presumably, there isn't anyone to answer our questions so,*/

	  query_info.explanation_ptr = addr (delete_explanation);
	  query_info.explanation_len = length (delete_explanation);
	  call command_query_ (addr (query_info), answer, myname, "^/^a^/^a",
	       "The open operation has failed.",
	       "Do you wish to delete the volume from the pool? ");
	  if answer = "yes" then
	    call manage_volume_pool_$delete (dmpr_data_.vpp, dmpr_report_$error_output,
	         (dmpr_data_.volname), ignore);
	  query_info.explanation_ptr = addr (continue_explanation);
	  query_info.explanation_len = length (continue_explanation);
	  call command_query_ (addr (query_info), answer, myname, "^/Do you wish to continue the dump?");
	  query_info.explanation_ptr = null ();
	  query_info.explanation_len = 0;
	  if answer = "yes" then ;
	  else do;
	      code = -1;				/* Operator aborted the dump			*/
	      return;
	    end;
	end;
        goto retry_attach;
      end;
    call iox_$modes (dmpr_data_.outputvol_iocbp, "async", (""), (0));
						/* run asynchronously			*/
    dmpr_data_.cur_vol_open = "1"b;			/* ok, good open				*/
    call dmpr_log_$init_contents_seg (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Contents seg init failure");
        return;
      end;

    if dmpr_data_.accounting then do;
        call dmpr_log_$init_account_file (code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, myname, "Account file init failure");
	  return;
	end;
      end;

    infop = dmpr_data_.infop;
    backup_info.rec2_type = null_type;
    backup_info.rec2_len = 0;
    backup_info.dump_volname = dmpr_data_.volname;
    backup_info.dump_volid = dmpr_data_.volid;
    backup_info.time_dumped = substr (bit (fixed (clock, 52), 52), 1, 36);
    retry = "1"b;
    do while (retry);
      call iox_$put_chars (dmpr_data_.outputvol_iocbp, infop, backup_info.rec1_len, code);
      call check_output_error;
    end;

    if dmpr_data_.prev_volname = "" then do;
        call dmpr_report_$error_output (0, dmpr_data_.myname,
	   "Previous dump volume not known. Contents segment not written to new dump volume");
        goto update_prev;
      end;
    call suffixed_name_$make ((dmpr_data_.prev_volname), "contents", ename, code);
    if code ^= 0 then goto prev_err;

    call hcs_$initiate (rtrim (dmpr_data_.sys_dir) || ">contents", ename, "", 0, 1, prev_contentsp, code);
    if prev_contentsp = null then do;
prev_err: call dmpr_report_$error_output (code, myname,
	   "Unable to locate contents seg ^a", ename);
        goto update_prev;
      end;

    call get_seg_current_length (prev_contentsp);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname,
	   "Unable to determine length of previous contents file");
        goto update_prev;
      end;
    prev_contentsp -> backup_volume_contents.rec1_len = CHARS_PER_PAGE * current_length;
    prev_contentsp -> backup_volume_contents.rec2_type = null_type;
    prev_contentsp -> backup_volume_contents.rec2_len = 0;
    prev_contentsp -> backup_volume_contents.time_dumped = substr (bit (fixed (clock, 52), 52), 1, 36);
    retry = "1"b;
    do while (retry);
      call iox_$put_chars (dmpr_data_.outputvol_iocbp, prev_contentsp,
	 prev_contentsp -> backup_volume_contents.rec1_len, code);
      call check_output_error;
    end;

update_prev:
    dmpr_data_.prev_volname = dmpr_data_.volname;

    if dmpr_data_.bvlp ^= null then do;
        if ^write_volume_log then call dmpr_log_$open_volume_log (code);
        if code ^= 0 then
	call dmpr_report_$error_output (code, myname, "Unable to open ^a.volog", dmpr_data_.pvname);
      end;

    dmpr_data_.not_reported = "1"b;
    dmpr_data_.dump_volume_seg_num = 0;
    dmpr_data_.dump_volume_seg_rec = 0;
    dmpr_data_.dump_volume_dir_num = 0;
    dmpr_data_.dump_volume_dir_rec = 0;

  end attach;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


detach: proc;

/* This proc closes out the use of a dump volume. It does this by closing the account segment and terminating the
   account and contents segment. It then closes and detachs the dump volume. */

    if dmpr_data_.accounting then do;
        call dmpr_log_$close_account_file (code);
        if code ^= 0 then
	call dmpr_report_$error_output (code, myname, "Unable to close account seg");
      end;
    call setbc_term (dmpr_data_.contentsp);
    call setbc_term (dmpr_data_.pvlp);
    call iox_$close (dmpr_data_.outputvol_iocbp, code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname, "Unable to close dump volume ^a", dmpr_data_.volname);
    call iox_$detach_iocb (dmpr_data_.outputvol_iocbp, code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname, "Unable to detach dump volume ^a", dmpr_data_.volname); ;
    dmpr_data_.outputvol_iocbp = null;			/* be sure */
    call dmpr_report_$online_output (0, myname,
         "Finished ^a: ^d ^d ^d ^d", dmpr_data_.volname,
         dmpr_data_.dump_volume_dir_rec, dmpr_data_.dump_volume_dir_num, dmpr_data_.dump_volume_seg_rec,
         dmpr_data_.dump_volume_seg_num);
    dmpr_data_.not_reported = "0"b;
    if ^write_volume_log then call dmpr_log_$close_volume_log (code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Unable to close ^a.volog", dmpr_data_.volname);

    dmpr_data_.dump_volume_seg_num = 0;
    dmpr_data_.dump_volume_seg_rec = 0;
    dmpr_data_.dump_volume_dir_num = 0;
    dmpr_data_.dump_volume_dir_rec = 0;
  end detach;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


check_output_error: proc;

/* This proc checks the error code retrurned from a write operation. If no error then it returns to its caller.
   If the dump volume is used up(end of reel/no more room) it closes the volume log, resets the counters associated with
   the dump volume and detachs the dump volume. It then atttaches a new dump volume, opens  the same volume log, but
   for a new dump volume, and requests the caller to retry the write operation. For any other kind of error it is
   reported but the action is the same */


    new_tape, retry = "0"b;
    if code = 0 then return;
continue_error_check:				/* if segfault err return to caller - data pointer is no good */
    if code = error_table_$segfault then goto non_local_return;
    if ^(code = error_table_$device_end | code = error_table_$end_of_info) then do;
        if code = error_table_$fatal_error then		/* Special case too many recoverable errors for *proper* message*/
	call dmpr_report_$error_output (0, myname, "The threshold for recoverable write errors (^d) has been reached.
Output to volume ^a will be terminated to minimize possible problems in later attempts to read it.",
	     max_error_count, dmpr_data_.volname);
        else call dmpr_report_$error_output (code, myname, "Error on output volume ^a", dmpr_data_.volname);
      end;
    call detach;
    call attach;
    if code ^= 0 then goto non_local_return;
    if ^write_volume_log then
      call dmpr_log_$update_pvolog (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to update ^a.pvolog", dmpr_data_.volname);
        goto non_local_return;
      end;
    new_tape = "1"b;
    retry = "1"b;
    return;

  end check_output_error;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


get_seg_current_length: proc (segp);

/* This proc calculates the length of the segment specified by segptr and returns the value in a global variable */

dcl segp		     ptr;
    call hcs_$fs_get_path_name (segp, dirname, ldn, ename, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to convert ptr to path-name");
        return;
      end;

    call hcs_$status_long (dirname, ename, 1, addr (local_status_branch), null, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to get current length of ^a>^a", dirname, ename);
        return;
      end;

    current_length = local_status_branch.current_length;

  end get_seg_current_length;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


page_by_page_write: proc;

/* This proc is use to write out a data object which has whole pages of zeros intermixed with non-zero pages.
   This is done to reduce the output load. To do this the file map contained in the vtoce is scanned and
   only non-null pages are written. If we switch to a new volume then we start from the beginning again. */

    do pagex = 0 to fixed (backup_volume_record.csl, 9) - 1;
      if ^substr (backup_volume_record.fm (pagex), 1, 1) then do;
	pagep = ptr (datap, pagex * WORDS_PER_PAGE);
	retry = "1"b;
	do while (retry);
	  call iox_$put_chars (dmpr_data_.outputvol_iocbp, pagep, fixed (CHARS_PER_PAGE, 21), code);
	  call check_output_error;
	  if new_tape then goto start_io;
	end;
        end;
    end;
    return;
  end page_by_page_write;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


set_volid: proc (a_volname, a_volid, code);
dcl a_volname	     char (*);
dcl a_volid	     bit (36);
dcl code		     fixed bin (35);

/* This proc constructs a volume id from a volume name. This is a interim measure until all dump volume are registered
   and have a unique id. This construction restricts the volume name to two or less non numeric characters followed
   by any numeric value lest then 262144. */

/* when rcp_ interface is defined
   call rcp_$volname_info (volname, dmpr_data_.volid, code);
   if code ^= 0 then
   call dmpr_report_$error_output (code, myname, "Unable to set volid");

   but until then  fudge it */


    start_numeric = search (a_volname, "0123456789");
    if start_numeric > 3 | start_numeric = 0 then do;
bad_volid: code = error_table_$bad_volid;
        return;
      end;
    else do;
        if start_numeric > 1 then volid.char = substr (a_volname, 1, start_numeric - 1);
        else volid.char = "";
        char_num = substr (a_volname, start_numeric, length (a_volname) - start_numeric);
        num = cv_dec_check_ (char_num, code);
        if code ^= 0 then goto bad_volid;
        volid.num = num;
      end;
    a_volid = unspec (volid);
    return;
  end set_volid;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


get_volname_from_user: proc (a_volname);
dcl a_volname	     char (*);
dcl avolname	     char (32) var;
						/* query_info is already set up		*/
    query_info.yes_or_no_sw = "0"b;			/* except for this				*/
rq: call command_query_ (addr (query_info), avolname, myname, "Type output volume name:");
    if avolname ^= "" then do;
        a_volname = avolname;
        query_info.yes_or_no_sw = "1"b;			/* back to my "normal" state			*/
      end;
    else goto rq;

  end get_volname_from_user;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


last_page_length: proc returns (fixed bin);

/* This proc back scans the last page of an object for the first non-zero character and returns the
   length of the non-zero page in words. The condition handler is established in case we share the segment with an
   other user who deletes/resets the ACL. */


    on seg_fault_error, page_read_error begin;
        code = error_table_$segfault;
        goto non_local_return;
      end;
    pagep = ptr (datap, (fixed (backup_volume_record.csl, 9) - 1) * WORDS_PER_PAGE);
    return (divide (length (rtrim (page_of_chars, zero_char)) + 3, CHARS_PER_WORD, 17, 0));
  end last_page_length;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


setbc_term: proc (p);

/* This proc terminates the specified segment and sets the ptr to it to null */

dcl p		     ptr;
dcl dn		     char (168);
dcl en		     char (32);
dcl ldn		     fixed bin;
    call hcs_$fs_get_path_name (p, dn, ldn, en, ignore);
    call adjust_bit_count_ (dn, en, "0"b, (0), ignore);
    call hcs_$terminate_seg (p, 0, ignore);
    p = null;

  end setbc_term;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

%include dmpr_data_;

%include backup_info;

%include backup_volume_contents;

%include backup_volume_header;
%include backup_volume_record;

%include vtoce;

%include backup_volume_log;
%include backup_pvol_info;

%include fs_vol_label;

%include iox_modes;

%include status_structures;

%include query_info;

%include system_constants;

  end dmpr_output_;




		    dmpr_report_.pl1                10/22/84  0946.0r w 10/22/84  0911.5       39798



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */

dmpr_report_: proc;

/* This routine is used by the volume dumper to report and log error and status
   messages. It is modled after the system routine com_err_. When called for the first time in a volume dumper
   invocation, it creates, in the working directory, an error file, in which it logs all error and status messages.
   If requested it also writes error message on the stream error_output. */

dcl  code fixed bin (35);
dcl  a_code fixed bin (35);
dcl  tstring char (24);
dcl  uname char (32);
dcl  caller char (*);
dcl  message char (*);
dcl  argp ptr;
dcl  error_iocbp ptr;
dcl  ret_string char (256);
dcl  len fixed bin;
dcl  error_output bit (1);
dcl  short char (8) ;
dcl  long char (100) ;

dcl  iox_$error_output ptr ext;
dcl  type_char (3) char (4) int static init ("incr", "cons", "comp") options (constant);
dcl  myname char (32) static int init ("dmpr_report_") options (constant);

dcl  date_time_ entry (fixed bin (71), char (*));
dcl  cu_$arg_list_ptr entry (ptr);
dcl  ioa_$general_rs entry (ptr, fixed bin, fixed bin, char (*), fixed bin, bit (1) aligned, bit (1) aligned);
dcl  ioa_$rsnnl entry options (variable);
dcl  iox_$attach_ioname entry (char (*), ptr, char (*), fixed bin (35));
dcl  iox_$open entry (ptr, fixed bin, bit (36), fixed bin (35));
dcl  convert_status_code_ entry (fixed bin (35), char (*), char (*));
dcl  ioa_$ioa_switch entry options (variable);
dcl  dmpr_report_$online_output entry options (variable);

dcl  null builtin;
dcl  clock builtin;

%include dmpr_data_;
%include backup_volume_header;

	return;					/* never should be call here */

error_output: entry (a_code, caller, message);

/* If an error file is not attached then fabricate a name with a data/time stamp, attach and open it. If
   successsful then report via online mechanism. */

	if dmprp = null then do;
	     error_output = "0"b;
	     goto common;
	end;
	if dmpr_data_.disable_error_report then return;
	error_output = "1"b;
	if dmpr_data_.error_iocbp = null then do;

	     call date_time_ (clock (), tstring);
	     uname = "dmpr_err." || type_char (dmpr_data_.dump_type) || "." || substr (tstring, 1, 8)||"."|| substr (tstring, 11, 4);
	     call iox_$attach_ioname ("error_file", error_iocbp, "vfile_ " || uname, code);
	     if code ^= 0 then do;
		call dmpr_report_$online_output (code, myname, "Unable to attach error file");
		return;
	     end;
	     call iox_$open (error_iocbp, 2, ""b, code);
	     if code ^= 0 then do;
		call dmpr_report_$online_output (code, myname, "Error opening error file");
		return;
	     end;
	     dmpr_data_.error_iocbp = error_iocbp;
	     call dmpr_report_$online_output (0, myname, "Error file ^a created", uname);
	end;

common:
						/* If given a non-zero code convert to a message */
	short, long = "";
	if a_code ^= 0 then
	     call convert_status_code_ (a_code, short, long);
						/* pick up arg list ptr */
	call cu_$arg_list_ptr (argp);
						/* convert args to message */
	call ioa_$general_rs (argp, 3, 4, ret_string, len, "0"b, "0"b);
	call date_time_ (clock (), tstring);

	if error_output then			/* write to file if specified */
	     call write_message (dmpr_data_.error_iocbp, "1"b);

/* Write online if requested, if args not initialized yet, or if correct entry */

	if dmprp = null then
	     call write_message (iox_$error_output, "0"b);

	else if (error_output & dmpr_data_.err_online) | ^error_output | ^dmpr_data_.arg_init then
	     call write_message (iox_$error_output, "0"b);

	return;

online_output: entry (a_code, caller, message);

	error_output = "0"b;
	goto common;


write_message: proc (P_iocbp, P_include_time);

dcl (P_iocbp pointer,
     P_include_time bit (1) aligned) parameter;

	     call ioa_$ioa_switch (P_iocbp, "^[^a^2x^;^s^]^a:^x^a^[:^x^a^;^s^]",
		P_include_time, substr (tstring, 11, 4),
		caller, substr (ret_string, 1, len),
		(a_code ^= 0), long);
	end write_message;

     end dmpr_report_;
  



		    dmpr_unlock_pv.pl1              11/15/82  1911.3rew 11/15/82  1529.5       21483



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */


dmpr_unlock_pv: proc;

dcl  pvname char (32);
dcl  pvid bit (36);
dcl  lvname char (32);
dcl  lvid bit (36);
dcl  argp ptr;
dcl  argl fixed bin;
dcl  device_type fixed bin;
dcl  dtype fixed bin;
dcl  arg char (argl) based (argp);
dcl  code fixed bin (35);
dcl  narg fixed bin;

dcl  myname char (32) int static init ("dmpr_unlock_pv") options (constant);

dcl  linkage_error condition;

dcl  error_table_$badopt fixed bin (35) ext;

dcl  cu_$arg_count entry (fixed bin);
dcl  cu_$arg_ptr entry (fixed bin, ptr, fixed bin, fixed bin (35));
dcl  com_err_ entry options (variable);
dcl  ioa_ entry options (variable);
dcl  mdc_$pvname_info entry (char (*), bit (36), char (*), bit (36), fixed bin, fixed bin (35));
dcl  hc_backup_$dmpr_unlock_pv entry (bit (36), fixed bin, fixed bin (35));

%include backup_static_variables;
	code = 0;
	call cu_$arg_count (narg);
	if narg ^= 2 then do;
	     call com_err_ (0, myname, "Usage: dmpr_unlock_pv pvname dump_type");
	     return;
	end;
	call cu_$arg_ptr (1, argp, argl, code);
	if code ^= 0 then goto err;;
	pvname = arg;
	call mdc_$pvname_info (pvname, pvid, lvname, lvid, device_type, code);
	if code ^= 0 then do;
	     call com_err_ (code, myname, "^a", pvname);
	     return;
	end;
	call cu_$arg_ptr (2, argp, argl, code);
	if code ^= 0 then goto err;
	if arg = "-incr" | arg = "-incremental" then dtype = incr;
	else if arg = "-cons" | arg = "-consolidated" then dtype = cons;
	else if arg = "-comp" | arg = "-complete" then dtype = comp;
	else do;
	     call com_err_ (error_table_$badopt, myname, "^a", arg);
	     return;
	end;
	on linkage_error begin;
	     call ioa_ ("Incorrect access to privilidged gate hc_backup_");
	     goto finish;
	end;

	call hc_backup_$dmpr_unlock_pv (pvid, dtype, code);
	if code ^= 0 then goto err;

finish:
	return;

err:
	call com_err_ (code, myname);
	goto finish;

     end dmpr_unlock_pv;
 



		    dump_volume_.pl1                10/10/89  1422.4r w 10/10/89  1359.7      173898



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1988                *
        *                                                         *
        * Copyright, (C) Honeywell Information Systems Inc., 1982 *
        *                                                         *
        * Copyright (c) 1972 by Massachusetts Institute of        *
        * Technology and Honeywell Information Systems, Inc.      *
        *                                                         *
        *********************************************************** */

/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/

dump_volume_: proc (code);

/* This routine dumps a single physical volume in the dump mode specified.  It also updates the appropriate
   volume log, a per physical volume log of all the output volumes that contain relevent information about that
   physical volume.In addition it maintains statistics about what is dumped from each physical volume. The incremental
   and consolidated volume dumping is driven by a ring 0 bit map of which vtoces to dump. The complete volume
   dump is driven by either a constructed bit map or a vtoce by vtoce scan, depending on which will use less resources.
   The volume log is written out befor and after the physical volume is dumped, so that the most recent copy
   is on an output volume should the online copy be lost. */

/* Modified: 10/22/81 by GA Texada to change page_read_error to page_fault_error.     
   Modified: 11/16/81 by GAT to close and write the current volume log if aborting a dump.
   Modified: 12/17/81 by GAT to recognize when an attachment of a volume fails and abort the dump.
   Modified: 11/10/82 by GAT (PBF for MR10.1) to actually indicate that the dump 
		  should be aborted ny Operator request.
   Modified: 11/17/82 by GAT to query when a pv is found locked under 'special' circumstances.
   Modified: August 1983 by GA Texada to call dmpr_output_$new_pass_attach if necessary.
*/

/****^  HISTORY COMMENTS:
  1) change(86-03-04,Fawcett), approve(86-04-10,MCR7383),
     audit(86-06-03,GWMay), install(86-07-18,MR12.0-1098):
     Support for subvolume devices real 512_word_io.
  2) change(88-04-13,GWMay), approve(88-04-13,MCR7855), audit(88-04-14,Farley),
     install(88-04-19,MR12.2-1039):
     Changed to diagnose vtoce connection failures and continue dumping.
  3) change(88-05-27,GWMay), approve(88-05-27,MCR7883),
     audit(88-06-14,Beattie), install(88-07-19,MR12.2-1061):
     Added init for first pass flag in  dmpr_data.
                                                   END HISTORY COMMENTS */

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

    code = 0;					/* set return values */
    loop_cnt = 0;					/* init */

/* First we will set the number of vtoce in a page dependent on device_type */

    if dmpr_data_.version <= dmpr_data_version_2 then n_vtoce_per_page = 5; /* old style can not be for a sub volume device */
    else n_vtoce_per_page = vtoc_per_rec (dmpr_data_.disk_type);

    recordp = dmpr_data_.recordp;
    dmpr_data_.num_null_vtoce,
         dmpr_data_.num_vtoce_only,
         dmpr_data_.physical_volume_dir_num,
         dmpr_data_.physical_volume_dir_rec,
         dmpr_data_.physical_volume_seg_num,
         dmpr_data_.physical_volume_seg_rec = 0;		/* reset counters */
						/* get ptr to volume log */
    call dmpr_log_$init_volume_log (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Volume log init failure of ^a.volog ", dmpr_data_.pvname);
        return;
      end;
    bvlp = dmpr_data_.bvlp;

/* Interlock physical volume against dumper operating in same mode, ie: two incremental dumpers.  Setup cleanup
   handler in case we abort. Also pickup newest copy of label record of physical volume and some other descriptive
   info about the state of the pack. The label record will be use by the volume reloader to check if the
   initialized pack it is given can handle the information to be reloaded. */

    on cleanup call unlock_pv;
try_again:
    call hc_backup_$dmpr_lock_pv (dmpr_data_.pvid, dmpr_data_.dump_type, addr (backup_volume_log.info), code);
    if code ^= 0 then do;
        if dmpr_data_.restart_pvname = dmpr_data_.pvname then do;
						/* only do this IF we are restarting		*/
	  call command_query_$yes_no (ansb, 0, myname,
	       "The physical volume ^a was found locked. This could have been caused by a previous system interruption.
A ""yes"" answer will attempt to forcibly unlock it. A ""no"" answer will not.",
	       "Volume ^a is locked, do you wish to unlock it?", dmpr_data_.pvname);
	  if ansb then do;
	      call unlock_pv ();
	      if ec = 0 then goto try_again;
	    end;
	end;
bust_anyway:
        call dmpr_report_$error_output (code, myname,
	   "Unable to lock  disk volume ^a",
	   dmpr_data_.pvname);
        return;
      end;
						/* pickup local copies */
    n_vtoce = backup_volume_log.n_vtoce;
    n_free_vtoce = backup_volume_log.n_free_vtoce;

/* For each dump volume we maintain a log of which physical volume are on it. This allows us  to control
   the use of volumes and to not overwrite a volume which has useful infomation on it.
   This call updates that log. */

/* If we need to, get an output volume. */
    if dmpr_data_.detach & dmpr_data_.outputvol_iocbp = null () then do;
        call dmpr_output_$new_pass_attach (code);
        if code ^= 0 then do;
	  call unlock_pv;
	  return;
	end;
      end;
						/* write physical volume log to dump volume */
    call dmpr_output_$write_volume_log (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to write ^a.volog", dmpr_data_.pvname);
        call unlock_pv;
        return;
      end;
						/*  Add dump volume to physical volume log */
    call dmpr_log_$open_volume_log (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to open ^a.volog", dmpr_data_.pvname);
        call unlock_pv;
        return;
      end;

    call dmpr_log_$update_pvolog (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, myname, "Unable to update ^a.pvolog", dmpr_data_.volname);
        call unlock_pv;
        return;

      end;


/* If this is a complete dump, then there are two ways to do it, either by reading each vtoce or by building
   a bit map of all in-use vtoces. The difference comes because to build the map we can read 5 vtoce in each page
   at one time by suitable use of an abs seg. Thus we compute which is the better method(uses the least resources)
   and  do the right thing. If we build the bit map, in our ring, we operate in "request" mode. */

    request = "0"b;
    if (dmpr_data_.dump_type = comp) &
         (n_free_vtoce * vtoce_read_time > n_vtoce * divide (page_read_time, n_vtoce_per_page, 17, 0)) then do;
        request = "1"b;
        vbmp = addr (vtoc_bit_map);
        unspec (vtoc_bit_map) = "0"b;

        n_windows = divide (n_vtoce, max_pages_per_segment * n_vtoce_per_page, 17, 0) + 1;
        on page_fault_error begin;
	  code = error_table_$device_parity;
	  call dmpr_report_$error_output (0, myname, "Page read error building volume bit map for disk ^a",
	       dmpr_data_.pvname);
	  goto map_err;
	end;
        do i = 0 to n_windows - 1;
	call hc_backup_$dmpr_build_vtoc_map (vbmp, i, code);
	if code ^= 0 then do;
map_err:	    call dmpr_report_$error_output (code, myname,
	         "Unable to construct bit map for disk ^a", dmpr_data_.pvname);
	    call unlock_pv;
	    return;
	  end;
        end;
        revert page_fault_error;
      end;

/* Initialize the input structure to the ring 0 volume dumper */

    inputp = dmpr_data_.inputp;
    dmpr_input.request_vtocx = -1;
    dmpr_input.request = request;
    dmpr_input.pvid = dmpr_data_.pvid;			/* changes each invocation */
    dmpr_input.start_time = clock ();

/* This is the main dump loop. We repeatedly call the ring 0 dumper to provide us with a pointer to the next
   object to be dumped until there are no more. Segments and directories are handled differently in that a directory
   must be consistent when dumped and thus are copied, while locked, into a temporyary segment. Segments, on the other
   hand are accessed through a ring 0 abs seg, we thus must be able to handle a seg fault error. Should one
   occur we call the ring 0 dumper and ask for a pointer to the segment again. We will repeat this up to 10 times
   and then give up. The final case is that of a vtoce which does not have an associated object. We dump this "null"
   vtoce as a place holder so that the volume reloader will not recover an earlier object with the same vtocx  index. */

    backup_volume_record.vtocx = -1;			/* set to beginning */
    dmpr_input.Sfirst_pass_for_pv = "1"b;
    do while (loop_cnt <= n_vtoce);			/* put a limit on it */
      seg_fault_retry_cnt = 0;
      in_use_retry_cnt = 0;
      vtocx_retry_cnt = 0;
      dmpr_input.retry = "0"b;
      if request then dmpr_input.request_vtocx = get_next_vtocx_ ();
      dmpr_input.prev_vtocx = backup_volume_record.vtocx;
      dmpr_input.volid = dmpr_data_.volid;
      on page_fault_error begin;
	call dmpr_report_$error_output (error_table_$device_parity, myname, "Skipping vtoce ^o on disk ^a",
	     backup_volume_record.vtocx, dmpr_data_.pvname);
	goto end_loop;
        end;
						/* get pointer to object */
retry: call hc_backup_$get_dmpr_data_object (dmpr_data_.inputp, recordp, code);
      if code ^= 0 then do;
	if code = error_table_$dmpr_in_use then do;
						/* object in use by other dumper so sleep */
	    in_use_retry_cnt = in_use_retry_cnt + 1;
	    if in_use_retry_cnt > 10 then do;
	        call dmpr_report_$error_output (0, myname,
		   "Skipping vtoce ^o on disk ^a because in-use too long",
		   backup_volume_record.vtocx, dmpr_data_.pvname);
	        goto end_loop;
	      end;
	    call timer_manager_$sleep (5, "11"b);
	    goto retry;
	  end;
						/*  if request could not be done */
	else if (request & code = error_table_$action_not_performed) then do;
	    code = 0;
	    goto end_loop;
	  end;
	else if code = error_table_$end_of_info then do;
	    code = 0;				/* completed sucessfully */
	    goto exit;
	  end;
	else if code = error_table_$invalid_vtoce then do;
	    backup_volume_record.uid = "0"b;
	  end;
	else if code = error_table_$vtoce_connection_fail then do;
						/* Directory damage is reported and this vtoce is not dumped until a system
   maintainer repairs the damage. */
	    call dmpr_report_$error_output (0, myname,
	         "Skipping vtoce ^o on disk volume ^a because it has the
same UID as another vtoce.  See the syserr log for more detailed information.",
	         backup_volume_record.vtocx, dmpr_data_.pvname);
	    go to end_loop;
	  end;

	else do;					/* error condition */
	    if vtocx_retry_cnt < 10 then do;
	        call dmpr_report_$error_output (code, myname, " vtoce after ^o on disk ^a, retrying dump.",
		   dmpr_input.prev_vtocx, dmpr_data_.pvname);
	        vtocx_retry_cnt = vtocx_retry_cnt + 1;
	        goto retry;
	      end;
	    else do;
	        call dmpr_report_$error_output (code, myname, "Volume dump of ^a aborted.", dmpr_data_.pvname);
	        goto exit;				/* got to clean up what I have already dumped.	*/
	      end;
	  end;
        end;
						/* type of object determines pointer	*/
      if (backup_volume_record.uid = "0"b | dmpr_input.no_object) then datap = null ();
      else if backup_volume_record.dirsw then datap = dmpr_data_.dirp;
      else datap = dmpr_data_.segp;
						/* write out vtoce and possibly object */
      call dmpr_output_$output_object (datap, code);
      if code ^= 0 then do;				/* if -1, the attach/open failed, so abort	*/
	if code = -1 then do;			/* which actually says that the operatore requested abort*/
	    call dmpr_report_$error_output (0, myname, "Dump aborted by operator request.");
	    call unlock_pv;
	    return;
	  end;
						/* retry dump up to 10 times */
	if code = error_table_$segfault then do;
	    dmpr_input.retry = "1"b;
	    seg_fault_retry_cnt = seg_fault_retry_cnt + 1;
	    if seg_fault_retry_cnt > 10 then do;
	        call dmpr_report_$error_output (code, myname, "Retry of vtocx ^o on disk ^a failed",
		   backup_volume_record.vtocx, dmpr_data_.pvname);
	        dmpr_input.retry = "0"b;
	        seg_fault_retry_cnt = 0;
	        goto end_loop;
	      end;
	    dmpr_data_.retrys = dmpr_data_.retrys + 1;
	    goto retry;
	  end;
	call dmpr_report_$error_output (code, myname, "Unable to write object");
        end;
						/* Update counters */
      if backup_volume_record.uid = "0"b | dmpr_input.no_object then do;
	if backup_volume_record.uid = "0"b then dmpr_data_.num_null_vtoce = dmpr_data_.num_null_vtoce + 1;
	else dmpr_data_.num_vtoce_only = dmpr_data_.num_vtoce_only + 1;
        end;

/* Record the uid of the object dumped in the contents seg. This will save the retriever having to
   mount and serach an output volume, rather it can search the online contents segment. In addition record
   in the accounting data base the uid pathname of the object dumped. Dumping uses system resources and
   users should be billed for this service. Finally update some counters about what is being dumped. */

      else do;
	call dmpr_log_$log_object (code);
	if code ^= 0 then
	  call dmpr_report_$error_output (code, myname, "Error logging object");
	if backup_volume_record.dirsw then do;
	    dmpr_data_.physical_volume_dir_num = dmpr_data_.physical_volume_dir_num + 1;
	    dmpr_data_.physical_volume_dir_rec = dmpr_data_.physical_volume_dir_rec +
	         fixed (backup_volume_record.records, 9);
	    dmpr_data_.vol_log_dir_num = dmpr_data_.vol_log_dir_num + 1;
	    dmpr_data_.vol_log_dir_rec = dmpr_data_.vol_log_dir_rec +
	         fixed (backup_volume_record.records, 9);
	    dmpr_data_.dump_volume_dir_num = dmpr_data_.dump_volume_dir_num + 1;
	    dmpr_data_.dump_volume_dir_rec = dmpr_data_.dump_volume_dir_rec +
	         fixed (backup_volume_record.records, 9);
	  end;
	else do;
	    dmpr_data_.physical_volume_seg_num = dmpr_data_.physical_volume_seg_num + 1;
	    dmpr_data_.physical_volume_seg_rec = dmpr_data_.physical_volume_seg_rec +
	         fixed (backup_volume_record.records, 9);
	    dmpr_data_.vol_log_seg_num = dmpr_data_.vol_log_seg_num + 1;
	    dmpr_data_.vol_log_seg_rec = dmpr_data_.vol_log_seg_rec +
	         fixed (backup_volume_record.records, 9);
	    dmpr_data_.dump_volume_seg_num = dmpr_data_.dump_volume_seg_num + 1;
	    dmpr_data_.dump_volume_seg_rec = dmpr_data_.dump_volume_seg_rec +
	         fixed (backup_volume_record.records, 9);
	  end;
        end;
end_loop:
						/* keep track of how many times in loop */
      loop_cnt = loop_cnt + 1;
    end;
exit:
    revert page_fault_error;

/* error exit - can't dump more then the number of vtoce on the physical volume */
    if loop_cnt > n_vtoce then
      call dmpr_report_$error_output (0, myname, "Bit map error - please salvage disk ^a",
	 dmpr_data_.pvname);

/* Unlock physical volume, close volume log and write updated copy to dump volume */

    call unlock_pv;
    call dmpr_log_$close_volume_log (code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname,
	 "Unable to close ^a.volog", dmpr_data_.pvname);
    call dmpr_output_$write_volume_log (code);
    if code ^= 0 then
      call dmpr_report_$error_output (code, myname, "Unable to write ^a.volog", dmpr_data_.pvname);
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/
%page;
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

get_next_vtocx_: proc returns (fixed bin);

/* This proc finds the next vtoce to dump from the complete volume dump bit map, described above, and
   retruns the vtocx index of it. */

    do idx = dmpr_input.request_vtocx + 1 to n_vtoce - 1 while (vtoc_bit_map (idx) = "0"b);
    end;
    vtoc_bit_map (idx) = "0"b;
    return (idx);

  end get_next_vtocx_;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


unlock_pv: proc;
    if dmprp = null then return;
    call hc_backup_$dmpr_unlock_pv (dmpr_data_.pvid, dmpr_data_.dump_type, ec);
    if ec ^= 0 then
      call dmpr_report_$error_output (ec, myname, "Unable to unlock disk ^a", dmpr_data_.pvname);
  end unlock_pv;
%page;

dcl ansb		     bit (1);
dcl loop_cnt	     fixed bin;
dcl seg_fault_retry_cnt  fixed bin;
dcl vtocx_retry_cnt	     fixed bin;
dcl in_use_retry_cnt     fixed bin;
dcl code		     fixed bin (35);
dcl ec		     fixed bin (35);
dcl idx		     fixed bin;
dcl n_vtoce	     fixed bin;
dcl n_free_vtoce	     fixed bin;
dcl datap		     ptr;
dcl i		     fixed bin;
dcl vbmp		     ptr;
dcl request	     bit (1);
dcl vtoc_bit_map	     (0:36720 - 1) bit (1) unaligned;
dcl n_windows	     fixed bin;
dcl n_vtoce_per_page     fixed bin;
dcl myname	     char (32) int static init ("dump_volume_") options (constant);
dcl vtoce_read_time	     fixed bin int static init (25) options (constant);
dcl page_read_time	     fixed bin int static init (40) options (constant);
dcl max_pages_per_segment fixed bin int static init (255) options (constant);

dcl error_table_$invalid_vtoce ext fixed bin (35);
dcl error_table_$dmpr_in_use ext fixed bin (35);
dcl error_table_$device_parity ext fixed bin (35);
dcl error_table_$action_not_performed ext fixed bin (35);
dcl error_table_$segfault ext fixed bin (35);
dcl error_table_$end_of_info ext fixed bin (35);
dcl error_table_$vtoce_connection_fail fixed bin (35) ext static;

dcl command_query_$yes_no entry () options (variable);
dcl timer_manager_$sleep entry (fixed bin (71), bit (2));
dcl dmpr_report_$error_output entry options (variable);
dcl dmpr_output_$new_pass_attach entry (fixed bin (35));
dcl dmpr_output_$write_volume_log entry (fixed bin (35));
dcl dmpr_output_$output_object entry (ptr, fixed bin (35));
dcl dmpr_log_$update_pvolog entry (fixed bin (35));
dcl dmpr_log_$log_object entry (fixed bin (35));
dcl dmpr_log_$init_volume_log entry (fixed bin (35));
dcl dmpr_log_$open_volume_log entry (fixed bin (35));
dcl dmpr_log_$close_volume_log entry (fixed bin (35));

dcl hc_backup_$dmpr_lock_pv entry (bit (36) aligned, fixed bin, ptr, fixed bin (35));
dcl hc_backup_$dmpr_unlock_pv entry (bit (36) aligned, fixed bin, fixed bin (35));
dcl hc_backup_$dmpr_build_vtoc_map entry (ptr, fixed bin, fixed bin (35));
dcl hc_backup_$get_dmpr_data_object entry (ptr, ptr, fixed bin (35));

dcl cleanup	     condition;
dcl page_fault_error     condition;
dcl addr		     builtin;
dcl clock		     builtin;
dcl divide	     builtin;
dcl fixed		     builtin;
dcl null		     builtin;
dcl unspec	     builtin;
%page;
%include dmpr_data_;
%page;
%include backup_volume_header;
%include dmpr_input;
%page;
%include backup_volume_record;
%include backup_static_variables;
%page;
%include vtoce;
%page;
%include backup_volume_log;
%include backup_pvol_info;
%page;
%include fs_vol_label;
%page;
%include fs_dev_types;

  end dump_volume_;
  



		    dumper.pl1                      07/20/88  1308.4r w 07/19/88  1535.6      340416



/* ***********************************************************
   *                                                         *
   * Copyright, (C) Honeywell Information Systems Inc., 1982 *
   *                                                         *
   * Copyright (c) 1972 by Massachusetts Institute of        *
   * Technology and Honeywell Information Systems, Inc.      *
   *                                                         *
   *********************************************************** */



/****^  HISTORY COMMENTS:
  1) change(81-12-16,Texada), approve(), audit(), install():
     fix phx12050 and phx12187
  2) change(82-08-01,Texada), approve(), audit(), install():
     for phx12187, phx13713, phx13662
  3) change(82-11-12,Texada), approve(), audit(), install():
     to implement phx13262
  4) change(82-11-16,Texada), approve(), audit(), install():
     to implement phx14088,  allow preattachment of dump volumes to an
     existing incremental dump.
  5) change(83-01-26,Texada), approve(), audit(), install():
     to support version 2 dmpr_data_ and fix a problem when volumes were
     attached but not opened then crash.
  6) change(83-03-01,Kittlitz), approve(), audit(), install():
     for 256K segments.
  7) change(83-04-05,Texada), approve(), audit(), install():
     add trace entries.
  8) change(83-08-18,Texada), approve(), audit(), install():
     redefine -detach/-no_detach.
  9) change(84-02-01,Texada), approve(), audit(), install():
     support version 3 dmpr_data_.
 10) change(84-03-05,Texada), approve(), audit(), install():
     add set_volume_wakeup_interval.
 11) change(85-11-05,GWMay), approve(85-12-02,MCR7310), audit(85-12-05,Dupuis),
     install(85-12-16,MR12.0-1001):
     modified the routine set_volume_wakeup_interval to allow a wakeup
     interval up to 1440 minutes, this was raised from 480.  To
     accomodate the size of the interval when converted to microseconds,
     the variable my_interval was increased in size.
                                                   END HISTORY COMMENTS */


/* format: style1,ind2,^inddcls,ifthenstmt,dclind2,declareind2,ifthendo,ifthen*/

dumper: proc;

/* This proc provides the command interface for the volume dumper subsystem.  It initializes the static
   data base and other external data bases, attaches to, opens and parses the dump
   control file converting the control file into an ordered array of physical volume names and ids. It then
   successivly dumps this array , volume by volume. */
        

dcl Area		     area based (areap);
dcl tp		     (4) ptr;
dcl dump_control_name    char (32);
dcl was_asleep	     bit (1);			/* if incr dump, is saved value of dmpr_data_.dmpr_asleep, else is "0"b*/
dcl (YES, dmpr_data_already_locked, new_control_seg, trace) bit (1);
dcl mname		     char (21);
dcl (cycle_uid, ignored_lvid) bit (36);
dcl answer	     char (3) var;
dcl (ac, argl, narg, nelemt, idx, num_pv, first_pvx, nvols, tnpv) fixed bin;
dcl control_seg_name     char (32);
dcl (areap, argp)	     ptr;
dcl line		     char (120) aligned;
dcl tlvname	     char (32) aligned;
dcl lvname	     (100) char (32);
dcl pvname	     (100) char (32);
dcl time_string	     char (24);
dcl pvid		     (100) bit (36);
dcl device_type	     (100) fixed bin;
dcl (old_time, time_pass_started) fixed bin (71);		/* Time this pass started. */
dcl (code, ignore)	     fixed bin (35);		/* Error code. */

dcl 1 query_info	     aligned,
    2 version	     fixed bin init (2),
    2 yes		     bit (1) init ("1"b),
    2 name	     bit (1) init ("0"b),
    2 code	     fixed bin (35) init (0),
    2 pad		     fixed bin;

dcl 1 pva		     (100) aligned,
    2 pvname	     char (32),
    2 device_type	     fixed bin,
    2 pvid	     bit (36);


dcl type_char	     (3) char (4) int static init ("incr", "cons", "comp") options (constant);
dcl force_write_bits     bit (36) init ((36)"0"b) int static options (constant); /* write pages in parallel			*/
dcl lock_wait_time	     fixed bin static init (60) options (constant);

dcl arg		     char (argl) based (argp);

dcl iox_$user_io	     ptr external;
dcl error_table_$action_not_performed fixed bin (35) ext static;
dcl error_table_$end_of_info ext fixed bin (35);
dcl error_table_$invalid_lock_reset ext fixed bin (35);
dcl error_table_$inconsistent fixed bin (35) ext static;
dcl error_table_$bad_arg ext fixed bin (35);
dcl error_table_$bad_conversion fixed bin (35) ext static;
dcl error_table_$wrong_no_of_args fixed bin (35) ext static;
dcl command_query_$yes_no entry () options (variable);
dcl cv_dec_check_	     entry (char (*), fixed bin (35)) returns (fixed bin (35));
dcl get_system_free_area_ entry () returns (ptr);
dcl suffixed_name_$make  entry (char (*), char (*), char (*), fixed bin (35));
dcl hcs_$force_write     entry (ptr, bit (36), fixed bin (35));
dcl hcs_$set_256K_switch entry (bit (2) aligned, bit (2) aligned, fixed bin (35));
dcl hcs_$status_minf     entry (char (*), char (*), fixed bin, fixed bin, fixed bin, fixed bin (35));
dcl manage_volume_pool_$set_pool_path entry (entry options (variable), char (*), ptr, fixed bin (35));
dcl com_err_	     entry options (variable);
dcl command_query_	     entry options (variable);
dcl set_lock_$lock	     entry (bit (36) aligned, fixed bin, fixed bin (35));
dcl ipc_$mask_ev_calls   entry (fixed bin (35));
dcl ipc_$unmask_ev_calls entry (fixed bin (35));
dcl ioa_$rsnnl	     entry options (variable);
dcl cu_$arg_count	     entry (fixed bin);
dcl cu_$arg_ptr	     entry (fixed bin, ptr, fixed bin, fixed bin (35));
dcl hcs_$make_seg	     entry (char (*), char (*), char (*), fixed bin (5), ptr, fixed bin (35));
dcl get_wdir_	     entry returns (char (168) aligned);
dcl mdc_$check_mounted   entry (char (*) aligned, fixed bin (35));
dcl add_epilogue_handler_ entry (entry, fixed bin (35));
dcl iox_$control	     entry (ptr, char (*), ptr, fixed bin (35));
dcl purge_volume_log_    entry (char (*) aligned, char (*) aligned, fixed bin, bit (1), fixed bin (35));
dcl hc_backup_$init_dmpr entry (ptr, ptr, fixed bin (35));
dcl dmpr_output_$init    entry (fixed bin (35));
dcl dmpr_output_$end_pass_detach entry (fixed bin (35));
dcl dmpr_output_$preattach_vols entry (fixed bin, fixed bin, fixed bin (35));
dcl dmpr_output_$preattach_ioname entry (fixed bin, fixed bin, fixed bin (35));
dcl get_temp_segments_   entry (char (*), (*) ptr, fixed bin (35));
dcl dump_volume_	     entry (fixed bin (35));
dcl dmpr_info_	     entry (fixed bin (35));
dcl dmpr_arg_reader_     entry (ptr, fixed bin (35));
dcl dmpr_finish_	     entry (fixed bin (35));
dcl timer_manager_$alarm_wakeup entry (fixed bin (71), bit (2), fixed bin (71));
dcl timer_manager_$get_schedule entry (ptr, ptr, fixed bin (35));
dcl timer_manager_$reset_alarm_wakeup entry (fixed bin (71));
dcl mdc_$lvname_info     entry (char (*) aligned, ptr, fixed bin, fixed bin (35));
dcl mdc_$pvname_info     entry (char (*), bit (36), char (*), bit (36), fixed bin, fixed bin (35));
dcl date_time_	     entry (fixed bin (71), char (*));
dcl cu_$arg_list_ptr     entry (ptr);			/* Arg list location */
dcl iox_$attach_ioname   entry (char (*), ptr, char (*), fixed bin (35));
dcl iox_$position	     entry (ptr, fixed bin, fixed bin, fixed bin (35));
dcl iox_$open	     entry (ptr, fixed bin, bit (36), fixed bin (35));
dcl iox_$get_line	     entry (ptr, ptr, fixed bin, fixed bin, fixed bin (35));
dcl ipc_$create_ev_chn   entry (fixed bin (71), fixed bin (35));
dcl ipc_$decl_ev_call_chn entry (fixed bin (71), entry, ptr, fixed bin, fixed bin (35));
dcl (dmpr_report_$error_output, dmpr_report_$online_output) entry options (variable);

dcl (cleanup, finish)    condition;


dcl (after, before, bit, rtrim, addr, clock, fixed, hbound, length, null, substr, verify) builtin;

incremental_volume_dump: entry;

    call init (incr, "incremental_volume_dumper");
    go to start;					/* Go get arguments. */

consolidated_volume_dump: entry;

    call init (cons, "consolidated_volume_dump");
    go to start;					/* Go get arguments. */

complete_volume_dump: entry;				/* Entry to do complete volume dump */

    call init (comp, "complete_volume_dump");

start:
    dmpr_data_.old_256K_switch = ""b;
    call add_epilogue_handler_ (end_volume_dump, code);
    if code ^= 0 then
         call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to set epilogue handler");
    on cleanup call dmpr_finish_ (ignore);
    on finish call dmpr_finish_ (ignore);
    call cu_$arg_list_ptr (argp);			/* get arg list ptr */
    call dmpr_arg_reader_ (argp, code);			/* Get any other arguments */
    if code ^= 0 then goto finale;

    call hcs_$set_256K_switch ("11"b, dmpr_data_.old_256K_switch, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Could not enable 256KW segments.");
        goto finale;
      end;
    dmpr_data_.arg_init = "1"b;
    if (dmpr_data_.dump_type = incr) & (dmpr_data_.detach) & (dmpr_data_.pre_attach_vol ^= 0) then do;
        call dmpr_report_$error_output (error_table_$inconsistent, dmpr_data_.myname,
	"The -detach and -preattach control arguments are mutually exclusive");
        goto finale;
      end;

    if dmpr_data_.control_name = "" | dmpr_data_.operator = "" then do;
        code = error_table_$bad_arg;			/* Must have dump control file and operator */
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Missing control file or operator name");
        goto finale;
      end;
    if dmpr_data_.auto_vol then do;
        call manage_volume_pool_$set_pool_path (dmpr_report_$error_output,
	rtrim (dmpr_data_.sys_dir) || ">Volume_Dumper", dmpr_data_.vpp, code);
						/* set the pool path to the standard one */
        if code ^= 0 then do;
	  call dmpr_report_$online_output (code, dmpr_data_.myname, "Unable to locate volume pool");
	  goto finale;
	end;

      end;
						/* setup temp segs */
    call get_temp_segments_ ("dumper", tp, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Temp seg init failure");
        goto finale;
      end;
						/* initialize static ptrs */
    dmpr_data_.dirp = tp (1);
    dmpr_data_.inputp = tp (2);
    dmpr_data_.recordp = tp (3);
    dmpr_data_.infop = tp (4);
						/* initialize info seg  - per dump info */
    call dmpr_info_ (code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Error initing info seg ");
        goto finale;
      end;
						/* attach and open control file */
    call iox_$attach_ioname ("dump_control", dmpr_data_.control_iocbp, "vfile_ " || dmpr_data_.control_name, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code,
	dmpr_data_.myname, "Unable to attach to ^a",
	dmpr_data_.control_name);
        goto finale;
      end;
    call iox_$open (dmpr_data_.control_iocbp, 1, "0"b, code);
    if code ^= 0 then do;				/* Was an error encountered? */
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Open error on ^a", dmpr_data_.control_name);
        goto finale;				/* Quit. */
      end;
    if dmpr_data_.dump_type = incr then do;		/* Is this an incremental volume dump? */
        call ipc_$create_ev_chn (dmpr_data_.incr_ev_chn, code); /* Create an event channel. */
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, dmpr_data_.myname, "Error creating event channel");
	  goto finale;
	end;					/* Make channel into call channel. */
        call ipc_$decl_ev_call_chn (dmpr_data_.incr_ev_chn, restart_volume_dump, null, 1, code);
        if code ^= 0 then do;				/* OK? */
	  call dmpr_report_$error_output (code, dmpr_data_.myname, "Error make event call channel");
	  goto finale;				/* Give up. */
	end;
      end;
						/* initialize ring 0 part of dumper */
    call hc_backup_$init_dmpr (dmpr_data_.dirp, dmpr_data_.segp, code);
    if code ^= 0 then do;
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Ring 0 dmpr init failure");
        goto finale;
      end;
    call dmpr_output_$init (code);
    if code ^= 0 then do;
        if code ^= -1 then				/* this code says that an attach/open failed	*/
	   call dmpr_report_$error_output (code, dmpr_data_.myname, "Output volume init failure");
        goto finale;
      end;
						/* init input structure to ring 0 */
    inputp = dmpr_data_.inputp;
    dmpr_input.version = dmpr_input_version_1;
    dmpr_input.type = dmpr_data_.dump_type;
    dmpr_input.reset = dmpr_data_.reset;
    dmpr_input.no_update = dmpr_data_.no_update;
    dmpr_input.no_object = dmpr_data_.no_object;
    dmpr_input.mod_after_time = dmpr_data_.mod_after_time;
    dmpr_data_.dump_in_progress = "1"b;			/* Set flag to prevent recursion. */
    go to over;					/* Start dump pass. */

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

wakeup_volume_dump: entry;				/* Enter here on  operator wakeup. */
    if dmprp = null then do;
no_dump: call com_err_ (0, "wakeup_volume_dump", "No dump to wakeup");
        return;
      end;
    dmpr_data_.myname = "wakeup_volume_dump";

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


restart_volume_dump: entry;				/* Enter here on alarm wakeup */

    if dmprp = null then do;
        call com_err_ (0, "restart_volume_dump", "no dump to restart");
        return;
      end;
    if dmpr_data_.dump_in_progress then do;		/* Is a dump pass being done now? */
        call dmpr_report_$online_output (0, dmpr_data_.myname,
	"Dump pass presently in progress; this call ignored.");
        return;
      end;

    call timer_manager_$reset_alarm_wakeup (dmpr_data_.incr_ev_chn);
    dmpr_data_.dump_in_progress = "1"b;			/* Set flag. */
    dmpr_data_.dmpr_asleep = "0"b;
    new_control_seg = "0"b;
    dmpr_data_already_locked = "0"b;
    call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper waking up at ^a", time_now_ ());

over:
    time_pass_started = clock;
						/* position to front of control file */
    call iox_$position (dmpr_data_.control_iocbp, -1, 0, code);
    if code ^= 0 then do;				/* OK? */
        call dmpr_report_$error_output (code, dmpr_data_.myname, "Error positioning on ^a",
	dmpr_data_.control_name);
        goto finale;				/* Give up. */
      end;
						/* initialize local variables */
    num_pv = 0;
    lvname (*) = "";
    pvname (*) = "";
    pvid (*) = "0"b;
    device_type (*) = 0;


/* This loop converts each line of the control file into a set(possibly one) of physical volume names and ids
   and stores the entire result in a local array of 100 entries. This is a limit on the number of online
   physical volumes that can be dumped by any one volume dumper. */

read_line:
    line = "";
    call iox_$get_line (dmpr_data_.control_iocbp, addr (line), length (line), nelemt, code);
    if code ^= 0 then do;
        if code = error_table_$end_of_info then goto begin_vol_dump;
        else do;
	  call dmpr_report_$error_output (code,
	    dmpr_data_.myname, "error reading ^a",
	    dmpr_data_.control_name);
	  goto finale;				/* Give up. */
	end;
      end;

    line = substr (line, 1, nelemt - 1);		/* strip off new line at end */
    if before (line, ",") = "lv" then do;
        tlvname = after (line, ",");
        call mdc_$lvname_info (tlvname, addr (pva), tnpv, code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to convert ^a to physical volumes",
	    tlvname);
	  goto read_line;
	end;
        do idx = 1 to tnpv;
	lvname (num_pv + idx) = tlvname;
	pvname (num_pv + idx) = pva (idx).pvname;
	pvid (num_pv + idx) = pva (idx).pvid;
	device_type (num_pv + idx) = pva (idx).device_type;
        end;
        num_pv = num_pv + tnpv;
      end;
    else if before (line, ",") = "pv" then do;
        num_pv = num_pv + 1;
        pvname (num_pv) = after (line, ",");
        call mdc_$pvname_info (pvname (num_pv), pvid (num_pv), lvname (num_pv), ignored_lvid,
	device_type (num_pv), code);
        if code ^= 0 then do;
	  call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to convert ^a to pvid",
	    pvname (num_pv));
	  num_pv = num_pv - 1;
	  goto read_line;
	end;
      end;
    else call dmpr_report_$error_output (0, dmpr_data_.myname, "Unrecognized line ^a", line);
    goto read_line;


/* This loop dumps each volid specified in the just constructed array. If we are in restart mode,
   then we skip over all volumes until a match is found and start from there. If not we start with the first volume
   in the list. In either case we process(dumped) each volume in turn reporting when we start and when we end
   and what we did. */

begin_vol_dump:
    inputp = dmpr_data_.inputp;
    first_pvx = 1;
    if dmpr_data_.restart_pvname = "" /* no restart specified */
      & ^new_control_seg
      & ^was_asleep
      & (dmpr_data_already_locked | (dmpr_data_.pvname ^= pvname (num_pv))) then do;
        if dmpr_data_already_locked then do;
	  dmpr_data_.restart_pvname = dmpr_data_.pvname;
	  call dmpr_report_$online_output (0, dmpr_data_.myname, "Restarting with physical volume ^a.",
	    dmpr_data_.restart_pvname);
	end;
        else if dmpr_data_.dump_type ^= incr then do;	/* it must be cons or comp */
	  call command_query_ (addr (query_info), answer, dmpr_data_.myname, "^/^a",
	    "Previous dump cycle may not have completed. Do you want to restart ? ");
	  if answer = "yes" then
	       dmpr_data_.restart_pvname = dmpr_data_.pvname;
	end;
      end;
    if dmpr_data_.restart_pvname ^= "" then do;
        if dmpr_data_.dump_type = incr then
	   dmpr_data_.cycle_uid = substr (bit (clock, 72), 20, 36);
        do idx = 1 to num_pv while (pvname (idx) ^= dmpr_data_.restart_pvname);
        end;
        if idx > num_pv then do;
	  call dmpr_report_$error_output (0, dmpr_data_.myname,
	    "No match of restart pvname ^a in control seg",
	    dmpr_data_.restart_pvname);
	  goto finale;
	end;
        first_pvx = idx;
      end;
    else dmpr_data_.cycle_uid = substr (bit (clock, 72), 20, 36);


    do idx = first_pvx to num_pv;
      dmpr_data_.pvid = pvid (idx);
      dmpr_data_.lvname = lvname (idx);
      dmpr_data_.pvname = pvname (idx);
      call mdc_$check_mounted (dmpr_data_.lvname, code);
      if code ^= 0 then do;
	call dmpr_report_$online_output (code, dmpr_data_.myname,
	  "Skipping logical volume ^a", dmpr_data_.lvname);
	do while (lvname (idx) = dmpr_data_.lvname);
	  idx = idx + 1;
	end;
	idx = idx - 1;
        end;
      else do;
	dmpr_data_.disk_type = device_type (idx);	/* set for the volume log			*/
	call hcs_$force_write (dmprp, force_write_bits, ignore);
						/* save changed dmpr_data_			*/
	if (dmpr_data_.dump_type = cons) | (dmpr_data_.dump_type = comp) then call dmpr_report_$online_output (0,
	       dmpr_data_.myname, "Begin dump of physical volume ^a", dmpr_data_.pvname);
	call dump_volume_ (code);
	if code = 0 then do;
	    call dmpr_report_$online_output (0, dmpr_data_.myname,
	      "Processed ^a: ^d ^d ^d ^d ^d",
	      dmpr_data_.pvname,
	      dmpr_data_.physical_volume_dir_rec, dmpr_data_.physical_volume_dir_num,
	      dmpr_data_.physical_volume_seg_rec, dmpr_data_.physical_volume_seg_num,
	      dmpr_data_.num_null_vtoce);


	    if dmpr_input.no_object then
	         call dmpr_report_$online_output (0, dmpr_data_.myname,
		 "Dumped ^d non null vtoces and ^d null vtoces",
		 dmpr_data_.num_vtoce_only, dmpr_data_.num_null_vtoce);

/* If this is a complete dump or the purge flag is on, then purge the volume log. This will release those dump
   volumes that have been superseeded by this dump */


	    if (dmpr_data_.dump_type = cons & dmpr_data_.incr_skip_count ^= -1)
	      | dmpr_data_.dump_type = comp then do;
	        call purge_volume_log_ (dmpr_data_.sys_dir, dmpr_data_.pvname, dmpr_data_.incr_skip_count,
		dmpr_data_.manual_free & dmpr_data_.auto_vol, code);
	        if code ^= 0 then
		   call dmpr_report_$error_output (code, dmpr_data_.myname, "Unable to purge volume log ^a",
		     dmpr_data_.pvname);
	      end;
	  end;
	else if code = -1 then goto finale;		/* Operator abort				*/
	else do;
	    call dmpr_report_$error_output (code, dmpr_data_.myname,
	      "Error dumping volume ^a", dmpr_data_.pvname);
	  end;
        end;
    end;


    dmpr_data_.restart_pvname = "";			/* only do it once */

    call dmpr_report_$online_output (0, dmpr_data_.myname, "Dump finished at ^a", time_now_ ());

/* If an incremental dump then setup alarm clock for wakeup */
    if dmpr_data_.dump_type = incr then do;
        call iox_$control (dmpr_data_.outputvol_iocbp, "error_count", addr (ignore), ignore);
        if dmpr_data_.detach then call dmpr_output_$end_pass_detach (ignore);
						/* detach if we are supposed too.		*/
        call timer_manager_$alarm_wakeup (time_pass_started + dmpr_data_.wakeup_interval, "00"b,
	dmpr_data_.incr_ev_chn);
        call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper going to sleep");
        call iox_$control (iox_$user_io, "start", null, code);
        if code ^= 0 then				/* OK? */
	   call dmpr_report_$error_output (code, dmpr_data_.myname, "iox_$control on user_i/o");
        dmpr_data_.dump_in_progress = ""b;		/* Indicate dump no longer active. */
        dmpr_data_.dmpr_asleep = "1"b;
        dmpr_data_.myname = "incremental_volume_dumper";	/* could have been invoked as wakeup_volume_dumper*/
        call hcs_$force_write (dmprp, force_write_bits, ignore);
						/* TRY and get it written now			*/

        return;					/* all done for this pass */
      end;
    goto finale;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


end_volume_dump: entry;				/* Finish up dumping. */

    if dmprp = null then do;				/* tell him there is no dump			*/
        call com_err_ (0, "end_volume_dump", "No dump to end.");
        return;
      end;
    dmpr_data_.myname = "end_volume_dump";
    dmpr_data_.dump_in_progress = "1"b;			/* let dmpr_finish_ turn it off		*/
    dmpr_data_.disable_error_report = "1"b;
    dmpr_data_.detach = "1"b;				/* detach output volume when finished */
finale:
    call dmpr_finish_ (ignore);
finale_nocleanup:
    return;					/* terminate processing */

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

preattach_dump_volumes: entry;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
/*									*/
/* Allow a running incremental dump to add volumes (just like the -preattach control	*/
/* argument), without having to do an end_volume_dump and starting over.		*/
/*									*/
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */

dcl announce_vols	     (nvols) char (32) based (addr (dmpr_data_.pre_attach_volname (dmpr_data_.pre_attach_vol + 1)));


    call ipc_$mask_ev_calls (code);			/* mask so we can do our work			*/
    if code ^= 0 then do;
        call com_err_ (code, "preattach_dump_volumes", "Unable to mask event calls, no preattachment performed.");
        return;
      end;

    if dmprp = null then do;				/* no funny stuff...			*/
        call com_err_ (0, "preattach_dump_volumes",
	"No dump in progress, use the ""-preattach"" control argument to the incremental_volume_dump command.");
        goto UNMASK_EV;
      end;

    if dmpr_data_.dump_type ^= incr then do;
        call com_err_ (0, "preattach_dump_volumes", "This command is only valid for incremental volume dumps.");
        goto UNMASK_EV;
      end;

    call cu_$arg_count (narg);
    if narg ^= 1 then do;
        call com_err_ (error_table_$wrong_no_of_args, "preattach_dump_volumes",
	"Usage is: preattach_dump_volumes no_of_volumes");
        goto UNMASK_EV;
      end;
    if dmpr_data_.detach then do;			/* ok, let's ask him if we should turn off this	*/
        call command_query_$yes_no (YES, 0, "preattach_dump_volumes",
	"In the invocation of the incremental_volume_dump command, -detach was specified.
This is used to detach  volumes after each pass of the dumper.  A ""yes"" answer will
turn this feature ""off"". A ""no"" answer will abort the preattachment of these volumes.",
	"Do you wish to turn off the effect of the -detach control argument (type ""?"" for an explaination).");
        if YES then dmpr_data_.detach = ""b;
        else goto UNMASK_EV;
      end;

    call cu_$arg_ptr (1, argp, argl, code);
    if verify (arg, "0123456789") = 0 then do;		/* only numbers fellas			*/
        nvols = fixed (arg, 17, 0);			/* now, be sure we don't have too many		*/

        if nvols = 0 then do;
	  call com_err_ (0, "preattach_dump_volumes", "The number of volumes must be greater than zero.");
	  goto UNMASK_EV;
	end;


        if ((dmpr_data_.pre_attach_vol + nvols) > hbound (dmpr_data_.pre_attach_volname, 1) |
	(hbound (dmpr_data_.pre_attach_volname, 1) - (nvols + dmpr_data_.pre_attach_vol) < 0)) then do;
	  call com_err_ (error_table_$action_not_performed, "preattach_dump_volumes",
	    "Too many volumes to preattach. Space available for ^d more.",
	    (hbound (dmpr_data_.pre_attach_volname, 1) - dmpr_data_.pre_attach_vol));
	  goto UNMASK_EV;
	end;
      end;
    else do;

        call com_err_ (error_table_$bad_conversion, "preattach_dump_volumes", "^a", arg);
        goto UNMASK_EV;
      end;

    on cleanup begin;
        code = 0;
        do while (code = 0);
	call ipc_$unmask_ev_calls (code);
        end;
      end;

    call dmpr_output_$preattach_vols (nvols, (dmpr_data_.pre_attach_vol + nvols) - (nvols - 1), code);
						/* get the volume names from the user or the pool */
    if code ^= 0 then goto UNMASK_EV;
    call dmpr_report_$online_output (0, "preattach_dump_volumes", "Please get the following volume^[s^]: ^v(^a ^)",
						/* announce which volumes to get		*/
      (nvols > 1), nvols, announce_vols (*));

    call dmpr_output_$preattach_ioname (nvols, (dmpr_data_.pre_attach_vol + nvols) - (nvols - 1), code);
						/* do the attach				*/
    if code = 0 then dmpr_data_.pre_attach_vol = dmpr_data_.pre_attach_vol + nvols;
UNMASK_EV:
    code = 0;
    do while (code = 0);
      call ipc_$unmask_ev_calls (code);
    end;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


set_volume_wakeup_interval: entry;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */
/*									*/
/* This entry allows the changing of the wakeup interval for a running incremental dump.	*/
/*									*/
/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * */

dcl i				fixed bin (35),
    my_interval			fixed bin (71);

    call ipc_$mask_ev_calls (code);
    if code ^= 0 then do;
        call com_err_ (code, "set_volume_wakeup_interval", "Unable to mask event calls, interval not changed.");
        return;
      end;
    areap, schedule_ptr = null ();
    areap = get_system_free_area_ ();
    on cleanup begin;
        if schedule_ptr ^= null () then free schedule in (Area);
        code = 0;
        do while (code = 0);
	call ipc_$unmask_ev_calls (code);
        end;
      end;
    if dmprp = null then do;
        call com_err_ (0, "set_volume_wakeup_interval", "No dump in progress.");
        goto UNMASK_EV;
      end;
    if dmpr_data_.dump_type ^= incr then do;
        call com_err_ (0, "set_volume_wakeup_interval", "This command is valid only for incremental volume dumps.");
        goto UNMASK_EV;
      end;
    call cu_$arg_count (narg);
    if narg ^= 1 then do;
        call com_err_ (error_table_$wrong_no_of_args, "set_volume_wakeup_interval",
	"Usage is: set_volume_wakeup_interval no_of_minutes");
        goto UNMASK_EV;
      end;
    call cu_$arg_ptr (1, argp, argl, code);
    if code ^= 0 then do;
        call com_err_ (code, "set_volume_wakeup_interval");
        goto UNMASK_EV;
      end;
    my_interval = cv_dec_check_ (arg, code);
    if code ^= 0 then do;
badint: call com_err_ (0, "set_volume_wakeup_interval", "The interval must be in minutes (1 to 1440).");
        goto UNMASK_EV;
      end;
    if (my_interval < 1) | (my_interval > 1440) then goto badint;
						/* make sure it's in the range		*/
    my_interval = my_interval * 60000000;		/* make it microseconds			*/
    call timer_manager_$get_schedule (areap, schedule_ptr, code);
    if code ^= 0 then do;
        call com_err_ (code, "set_volume_wakeup_interval", "Getting the event schedule.");
        goto UNMASK_EV;
      end;
    do i = 1 to schedule.n_timers;			/* now, find the right event channel		*/
      if schedule.timer (i).channel = dmpr_data_.incr_ev_chn then do;
						/* here it is				*/
	old_time = (schedule.timer (i).time - dmpr_data_.wakeup_interval);
						/* this was the *base* time for the wakeup	*/
	call timer_manager_$reset_alarm_wakeup (dmpr_data_.incr_ev_chn);
						/* reset the *old* one			*/
	dmpr_data_.wakeup_interval = my_interval;	/* set the new one				*/
	call timer_manager_$alarm_wakeup (old_time + dmpr_data_.wakeup_interval, "00"b,
	  dmpr_data_.incr_ev_chn);			/* and set the new wakeup			*/
	call hcs_$force_write (dmprp, force_write_bits, ignore);
						/* and get it written			*/
	free schedule in (Area);			/* be clean				*/
	goto UNMASK_EV;				/* let 'er rip				*/
        end;
    end;
    call com_err_ (0, "set_volume_wakeup_interval", "Unable to find the interval timer, no action performed.");
    free schedule in (Area);
    goto UNMASK_EV;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

volume_dump_trace_on: entry;

    trace = "1"b;					/* turn on tracing...			*/
    mname = "volume_dump_trace_on";
    goto trace_join;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

volume_dump_trace_off: entry ();
    mname = "volume_dump_trace_off";
    trace = "0"b;

trace_join:
    if dmprp = null () then				/* no dump to trace yet...			*/
         call com_err_ (0, mname, "No dump in progress.");
    else do;
        call cu_$arg_count (narg);
        if narg > 0 then call com_err_ (error_table_$wrong_no_of_args, mname,
	     "This command accepts no arguments.");
        else if dmpr_data_.trace = trace then call com_err_ (error_table_$action_not_performed, mname,
	     "Tracing is already in the state requested, ^[on^;^off^]", trace);
        else dmpr_data_.trace = trace;
      end;
    return;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


init: proc (type, myname);

dcl type		     fixed bin;
dcl myname	     char (*);
dcl (volname, pvname, prev_volname) char (32);
dcl (dir_rec, dir_num, seg_num, seg_rec) fixed bin;

/* This proc initializes the dumper's external static data base */

    call cu_$arg_count (narg);
    if narg < 2 then do;
        call dmpr_report_$error_output (error_table_$bad_arg, myname, "Required control args not specified");
        goto finale;
      end;
    if dmprp ^= null () then do;
        call com_err_ (0, myname, "Recursive invocations of the dumper are not allowed.^[^/Use end_volume_dump first.^]",
	type = incr);
        goto finale_nocleanup;
      end;
    do ac = 1 to narg;
      call cu_$arg_ptr (ac, argp, argl, code);
      if arg = "-control" then do;
	call cu_$arg_ptr (ac + 1, argp, argl, code);
	if code ^= 0 then do;
	    call dmpr_report_$error_output (code, myname,
	      "No control segment specified after -control.");
	    goto finale;
	  end;
	call suffixed_name_$make (arg, "dump", dump_control_name, code);
	if code ^= 0 then do;
	    call dmpr_report_$online_output (code, myname,
	      "Unable to create dump control seg name from ^a", arg);
	    goto finale;
	  end;
	call hcs_$status_minf (get_wdir_ (), dump_control_name, 0, (0), (0), code);
	if code ^= 0 then do;
	    call dmpr_report_$online_output (code, myname, "Unable to locate ^a>^a",
	      get_wdir_ (), dump_control_name);
	    goto finale;
	  end;
	call ioa_$rsnnl ("^a.^a.^a", control_seg_name, (0), arg, type_char (type), "control");
	call hcs_$make_seg (get_wdir_ (), control_seg_name, "", 01010b, dmprp, code);
	if code = 0 then do;			/* new control seg */
new_control:  call dmpr_report_$online_output (0, myname, "^/Creating new control seg ^a>^a",
	      get_wdir_ (), control_seg_name);
	    new_control_seg = "1"b;
	    dmpr_data_.version = dmpr_data_version_2;
	    prev_volname, volname, pvname = "";
	    cycle_uid = substr (bit (clock, 72), 20, 36);
	    dir_rec, dir_num, seg_rec, seg_num = 0;
	    call lock_dmpr_data;
	  end;
	else if dmprp ^= null then do;		/* already existed */
	    new_control_seg = "0"b;
	    if dmpr_data_.version ^= dmpr_data_version_3 then do;
	        if dmpr_data_.version = dmpr_data_version_2 then do;
		  dmpr_data_.version = dmpr_data_version_3;
		  dmpr_data_.disk_type = 0;		/* totally invisible			*/
		end;
	        else do;
		  call dmpr_report_$online_output (0, myname, "Invalid control seg found");
		  goto new_control;
		end;
	      end;
	    call lock_dmpr_data;
	    if (dmpr_data_.not_reported & dmpr_data_.cur_vol_open) then
						/* do only if the volume was opened.		*/
	         call dmpr_report_$online_output (0, myname,
		 "Finished volume ^a: ^d ^d ^d ^d", dmpr_data_.volname,
		 dmpr_data_.dump_volume_dir_rec, dmpr_data_.dump_volume_dir_num,
		 dmpr_data_.dump_volume_seg_rec,
		 dmpr_data_.dump_volume_seg_num);
	    cycle_uid = dmpr_data_.cycle_uid;
	    if dmpr_data_.cur_vol_open then do;		/* if it was opened successfully		*/
	        volname = dmpr_data_.volname;
	        prev_volname = dmpr_data_.volname;
	      end;
	    else do;				/* nope, use the previous one			*/
	        volname = dmpr_data_.prev_volname;
	        prev_volname = dmpr_data_.prev_volname;
	      end;
	    pvname = dmpr_data_.pvname;
	    dir_rec = dmpr_data_.physical_volume_dir_rec;
	    dir_num = dmpr_data_.physical_volume_dir_num;
	    seg_rec = dmpr_data_.physical_volume_seg_rec;
	    seg_num = dmpr_data_.physical_volume_seg_num;
	  end;
	else do;					/* couldn't create it, so punt */
	    call dmpr_report_$online_output (code, myname, "Unable to initialize control seg");
	    goto finale;
	  end;
        end;
    end;
    if dmprp = null then do;
        call dmpr_report_$online_output (0, myname,
	"Control seg initialization failed - control seg not specified.");
        goto finale;
      end;
    dmpr_data_.ptrs = null;
    if type = incr then was_asleep = dmpr_data_.dmpr_asleep;
    else was_asleep = "0"b;				/* save or set for restart processing		*/
    dmpr_data_.bits = "0"b;
    dmpr_data_.fixed_bin = 0;
    dmpr_data_.disk_type = 0;
    dmpr_data_.chars = "";
    if type = incr then dmpr_data_.detach = "0"b;		/* default for incrs			*/
    else dmpr_data_.detach = "1"b;
    dmpr_data_.cycle_uid = cycle_uid;
    dmpr_data_.wakeup_interval = 3600000000;		/* Default, one hour (in micro seconds) */
    dmpr_data_.data_init = "1"b;
    dmpr_data_.incr_skip_count = -1;
    dmpr_data_.pre_attach_vol = 0;
    dmpr_data_.dump_type = type;
    dmpr_data_.sys_dir = ">daemon_dir_dir>volume_backup";
    dmpr_data_.myname = myname;
    dmpr_data_.pvname = pvname;
    dmpr_data_.volname = volname;
    dmpr_data_.prev_volname = prev_volname;
    dmpr_data_.physical_volume_dir_rec = dir_rec;
    dmpr_data_.physical_volume_dir_num = dir_num;
    dmpr_data_.physical_volume_seg_rec = seg_rec;
    dmpr_data_.physical_volume_seg_num = seg_num;
    code = 0;
  end init;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


time_now_: proc returns (char (6));

/* This proc returns a time string suitable for printing of the present time */

    call date_time_ (clock, time_string);
    return (substr (time_string, 11, 6));
  end time_now_;

/*  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  *  * 	*/


lock_dmpr_data: proc;
    call set_lock_$lock (dmpr_data_.lock, lock_wait_time, code);
    if code ^= 0 then do;
        if code = error_table_$invalid_lock_reset then do;
	  code = 0;
	  dmpr_data_already_locked = "1"b;
	end;
        else do;
	  if dmpr_data_.dump_in_progress then do;
	      call dmpr_report_$online_output (0, dmpr_data_.myname,
	        "Dump pass presently in progress; this call ignored");
	      goto finale_nocleanup;
	    end;
	  else if dmpr_data_.dmpr_asleep then do;
	      call dmpr_report_$online_output (0, dmpr_data_.myname, "Dumper asleep. Use wakeup_volume_dump");
	      goto finale_nocleanup;
	    end;
	  else do;
	      call dmpr_report_$online_output (code, dmpr_data_.myname,
	        "Dumper invoked recursively. Use end_volume_dump");
	      goto finale_nocleanup;
	    end;
	end;
      end;
    else dmpr_data_already_locked = "0"b;
  end lock_dmpr_data;

%include dmpr_data_;

%include dmpr_input;
%include backup_static_variables;

%include backup_volume_header;

%include timer_manager_schedule;


  end dumper;



		    bull_copyright_notice.txt       08/30/05  1008.4r   08/30/05  1007.3    00020025

                                          -----------------------------------------------------------


Historical Background

This edition of the Multics software materials and documentation is provided and donated
to Massachusetts Institute of Technology by Group Bull including Bull HN Information Systems Inc. 
as a contribution to computer science knowledge.  
This donation is made also to give evidence of the common contributions of Massachusetts Institute of Technology,
Bell Laboratories, General Electric, Honeywell Information Systems Inc., Honeywell Bull Inc., Groupe Bull
and Bull HN Information Systems Inc. to the development of this operating system. 
Multics development was initiated by Massachusetts Institute of Technology Project MAC (1963-1970),
renamed the MIT Laboratory for Computer Science and Artificial Intelligence in the mid 1970s, under the leadership
of Professor Fernando Jose Corbato.Users consider that Multics provided the best software architecture for 
managing computer hardware properly and for executing programs. Many subsequent operating systems
incorporated Multics principles.
Multics was distributed in 1975 to 2000 by Group Bull in Europe , and in the U.S. by Bull HN Information Systems Inc., 
as successor in interest by change in name only to Honeywell Bull Inc. and Honeywell Information Systems Inc. .

                                          -----------------------------------------------------------

Permission to use, copy, modify, and distribute these programs and their documentation for any purpose and without
fee is hereby granted,provided that the below copyright notice and historical background appear in all copies
and that both the copyright notice and historical background and this permission notice appear in supporting
documentation, and that the names of MIT, HIS, Bull or Bull HN not be used in advertising or publicity pertaining
to distribution of the programs without specific prior written permission.
    Copyright 1972 by Massachusetts Institute of Technology and Honeywell Information Systems Inc.
    Copyright 2006 by Bull HN Information Systems Inc.
    Copyright 2006 by Bull SAS
    All Rights Reserved

