



		    daemon_user_manager_.pl1        07/13/88  1236.0r w 07/13/88  0938.7      371493



/****^  ***********************************************************
        *                                                         *
        * Copyright, (C) Honeywell Bull Inc., 1987                *
        *                                                         *
        * 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-05-13,GJohnson), approve(86-05-13,MCR7387),
     audit(86-05-13,Martinson), install(86-05-14,MR12.0-1055):
     Correct error message documentation.
  2) change(86-05-19,Gilcrease), approve(86-05-20,MCR7370),
     audit(86-06-25,Lippard), install(86-06-30,MR12.0-1082):
               Implement -truncate absout files. SCP6297.
               Also fix ioa_$rsnnl call, phx20101.
  3) change(87-04-26,GDixon), approve(87-07-13,MCR7741),
     audit(87-07-16,Brunelle), install(87-08-04,MR12.1-1055):
      A) Modify to use user_table_mgr_ to manage daemon_user_table entries.
      B) Upgraded for change to answer_table.incl.pl1 and
         user_table_entry.incl.pl1
      C) Note new user-signalled event for the disconnect command (disconn).
         Although the command cannot be used in absentee processes, if the user
         attempts to call terminate_process_ for a disconnection, we will
         instead destroy the process.
  4) change(87-05-12,GDixon), approve(87-07-13,MCR7741),
     audit(87-07-16,Brunelle), install(87-08-04,MR12.1-1055):
     Use constants in dialup_values.incl.pl1 to set ute.tag.
  5) change(87-05-15,GDixon), approve(87-07-13,MCR7741),
     audit(87-07-16,Brunelle), install(87-08-04,MR12.1-1055):
      A) Set ute.line_type.
      B) Set additional ute elements for Initializer's entry.
      C) Use constants to set/test ute.preempted.
  6) change(87-07-13,GDixon), approve(87-07-13,MCR7741),
     audit(87-07-16,Brunelle), install(87-08-04,MR12.1-1055):
      A) Add cleanup handler to free UTE.
      B) Remove windows in cleanup strategy.
      C) Supply missing operator message documentation.
                                                   END HISTORY COMMENTS */


/* format: style4 */
daemon_user_manager_: proc;

/* DAEMON_USER_MANAGER - Manage login requests from the operator.

   This program is the analogue of "dialup_" and "absentee_user_manager_", for the case
   in which the operator or the system startup deck wants a daemon process.
   These daemon processes often run without a typewriter console, sending their output to
   the initializer message coordinator via the message routing DIM. Real consoles are allowed though.

   Bob May, 1972

   Modified by THVV for real ttys and to fix bugs, 2/73
   Modified 750519 by PG for new_proc -auth and to logout daemons if they
   .	get a fatal process error, rather than new_proc'ing them (caused
   .	system loops if daemon was gronked).

   Modified April 1976 by T. Casey to check for "initxxxx" process termination event message.
   Modified 760819 by Roy Planalp to set outer module for daemons, instead of
   letting lg_ctl_ do it
   Modified September 1977 by T. Casey to log all ignored wakeups for debugging purposes.
   Modified March 1980 by Tom Casey to add metering.
   Modified June 1981 by T. Casey for MR9.0 to fix bug in metering.
   Modified November 1981, E. N. Kittlitz.  user_table_entry conversion.
   Modified May 1982, E. N. Kittlitz. New AS intialization.
   Modified October 1982, E. N. Kittlitz. Allow FPE to cause new_proc.
   Modified May 1983, E. N. Kittlitz. logout trm_ mechanism.
   Modified 84-04-24 BIM to set ute.tag
   Modified 84-11-27 by E. Swenson for new IPC validation.
   Modified 1985-01-10, BIM: MC access control.
   Modified 1985-01-16 by E. Swenson to set ute.tag before calling lg_ctl_.
   Modified 1985-02-20, BIM: logout_source_no_access_check.
   Modified 1985-03-18, E. Swenson to fix above entry.
   Modified 1985-04-05, E. Swenson to return error codes for subroutine calls.
   Modified 1985-04-23, E. Swenson to zero error code for successful login.
*/

/* entry parameters */

dcl  a_person char (*);
dcl  a_project char (*);
dcl  a_source char (*);
dcl  a_string char (*);
dcl  a_code fixed bin (35);
dcl  ev_chn_msgp ptr;

/* automatic */

dcl  bad_login_arg_fmt char (100);			/* for login errors */
dcl  buff char (256);				/* for formatting error messages */
dcl  buff_len fixed bin;				/* number of good chars in buff */
dcl  code fixed bin (35);				/* used for call status returns */
dcl  dum_status char (8) init ("null    ");		/* where we are in the process */
dcl  found_one_sw bit (1) aligned init ("0"b);		/* TRUE in logout if one user has been done. */
dcl  hello char (64) aligned;				/* Daemon login message. */
dcl  i fixed bin;					/* do index */
dcl  indx fixed bin;				/* dut index */
dcl  lg_ctl_reason char (8);				/* return code from $daemon_in */
dcl  loginline char (168) aligned;			/* Daemon login line. */
dcl  modes char (12) aligned;				/* .. new modes (not used) */
dcl  rcode fixed bin (35);				/* RCP error code. */
dcl  reason char (8) init ("null    ");			/* reason code for login or logout */
dcl  star_person_sw bit (1) aligned;
dcl  star_project_sw bit (1) aligned;
dcl  star_source_sw bit (1) aligned;
dcl  t_person char (28);				/* temporaries for commonality in login and logout processing */
dcl  t_project char (28);				/* temporaries for commonality in login and logout processing */
dcl  t_source char (32);				/* temporaries for commonality in login and logout processing */
dcl  tempp ptr;
dcl  wakeup_from_as bit (1) aligned init (""b);
dcl  wakeup_from_ring_0 bit (1) aligned init (""b);
dcl  wakeup_from_user bit (1) aligned init (""b);
dcl  ws_ev_chn fixed bin (71);			/* working storage */
dcl  ws_ev_msg char (8);
dcl  ws_from_procid bit (36) aligned;

/* entries */

dcl  act_ctl_$close_account entry (ptr);
dcl  act_ctl_$cp entry (ptr);
dcl  act_ctl_$dp entry (ptr);
dcl  act_ctl_$open_account entry (ptr);
dcl  aim_check_$in_range entry (bit (72) aligned, (2) bit (72) aligned) returns (bit (1) aligned);
 dcl  as_dump_ entry (char (*) aligned);
dcl  as_meter_$enter entry (fixed bin);
dcl  as_meter_$exit entry (fixed bin);
dcl  asu_$find_process entry (bit (36) aligned, fixed bin, ptr);
dcl  asu_$send_term_signal entry (ptr, fixed bin) returns (bit (1) aligned);
dcl  asu_$start_process entry (ptr);			/* called to get a process running */
dcl  condition_ entry (char (*), entry);
dcl  convert_access_class_$from_string_range entry ((2) bit(72) aligned, char(*), fixed bin(35));
dcl  convert_status_code_ entry (fixed bin (35), char (*), char (*));
dcl  cpg_$cpg_daemon entry (ptr, fixed bin (35));
dcl  daemon_user_manager_$dum_event entry (ptr);		/* for event call */
dcl  dpg_	entry (ptr, char(*));
dcl  dpg_$finish entry (ptr);
dcl  get_authorization_ entry() returns(bit(72) aligned);
dcl  get_process_id_ entry () returns (bit (36) aligned);
dcl  get_ring_ entry() returns(fixed bin(3));
dcl  hcs_$truncate_seg entry (ptr, fixed bin(19), fixed bin(35));
dcl  hcs_$wakeup entry (bit (*) aligned, fixed bin (71), fixed bin (71), fixed bin (35));
dcl  hphcs_$set_cpu_monitor entry (bit (36) aligned, fixed bin (71), fixed bin (35));
dcl  ioa_$rsnnl entry options (variable);
dcl  ipc_$decl_ev_call_chn entry (fixed bin (71), entry, ptr, fixed bin, fixed bin (35));
dcl  lg_ctl_$daemon_in entry (ptr, char (*), fixed bin (35));
dcl  lg_ctl_$daemon_out entry (ptr);
dcl  mc_check_access_$log_daemon_out entry (pointer, character (*), fixed binary (35));
dcl  lv_request_$cleanup_process entry (bit (36) aligned);
dcl  parse_login_line_ entry (ptr, fixed bin, ptr, char (*) aligned, char (*) aligned, fixed bin (35));
dcl  rcp_sys_$unassign_process entry (bit (36) aligned, fixed bin (35));
dcl  ssu_$get_info_ptr entry (ptr) returns (ptr);
dcl  sub_err_ entry () options (variable);
dcl  sys_log_ entry options (variable);
dcl  sys_log_$error_log entry options (variable);
dcl  sys_log_$command entry options (variable);		/* (fixed bin) */
dcl  sys_log_$command_error entry options (variable);	/* (fixed binary, fixed binary (35), character (*)); */
dcl  timer_manager_$reset_alarm_wakeup entry (fixed bin (71));
dcl  user_table_mgr_$allocate	entry (fixed bin) returns(ptr);
dcl  user_table_mgr_$free entry (ptr);

/* external static */

dcl  as_error_table_$illegal_new_proc ext fixed bin (35);
dcl  as_error_table_$bump_cancelled fixed bin (35) ext static;
dcl  as_error_table_$illegal_signal fixed bin (35) ext static;
dcl  error_table_$out_of_sequence fixed bin (35) ext static;
dcl  error_table_$noentry fixed bin (35) ext static;
dcl  error_table_$namedup fixed bin (35) ext static;
dcl  error_table_$action_not_performed fixed bin (35) ext static;
dcl  sys_info$max_seg_size fixed bin (35) ext static;

/* builtins */

dcl  (addr, baseno, clock, divide, fixed, hbound, lbound, length, null, rel, size, substr) builtin;

/* internal static */

dcl  ME char (32) initial ("daemon_user_manager_") internal static options (constant);
dcl  static_label label internal static;
dcl  STOPstop char (8) aligned int static init ("STOPstop") options (constant);
dcl  STOPstop_msg fixed bin (71) based (addr (STOPstop));	/* For special wakeup. */
dcl  termstop char (8) aligned int static init ("termstop") options (constant);
dcl  termstop_msg fixed bin (71) based (addr (termstop));

/* based */

dcl  1 new_proc_auth aligned based (addr (ws_ev_msg)),
       2 np_signal char (2) unaligned,
       2 authorization bit (54) unaligned;

dcl  1 ev_msg_string aligned based (addr (ws_ev_msg)),	/* to decode "term...." or other commands */
       2 cmd char (4),
       2 fs_code fixed bin;				/* for use in check_fs_errcode */

dcl  signal_type char (8) aligned based;
dcl  sys_log entry variable options (variable);
dcl  sys_log_error entry variable options (variable);
dcl  subroutine_entry bit (1) aligned initial ("0"b);
%page;

/* Program */

/**** Subroutine interface to login */

login_:
     entry (a_person, a_project, a_source, a_string, a_code);

	sys_log = sys_log_;
	sys_log_error = sys_log_$error_log;
	subroutine_entry = "1"b;
	go to login_common;

login: entry (a_person, a_project, a_source, a_string);

	sys_log = sys_log_$command;
	sys_log_error = sys_log_$command_error;
	subroutine_entry = "0"b;

login_common:

	dum_status = "login   ";			/* where we are in case of trouble */
	static_label = ucs_return;			/* guarenteed return to system level */
	call condition_ ("any_other", ucs);		/* Set up error-handling procedure. */
	utep = null;
	call condition_ ("cleanup", cleaner_up);
	if as_data_$dutp = null then go to no_init;	/* check for init already done */
	dutp = as_data_$dutp;
	call as_meter_$enter (DUM_METER);

/* initial checks ok. now search for open entry */

	reason = "login   ";			/* Note what was going on. */
	t_person = a_person;			/* use temps for commonality */
	t_project = a_project;			/* .. copy all arguments */
	t_source = a_source;			/* ... */
	loginline = t_person || " " || t_project || " " || a_string;
	indx = 0;					/* 'indx' remembers location of free slot. */

	do i = 2 to dutbl.current_size;		/* Scan daemons (skipping initializer) for free or already in */
	     utep = addr (dutbl.entry (i));		/* Get ptr to entry. */
	     if ute.tty_name = t_source then do;	/* Source is already in use. */
		call sys_log (SL_LOG, "login: ^a.^a already logged in on ^a",
		     ute.person, ute.project, ute.tty_name); /* .. this would mess up message coord. */
		if subroutine_entry then a_code = error_table_$namedup;
		goto exit;			/* Cannot log the fellow in. */
	     end;
	end;

          static_label = backout_1;
          utep = user_table_mgr_$allocate (PT_DAEMON);
	if utep = null then go to exit;

	ute.uflags.fpe_causes_logout = "1"b;		/* default for daemons */
	call parse_login_line_ (addr (loginline), 168, utep, modes, hello, code);
	if code ^= 0 then do;			/* See if error in optional args. */
	     call convert_status_code_ (code, "", bad_login_arg_fmt);
	     call ioa_$rsnnl (bad_login_arg_fmt, buff, buff_len, hello);
	     call sys_log (SL_LOG, "login: Cannot login ^a.^a ^a", t_person, t_project, t_source);
	     call sys_log (SL_LOG, buff);
	     ute.active = NOW_FREE;
	     if subroutine_entry then a_code = code;
	     goto backout_1;
	end;

	call ipc_$decl_ev_call_chn (ute.event,
	     daemon_user_manager_$dum_event, utep, DAEMON_LOGIN_PRIO, code);
	if code ^= 0 then do;
	     call sys_log_error (SL_LOG_BEEP, code, "login", "declaring ev_call_chn for ^a ^a ^a",
		t_person, t_project, t_source);
	     if subroutine_entry then a_code = code;
	     go to backout_1;			/* Go free this entry. */
	end;

	ute.person = t_person;			/* .. for login */
	ute.project = t_project;			/* ... */
	ute.tag = TAG_DAEMON;
	ute.tty_name = t_source;			/* ... */
	ute.tty_id_code = substr (t_source, 1, length (ute.tty_id_code));			/* ... */
	ute.line_type = LINE_MC;
	ute.queue = -1;				/* special daemon flag  */
	ute.n_processes = 0;			/* no processes yet */
	ute.channel = null;				/* no attached channels */
	ute.outer_module = as_data_$mrd_dim;		/* daemons use message routing DIM */

	static_label = backout_2;
	call lg_ctl_$daemon_in (utep, lg_ctl_reason, code); /* Verify that daemon is registered. */
	if ute.login_result ^= 0 then do;		/* If daemon login is not allowed, */
	     reason = lg_ctl_reason;			/* .. complain and */
	     if subroutine_entry then do;
		call sys_log (SL_LOG, "login: no login ^a.^a ^a ^a",
		     ute.person, ute.project, ute.tty_name, reason); /* lg_ctl_ has audited officially */
		a_code = code;
		if a_code = 0 then a_code = error_table_$action_not_performed;
	     end;
	     else call sys_log (SL_LOG, "login: no login ^a.^a ^a ^a",
		     ute.person, ute.project, ute.tty_name, reason); /* lg_ctl_ has audited officially */
	     go to backout_1;			/* .. give up. */
	end;

	ute.active = NOW_LOGGED_IN;			/* Indicate that there is a user in the slot. */
	call act_ctl_$open_account (utep);		/* Now we check accounting limits. */
l_cpg_:	ute.n_processes = ute.n_processes + 1;
	call cpg_$cpg_daemon (utep, code);		/* Create daemon process */
	if code ^= 0 then do;			/* If process cannot be created, */
	     if subroutine_entry then do;
		call sys_log_error (SL_LOG, code, "login", "creating proc for ^a ^a ^a",
		     t_person, t_project, t_source);	/* .. fuss and */
		a_code = code;
	     end;
	     else call sys_log_error (SL_LOG, code, "login", "creating proc for ^a ^a ^a",
		     t_person, t_project, t_source);	/* .. fuss and */


	     go to backout_2;			/* .. destroy the user. */
	end;

	call act_ctl_$cp (utep);			/* we made it all the way */

	ute.active = NOW_HAS_PROCESS;			/* Mark slot having process. */
	ute.destroy_flag = WAIT_LOGOUT_SIG;		/* .. and expecting logout next. */

	call asu_$start_process (utep);		/* kick the process into execution */
	if subroutine_entry then
	     a_code = 0; /* no error */
	goto exit;
%page;

/**** This entrypoint is called by the server for send daemon logout commands */

logout_source_no_access_check:
     entry (a_source, a_code);

	dum_status = "logout  ";			/* normal entry */
	subroutine_entry = "1"b;
	static_label = ucs_return;			/* set up guarenteed return to system level */
	call condition_ ("any_other", ucs);		/* Set up error-handling procedure. */
	if as_data_$dutp = null then go to no_init;	/* check for init already done */
	dutp = as_data_$dutp;
	call as_meter_$enter (DUM_METER);

	reason = "logout  ";			/* normal path of action */
	found_one_sw = "0"b;
	t_source = a_source;
	a_code = 0;

	do i = 2 to dutbl.current_size		/* never look at Initializer */
	     while (^found_one_sw);
	     utep = addr (dutbl.entry (i));		/* step through the entries to find "t_source" */
	     if ute.active = NOW_FREE then go to logout_nacc_get_next;

	     if ute.tty_name ^= t_source then go to logout_nacc_get_next;
	     found_one_sw = "1"b;			/* so we don't get "missing entry" msg */

	     ute.destroy_flag = WAIT_LOGOUT;		/* Indicate that process logs out when it dies. */
	     if ^asu_$send_term_signal (utep, 0) then do; /* didn't send trm_ */
		ute.logout_type = "term";
		call destroy_process;
	     end;
	     else ute.logout_type = "looc";
logout_nacc_get_next:
	end;					/* loop through DUT */

	if ^found_one_sw
	then a_code = error_table_$noentry;
	go to exit;


logout: entry (a_person, a_project, a_source);

	dum_status = "logout  ";			/* normal entry */
	sc_subsystem_info_ptr = ssu_$get_info_ptr (sc_stat_$admin_sci_ptr);
	static_label = ucs_return;			/* set up guarenteed return to system level */
	call condition_ ("any_other", ucs);		/* Set up error-handling procedure. */
	if as_data_$dutp = null then go to no_init;	/* check for init already done */
	dutp = as_data_$dutp;
	call as_meter_$enter (DUM_METER);

	reason = "logout  ";			/* normal path of action */

	found_one_sw = "0"b;			/* we haven't found any */
	t_person = a_person;
	star_person_sw = (t_person = "*");
	t_project = a_project;
	star_project_sw = (t_project = "*");
	t_source = a_source;
	star_source_sw = (t_source = "*");
	do i = 2 to dutbl.current_size		/* never look at Initializer */
	     while (^found_one_sw | star_person_sw |
	     star_source_sw | star_project_sw);
	     utep = addr (dutbl.entry (i));		/* step through the entries to find "t_person" */
	     if ute.active = NOW_FREE then go to logout_get_next;

	     if ^star_person_sw & ute.person ^= t_person then go to logout_get_next;
	     if ^star_project_sw & ute.project ^= t_project then go to logout_get_next;
	     if ^star_source_sw & ute.tty_name ^= t_source then go to logout_get_next;
	     found_one_sw = "1"b;			/* so we don't get "missing entry" msg */
	     call mc_check_access_$log_daemon_out (sc_subsystem_info_ptr, (ute.tty_name), code);
	     if code ^= 0 then do;
		if code = error_table_$noentry
		then call sys_log_$command_error (SL_LOG, code, "logout",
		     "No MC ACS segment for message coordinator source ^a.",
		     ute.tty_name);
		else call sys_log_$command_error (SL_LOG, code, "logout",
		     "Logout not permitted for message coordinator source ^a.",
		     ute.tty_name);
		go to logout_get_next;
	     end;

	     ute.destroy_flag = WAIT_LOGOUT;		/* Indicate that process logs out when it dies. */
	     if ^asu_$send_term_signal (utep, 0) then do; /* didn't send trm_ */
		ute.logout_type = "term";
		call destroy_process;
	     end;
	     else ute.logout_type = "looc";
logout_get_next:
	end;					/* loop through DUT */
	if ^found_one_sw then
	     call sys_log_$command (SL_LOG, "logout: Entry not found. ^a ^a ^a", t_person, t_project, t_source);
	goto exit;
%page;

/* This entry is called in response to a signal over the event channel in the daemon user table entry.
   It handles logout requests from the daemon, login failures from the daemon, and process terminations. */

dum_event: entry (ev_chn_msgp);

	event_call_info_ptr = ev_chn_msgp;		/* copy argument */
	dum_status = "event   ";			/* where we are in case of trouble */
	static_label = ucs_return;
	code = 0;
	call condition_ ("any_other", ucs);		/* Set up error-handling procedure. */

	if as_data_$dutp = null then go to no_init;	/* another "impossible" */
	dutp = as_data_$dutp;
	if event_call_info_ptr = null then do;		/* also should never happen */
	     call sys_log_ (SL_LOG_BEEP, "^a: Event entry called with null ev_msg_ptr", ME);
	     return;
	end;
	call as_meter_$enter (DUM_METER);
	utep = event_call_info.data_ptr;		/* should point right to dut.entry */
	if baseno (utep) ^= baseno (dutp) then do;	/* check for right ballpark */
	     go to evil;
	end;
	ws_ev_chn = event_call_info.channel_id;
	ws_from_procid = event_call_info.sender;
	if fixed (event_call_info.origin.ring, 18) = 0 then wakeup_from_ring_0 = "1"b;
	else if ws_from_procid = dutbl.as_procid then wakeup_from_as = "1"b;
	else if ws_from_procid = ute.proc_id then wakeup_from_user = "1"b;
	else go to evil;
	if ute.active ^= NOW_HAS_PROCESS then do;	/* Signal should refer to active process. */
	     if ws_ev_msg = "STOPstop" then goto log_ignored_msg;
	     if ws_ev_msg = "termstop" then goto log_ignored_msg;
evil:	     call asu_$find_process (ws_from_procid, i, tempp);
	     if tempp = null then
		call sys_log_ (SL_LOG_BEEP, "^a: Invalid signal from process ^w", ME, ws_from_procid);

	     else call sys_log_ (SL_LOG_BEEP, "^a: Invalid signal from ^a ^a ^a",
		     ME, tempp -> ute.person, tempp -> ute.project, tempp -> ute.tty_name);
	     call sys_log_ (SL_LOG_BEEP, "^a: signal was ""^24.3b"" ^p",
		ME, event_call_info.message, utep);
	     goto exit;
	end;

	t_person = ute.person;			/* set up for login after logout */
	t_project = ute.project;
	t_source = ute.tty_name;
	ws_ev_msg = addr (event_call_info.message) -> signal_type; /* see what's happening */
	reason = ws_ev_msg;
	if ws_ev_msg = "STOPstop" then go to logout_part_two;

/* First part of a logout. Classify the signal and dispatch on it. */

	if wakeup_from_user then do;
	     do i = 1 to n_signals while (ws_ev_msg ^= signals (i)); end;
	     if i > n_signals
	     then if new_proc_auth.np_signal = "np"
		then i = 13;
		else i = 1;			/* hangup, probably */
	end;
	else do;					/* must be from system */
	     do i = 1 to n_system_signals while (ws_ev_msg ^= system_signals (i)); end;
	     if i <= n_system_signals then i = i + 19;	/* it was a system signal */
	     else i = 19;				/* foo */
	end;

	if i < lbound (logout_handler, 1) | i > hbound (logout_handler, 1) then
	     go to log_ignored_msg;
	go to logout_handler (i);

logout_handler (7):					/* init_err */
logout_handler (8):					/* no_ioatt */
logout_handler (9):					/* no_initp */
logout_handler (10):				/* disconn  */
logout_handler (11):
logout_handler (12):				/* Absentee only. */
	call sys_log_ (SL_LOG_BEEP, "^a: Daemon init error: ^a ^a ^a ^a",
	     ME, ute.person, ute.project, ute.tty_name, reason);
logout_handler (3):					/* Logout -hold */
logout_handler (4):					/* logout */
logout_handler (5):					/* logout -bf */
logout_handler (6):					/* logout -hold -bf */
	ute.destroy_flag = WAIT_LOGOUT;
	ute.logout_type = substr (reason, 1, length (ute.logout_type));
	go to event_logout;
logout_handler (27):				/* terminat */
	ute.destroy_flag = WAIT_NEW_PROC;
	ute.logout_type = "np";
	if ^asu_$send_term_signal (utep, 0) then
	     call destroy_process;
	go to exit;

logout_handler (14):				/* termsgnl */
	call timer_manager_$reset_alarm_wakeup (ute.event);
	call hphcs_$set_cpu_monitor (ute.proc_id, -1, 0);
	if ute.preempted = PREEMPT_UNBUMP then do;
	     code = as_error_table_$bump_cancelled;
	     go to logout_handler (1);
	end;
	if ute.preempted = PREEMPT_TERM_SENT then do;	/* sent term signal, expecting termsgnl */
	     ute.preempted = PREEMPT_TERMSGNL_RECEIVED;
	     go to event_logout;
	end;
	code = as_error_table_$illegal_signal;
	go to logout_28a;

logout_handler (1):					/* Process termination. */
logout_handler (28):				/* termstop */
	if ws_ev_msg = "termstop" then code = 0;
	else code = ev_msg_string.fs_code;		/* break out "term...." or "init...." message */
logout_28a:
	call sys_log_$error_log (SL_LOG_BEEP, code, ME, "^a.^a ^a terminated^[ (^a)^].",
	     ute.person, ute.project, ute.tty_name, (code = 0), reason);
	if ev_msg_string.cmd = "init" then do;
	     ute.logout_type, reason = "init";
	     ute.destroy_flag = WAIT_LOGOUT;
	end;
	else if ute.destroy_flag = WAIT_LOGOUT_SIG then do; /* a big-boy terminated */
	     ute.logout_type, reason = "term";
	     if ute.recent_fatal_error_time + installation_parms.fatal_error_loop_seconds * 1000000 < clock () then
		do;				/* if previous fatal error was long ago */
		if ute.uflags.fpe_causes_logout then do;/* user has no wish to continue */
		     call sys_log_ (SL_LOG, "^a: Daemon will be logged out.", ME);
		     ute.destroy_flag = WAIT_LOGOUT;
		end;				/* fpe causes logout */
		else do;
		     ute.recent_fatal_error_time = clock (); /* reset the fatal error loop timer */
		     ute.recent_fatal_error_count = 1;	/* and set the counter back to 1 */
create_another_new_proc:
		     ute.destroy_flag = WAIT_NEW_PROC;	/* let user have another new process after destroying this one. */
		     call sys_log_ (SL_LOG, "^a: New process created.", ME);
		end;				/* ^ute.fpe_causes_logout */
	     end;					/* last FPE was long ago */

	     else do;				/* we seem to have a loop */
		ute.recent_fatal_error_count = ute.recent_fatal_error_count + 1; /* count times around it */
		if ute.recent_fatal_error_count < installation_parms.fatal_error_loop_count then /* if not too many */
		     ute.destroy_flag = WAIT_NEW_PROC;
		else do;
		     ute.destroy_flag = WAIT_LOGOUT;	/* too many. boom */
		     call sys_log_ (SL_LOG, "^a: Fatal process error loop for ^a.^a ^a.
Daemon will be logged out.",
			ME, ute.person, ute.project, ute.tty_name);
		end;				/* terminate fatal process error loop */
	     end;					/* check for FPE loop */
	end;					/* term signalled */
	go to event_logout;

logout_handler (13):				/* new_proc -auth AUTH */
	ute.destroy_flag = WAIT_NEW_PROC;

	ute.logout_type = substr (reason, 1, length (ute.logout_type));
	if ^aim_check_$in_range ((new_proc_auth.authorization), ute.process_authorization_range) then do;
	     call sys_log_$error_log (SL_LOG, as_error_table_$illegal_new_proc, ME,
		"Cannot new_proc to an authorization outside the daemon's allowed range.");
	     go to event_logout;
	end;

	ute.process_authorization = new_proc_auth.authorization;
	go to event_logout;

logout_handler (2):					/* new_proc */
	ute.destroy_flag = WAIT_NEW_PROC;
	ute.logout_type = substr (reason, 1, length (ute.logout_type));
	go to event_logout;

logout_handler (23):				/* alarm___ */
logout_handler (29):				/* cpulimit */
	call timer_manager_$reset_alarm_wakeup (ute.event);
	call hphcs_$set_cpu_monitor (ute.proc_id, -1, (0));
	if ute.preempted <= PREEMPT_UNBUMP_IGNORE_ALARM then go to exit;
						/* no reason to die */
	if ute.preempted = PREEMPT_TERM_SENT then do;	/* sent trm_, got no response */
	     ute.preempted = PREEMPT_TERMSGNL_RECEIVED;
	     call sys_log_ (SL_LOG, "^a: process ^a.^a ^a ignored trm_ signal.",
		ME, ute.person, ute.project, ute.tty_name);
	end;
	else go to log_ignored_msg;
	reason = "logout";
	ute.logout_type = substr (reason, 1, length (ute.logout_type));
	go to event_logout;

/* Come here to complete process destruction. */

logout_handler (26):				/* stopstop */
logout_part_two:
	if ute.destroy_flag = WAIT_LOGOUT_SIG then do;	/* This "stopstop" is premature. */
	     call sys_log_ (SL_LOG_SILENT, "^a: premature STOPSTOP for ^a.^a ^a",
		ME, ute.person, ute.project, ute.tty_name);
	     call hcs_$wakeup (dutbl.as_procid, ute.event, termstop_msg, code);
	     call hcs_$wakeup (dutbl.as_procid, ute.event, STOPstop_msg, code);
	     goto exit;				/* Assume that a "termxxxx" will arrive. */
	end;
	call dpg_$finish (utep);			/* Process destroyed self. Clean out. */
	ute.active = NOW_LOGGED_IN;			/* Process all gone. */
	call act_ctl_$dp (utep);			/* we destroyed the process */
	if ute.destroy_flag = WAIT_NEW_PROC then go to l_cpg_; /* Go make a new process. */
backout_2:
	call act_ctl_$close_account (utep);
	call lg_ctl_$daemon_out (utep);
backout_1:
	call user_table_mgr_$free (utep);
	goto exit;

ucs_return:					/* the infallible return */
	if subroutine_entry then
	     a_code = error_table_$action_not_performed;
	go to exit;

event_logout:
	call destroy_process;
	go to exit;

logout_handler (15):				/* unused */
logout_handler (16):				/* unused */
logout_handler (17):				/* unused */
logout_handler (18):				/* unused */
logout_handler (19):				/* unused */
logout_handler (20):				/* hangup */
logout_handler (21):				/* shutdown */
logout_handler (22):				/* bump */
logout_handler (24):				/* detach */
logout_handler (25):				/* unbump */
log_ignored_msg:
	call sys_log_ (SL_LOG_SILENT, "^a: process ^a.^a ^a ignored wakeup ^24.3b from ^w",
	     ME, event_call_info.message, ute.person, ute.project, ute.tty_name, ws_from_procid);

exit:	static_label = retr;
	call as_meter_$exit (DUM_METER);
retr:	return;


no_init:						/* operator no no */
	call sys_log_$command (SL_LOG_BEEP, "^a: Command sent to daemon_user_manager_ before it was initialized", ME);
	if subroutine_entry then
	     a_code = error_table_$action_not_performed;
	return;
%page;
init: entry;

	if ^sc_stat_$Multics_typed then
	     call sub_err_ (error_table_$out_of_sequence,
	     "daemon_user_manager_$init", "s");
	dum_status = "init    ";			/* in case of trouble */
	call hcs_$truncate_seg (as_data_$dutp, 0, code);
	if code ^= 0 then
	     call sub_err_ (code, "daemon_user_manager_$init", "s");
	dutp = as_data_$dutp;
	dutbl.header_version = DUTBL_version_4;		/* set version number into active table */
	dutbl.entry_version = UTE_version_4;
	dutbl.user_table_type = PT_DAEMON;
	dutbl.header_length = fixed (rel (addr (dutbl.entry (1))));
	dutbl.max_size = divide (sys_info$max_seg_size - dutbl.header_length, size (ute), 17, 0);
	dutbl.current_size = 0;			/* Empty table. */
	dutbl.number_free, dutbl.first_free = 0;
	dutbl.as_procid = get_process_id_ ();

	utep = user_table_mgr_$allocate (PT_DAEMON);	/* First entry in DUT is always initializer */

	ute.active = NOW_HAS_PROCESS;			/* Fill in entry.*/
	ute.person = "Initializer";
	ute.project = "SysDaemon";
	ute.tag = TAG_DAEMON;
	ute.process_authorization = get_authorization_();
	ute.outer_module = "otw_";
	ute.home_dir = as_data_$sysdir;
	ute.queue = -1;				/* means "daemon"*/
	ute.proc_id = dutbl.as_procid;
	call convert_access_class_$from_string_range (
	   ute.process_authorization_range, "system_low:system_high", code);
	ute.highest_ring = get_ring_();
	ute.tty_name = "sysctl";
	ute.line_type = LINE_MC;
	ute.tty_id_code = "****";
	ute.cpu_this_process = 0;
	ute.mem_this_process = 0;
	ute.last_update_time = clock ();
	ute.login_time = ute.last_update_time;
	ute.n_processes = 1;
	ute.work_class = 0;
	ute.group = "System";

	return;
%page;
cleaner_up:
	proc;

	if utep = null then return;
	if static_label = backout_2 then do;
	     call act_ctl_$close_account (utep);
	     call lg_ctl_$daemon_out (utep);
	     static_label = backout_1;
	end;
	if static_label = backout_1 then do;
	     call user_table_mgr_$free (utep);
	     utep = null;
	     static_label = ucs_return;
	end;
	if static_label = retr then do;
	     call as_meter_$exit (DUM_METER);
	     static_label = retr;
	end;
     	end cleaner_up;
     

destroy_process: proc;
	ws_ev_chn = ute.event;			/* set for logout */
	call rcp_sys_$unassign_process (ute.proc_id, rcode);
	if ute.lvs_attached then
	     call lv_request_$cleanup_process (ute.proc_id);
	call dpg_ (utep, reason);			/* logout process started */
     end destroy_process;


ucs: proc (mcptr, condname, coptr, infoptr, continue);

dcl  (mcptr, coptr, infoptr) ptr,			/* not used */
     condname char (*),
     continue bit (1);

dcl  non_local bit (1);
dcl  err_msg char (120) aligned, err_n fixed bin;
dcl  as_check_condition_ entry (char (*), bit (1), bit (1));

	call as_check_condition_ (condname, continue, non_local);
	if continue | non_local then return;

	call ioa_$rsnnl ("^a: Error: ^a during ^a for ^a ^a ^a", err_msg, err_n, ME,
	     condname, dum_status, t_person, t_project, t_source);
	dum_status = "ucs     ";			/* we're here now */
	call sys_log_ (SL_LOG_BEEP, "^a", err_msg);
	call as_dump_ (err_msg);
	go to static_label;
     end ucs;

/* format: off */
%page; %include as_meter_numbers;
%page; %include as_data_;
%page; %include as_data_definitions_;
%page; %include as_wakeup_priorities;
%page; %include daemon_user_table;
%page; %include dialup_values;
%page; %include event_call_info;
%page; %include installation_parms;
%page; %include line_types;
%page; %include sc_stat_;
%page; %include sc_subsystem_info_;
%page; %include sys_log_constants;
%page; %include user_attributes;
%page; %include user_table_entry;
%page; %include user_table_header;
%page;
/* format: on */

/* BEGIN MESSAGE DOCUMENTATION

   Message:
   daemon_user_manager_: Command sent to daemon_user_manager_ before it was initialized

   S:	as (severity1)

   T:	In response to an operator command.

   M:	This message indicates an error in the Answering Service
   or an incorrect installation.  No daemon users can
   log in.

   A:	$inform


   Message:
   daemon_user_manager_: ERROR_MESSAGE. No MC ACS segment for message coordinator source SOURCE

   S:	as (severity1)

   T:	In response to an operator command.

   M:	The message coordinator access control segment
   >system_control_1>mc_acs>SOURCE.mcacs was not found.  It must be 
   created and given an ACL which permits the operator to logout the daemon.
   Therefore, the operator cannot logout the daemon.

   A:	$notify_sa


   Message:
   daemon_user_manager_: ERROR_MESSAGE.  Logout not permitted for message coordinator source SOURCE.

   S:	as (severity1)

   T:	In response to an operator command.

   M:	The message coordinator access control segment
   >system_control_1>mc_acs>SOURCE.mcacs does not permit the operator to 
   logout the daemon.  Therefore, the operator cannot logout the daemon.

   A:	$notify_sa


   Message:
   daemon_user_manager_: Daemon init error. NAME PROJ SOURCE REASON

   S:	as (severity2)

   T:	In response to an operator command.

   M:	The daemon user NAME PROJ on SOURCE was logged in
   correctly but his process could not be started.  The daemon will be
   logged out.

   A:	$inform


   Message:
   logout: Entry not found. NAME PROJ SOURCE

   S:	as (severity1)

   T:	In response to an operator logout command.

   M:	This is a response to an incorrect logout command.
   There is no entry in the daemon user table for NAME.PROJ.

   A:	Check the spelling for accuracy and try again.


   Message:
   daemon_user_manager_: Error: CONDITION during OP for NAME.PROJ SOURCE

   S:	as (severity2)

   T:	$run

   M:	An unexpected fault has occurred while the daemon user
   manager was performing an operation of type OP for the
   named daemon process.  An Answering Service dump was
   performed and the system attempts to continue, but
   the daemon process may be in an unusable state.

   A:	$contact


   Message:
   login: ERROR_MESSAGE. creating event channel for NAME PROJ SOURCE

   S:	as (severity2)

   T:	In response to an operator command.

   M:	This message indicates a system error in setting up a daemon
   user.  The daemon cannot be logged in.

   A:	$inform
   Try again.


   Message:
   login: ERROR_MESSAGE. creating proc for NAME PROJ SOURCE

   S:	as (severity2)

   T:	In response to an operator command.

   M:	A daemon process cannot be created.  This is probably due
   to a serious system bug.  The daemon is not logged in.

   A:	$contact


   Message:
   login: ERROR_MESSAGE. declaring ev_call_chn for NAME PROJ SOURCE

   S:	as (severity2)

   T:	In response to an operator command.

   M:	This message indicates a system error in setting up a daemon
   user.  The daemon cannot be logged in.

   A:	$inform


   Message:
   daemon_user_manager_: ERROR_MESSAGE. NAME.PROJ SOURCE terminated.

   S:	as (severity1)

   T:	$run

   M:	An error in a daemon process has caused it to terminate.
   A following message will indicate whether a new process has been
   automatically created.

   A:	If the daemon is logged out, reinitialize the daemon and continue.
   Otherwise, a new daemon process is created automatically and you
   can continue from there.


   Message:
   daemon_user_manager_: Fatal process error loop for NAME.PROJ SOURCE.
   .br
   Daemon will be logged out.

   S:	as (severity1)

   T:	$run

   M:	An error in a daemon process has caused it to terminate repeatedly
   within the last few minutes.  Detection of the loop causes the daemon
   to be logged out.

   A:	Try to login the daemon again.  If it still fails, notify your
   System Administrator of the problem.


   Message:
   daemon_user_manager_: Daemon will be logged out.

   S:	as (severity1)

   T:	$run

   M:	An error in a daemon process has caused it to terminate.
   The daemon suffered a fatal process error during initialization
   or it has set the option which causes it to be logged out when
   a fatal process error occurs.

   A:	Attempt to log in the daemon again and proceed.


   Message:
   daemon_user_manager_: New process created.

   S:	as (severity1)

   T:	$run

   M:	An error in a daemon process has caused it to terminate.
   A new process has been created.

   A:	A new daemon process is created automatically and you
   can continue from there.


   Message:
   daemon_user_manager_: Event entry called with null ev_msg_ptr

   S:	as (severity2)

   T:	$run

   M:	This indicates an error in the Answering Service.

   A:	$inform


   Message:
   daemon_user_manager_: Invalid signal from NAME PROJ SOURCE
   .br
   daemon_user_manager_: signal was "XXXXXXXX" YYY|ZZZZ

   S:	as (severity2)

   T:	$run

   M:	This message may result from an error in the Answering Service, an
   error in one of the daemon processes, or an attempt by an
   unauthorized user to signal the daemon user manager.  If the NAME,
   PROJ, and SOURCE cannot be determined, the process ID of the sender
   is shown instead.  The DUT (daemon user table) entry affected is
   located at YYY|ZZZZ in the Answering Service.

   The signal is ignored and the Answering Service attempts
   to continue.  If a daemon user is named on the first line of the
   message, this user will probably be unable to continue.

   A:	$inform
   If the user named
   in the message is a daemon user, try typing "logout NAME PROJ
   SOURCE", and if this succeeds, log the user in again if
   necessary.


   Message:
   login: NAME.PROJ already logged in on SOURCE

   S:	as (severity1)

   T:	In response to an operator command.

   M:	This is the response to the login command if the source
   specified by SOURCE is already in use.  Each daemon process must have
   a different source name.  The daemon user is not logged in.  Usually,
   this message is the result of attempting to perform an operation that
   has already been done.

   A:	Reissue the command with another source or continue.


   Message:
   daemon_user_manager_: NAME PROJ SOURCE terminated.  Daemon will be logged out.

   S:	as (severity2)

   T:	$run

   M:	NAME is the Person_id of the daemon, PROJ is the Project_id of the daemon, and SOURCE is the Message Coordinator
   source id of the daemon.  The daemon encountered a fatal process error and was logged out to prevent the system from getting
   into a loop.

   A:	$contact
   You can try logging the daemon in again, but if the process error is recurrent
   the problem must be corrected before the daemon will operate successfully.


   Message:
   login: no login NAME.PROJ SOURCE REASON

   S:	as (severity1)

   T:	In response to an operator command.

   M:	The operator issued a login NAME PROJ SOURCE command
   but the daemon user named cannot be logged in for the reason given.
   If REASON is badpers or bad_proj, the NAME or PROJ was
   probably misspelled.  If REASON is non_daem, the user NAME.PROJ
   is not authorized to be a daemon user.

   A:	Correct the command if misspelled and try to log in again.


   Message:
   daemon_user_manager_: You cannot new_proc to the requested authorization.
   .br
   Cannot new_proc to an authorization outside the daemon's allowed range.

   S:	as (severity1)

   T:	$run

   M:	A daemon executed an improper new_proc command, trying to change to
	an authorization greater than its maximum allowed authorization, or
	less than its minimum allowed authorization, as specified in the 
	Person Name Table (PNT), System Administrator's Table (SAT) and
	Project Master File (PMF).  The new_proc is performed at the
	original authorization of the process.

   A:	$notify_sa


   Message:
   daemon_user_manager_: process PERSON.PROJECT SOURCE ignored trm_ signal.

   S:	$as1

   T:	$run

   M:	The daemon process PERSON.PROJECT using message coordinator SOURCE
   had been sent a trm_ signal to cause process termination, but the process
   did not respond to the signal.  The answering service proceeds with the
   bump, new_proc, log out, etc operation.

   A:	$ignore


   Message:
   daemon_user_manager_: process PERSON.PROJECT SOURCE ignored wakeup EVENT_MSG from SENDER_PROCESS_ID

   S:	$as1

   T:	$run

   M:	The daemon process PERSON.PROJECT using message coordinator SOURCE
   had been sent a wakeup with EVENT_MSG by the process with process_id 
   SENDER_PROCESS_ID.  This event message is unknown and will be ignored.

   A:	$ignore


   Message:
   login: Cannot login NAME.PROJ SOURCE
   .br
   ERROR_MESSAGE

   S:	as (severity1)

   T:	$run

   M:	Illegal login arguments have been given when attempting to log in a daemon user.
   No action was taken.

   A:	Enter a corrected command.


   Message:
   daemon_user_manager_: premature STOPSTOP for NAME.PROJ SOURCE

   S:	as (severity0)

   T:	$run

   M:	$err

   A:	$ignore

   END MESSAGE DOCUMENTATION */

     end daemon_user_manager_;






		    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
