From:	MERC::"uunet!WKUVX1.BITNET!FILESERV-Mgr" 12-JUN-1992 15:41:10.75
To:	galaxy::gleeve
CC:	
Subj:	JOBLOG.02_OF_07

-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+
X`09`09  JLG_NO_EXH,
X`09`09  JLG_CANT_QUEUE,
X`09`09  JLG_CANT_WRITE,
X`09`09  JLG_INUSE,
X`09`09  JLG_NO_SPAWN,
X`09`09  JLG_CANT_CANCEL_IO,
X`09`09  JLG_CANT_DELETE,
X`09`09  JLG_CANT_DASSGN,
X`09`09  JLG_CANT_RESET,
X`09`09  JLG_CANT_DELETE_LOG,
X`09`09  LIB$M_CLI_CTRLY;
X
Xextern`09 char`09  *mktemp(),
X`09`09  *cat(),
X`09`09  *strmcpy(),
X`09`09  *str_post_trim(),
X`09`09  *str_pref_trim();
X
Xextern`09 ULONG`09  LIB$ASN_WTH_MBX(),
X`09`09  LIB$DISABLE_CTRL(),
X`09`09  LIB$ENABLE_CTRL(),
X`09`09  LIB$FIND_FILE(),
X`09`09  LIB$FIND_FILE_END(),
X`09`09  LIB$GET_INPUT(),
X`09`09  LIB$GETJPI(),
X`09`09  LIB$SPAWN(),
X`09`09  LIB$STOP(),
X`09`09  SYS$ASCTIM(),
X`09`09  SYS$ASCTOID(),
X`09`09  SYS$ASSIGN(),
X`09`09  SYS$CANCEL(),
X`09`09  SYS$CANEXH(),
X`09`09  SYS$CLOSE(),
X`09`09  SYS$CONNECT(),
X`09`09  SYS$DASSGN(),
X`09`09  SYS$DCLEXH(),
X`09`09  SYS$EXIT(),
X`09`09  SYS$EXPREG(),
X`09`09  SYS$FAO(),
X`09`09  SYS$FINISH_RDB(),
X`09`09  SYS$FIND_HELD(),
X`09`09  SYS$GETDVI(),
X`09`09  SYS$GETUAI(),
X`09`09  SYS$QIO(),
X`09`09  SYS$QIOW(),
X`09`09  SYS$OPEN(),
X`09`09  SYS$PUT(),
X`09`09  SYS$READ(),
X`09`09  SYS$SETPRV(),
X`09`09  SYS$TRNLNM(),
X`09`09  SYS$WRITE();
X
Xextern`09 int`09  delete();
X
Xextern`09 void`09  strlu();
X
X/***************************************************************************
V***/
X/*
V                                                                         `20
V  */
X/*     S T A T I C   D E F I N I T I O N S   &   D E C L A R A T I O N S
V      */
X/*
V                                                                         `20
V  */
X/***************************************************************************
V***/
X
Xstatic`09 ULONG`09  write_tt(short,char *,ULONG),
X`09`09  get_file(char *,char *,struct FAB *,struct RAB *,
X`09`09`09   struct XABPRO *,ARG_DEF *,FLAG_DEF *),
X`09`09  copy_file(char *,char *,USHORT),
X`09`09  print_log(char *,USHORT,UCHAR),
X`09`09  retrieve_log(char *,ARG_DEF *,USHORT *),
X`09`09  delete_mlog(char *,USHORT *),
X`09`09  class_retrieve(char *,char *),
X`09`09  user_retrieve(char *,char *),
X`09`09  ctrlc_trap(void),
X`09`09  ctrly_trap(USHORT),
X`09`09  write_ft(USHORT,FT_BUF *),
X`09`09  save_log(char *,USHORT),
X`09`09  my_gets(USHORT,char *,char *,USHORT *,USHORT),
X`09`09  mail_log(char *,char *,USHORT,UCHAR),
X`09`09  tt_r_efn,
X`09`09  ft_efn,
X`09`09  wait_efn;
X
Xstatic`09 long`09  bintim`5B2`5D = `7B-5*10*100*100,-1`7D;
X
Xstatic`09 USHORT`09  ft_chan,`09`09/* channel to FT device`09`09      */
X`09`09  tt_chan,`09`09/* channel to TTY`09`09      */
X`09`09  disp_failed = FALSE,`09/* set if disposition of log fails    */
X`09`09  clean_exit = FALSE,`09/* set if good exit of subprocess     */
X`09`09  term_mask`5B8`5D = `7B0,0,0,0,0,0,0,0`7D,
X`09`09  valid_recip(char *),
X`09`09  delete_log(char *);
X
Xstatic`09 void`09  get_args(ARG_DEF *),
X`09`09  get_channels(USHORT *,USHORT *,ADDR_RAN *),
X`09`09  ft_ast(void),
X`09`09  log_session(USHORT,USHORT),
X`09`09  write_log(char *,USHORT,struct RAB *,FLAG_DEF *),
X`09`09  ask_disposition(char *,char *,FLAG_DEF *,ARG_DEF *),
X`09`09  welcome(ARG_DEF *),
X`09`09  ctrlc_ast(void),
X`09`09  ctrly_ast(void),
X`09`09  skim(char *),
X`09`09  squeeze_str(register char *),
X`09`09  quit(void),
X`09`09  quit2(void),
X`09`09  subprocess_exit(void),
X`09`09  spawn(ULONG *),
X`09`09  parse_filename(char *,char *,char *,USHORT *),
X`09`09  warn(char *,UINT,int,int,int),
X`09`09  dev_chg_ast(void),
X`09`09  get_logicals(char *,char *),
X`09`09  my_puts(char *),
X`09`09  joblog_check(void),
X`09`09  xon_ast(void),
X`09`09  xoff_ast(void),
X`09`09  bell_ast(void),
X`09`09  kill_log(void);
X                 `20
Xstatic`09 char`09  ftname`5BFT_NAME_MAX+1`5D,/* name of FT device`09`09
V      */
X`09`09  stamp_buf`5BTIME_MAX+3`5D, /* for holding time stamp string     */
X`09`09  logfile`5BNAM$C_MAXRSS`5D, /* log file name`09`09      */
X`09`09  log_dir`5BNAM$C_MAXRSS`5D, /* where log files are created`09      */
X`09`09  stage_dir`5BNAM$C_MAXRSS`5D, /* where mailed log files live     */
X`09`09  *get_stamp(char *);
X
Xstatic`09 IOSB_DEF tt_read_iosb,`09`09/* read I/O status block for TTY
V      */
X`09`09  tt_write_iosb;`09/* write I/O status block for TTY     */
X
Xstatic`09 FT_BUF`09  *ft_buf,`09`09/* FT device I/O buffer`09`09      */
X`09`09  *tt_buf,`09`09/* TTY I/O buffer`09`09      */
X`09`09  *cr_buf;`09`09/* Carriage-return I/O buffer`09      */
X
Xstatic`09 SENS_DEF tty_save_char;`09/* for saving TTY characteristics     */
X
Xstatic`09 TERM_DEF term_block = `7B32,0,&term_mask`7D;
X
Xstatic`09 struct`09  FAB`09  log_fab;
X
Xstatic`09 struct`09  RAB`09  log_rab;
X
Xstatic`09 struct`09  XABPRO  log_xabpro;
X
Xstatic`09 FLAG_DEF flags;`09`09/* global flags`09`09`09      */
X
Xstatic`09 ARG_DEF  args;`09`09`09/* run-time arguments`09`09      */
X
Xstatic`09 union`09  prvdef  _align(longword) privs;
Xstatic`09 union`09  prvdef  _align(longword) old_privs;
X
Xstatic $DESCRIPTOR(tt_d,"TT:");
Xstatic $DESCRIPTOR(ft_d,ftname);
Xstatic $DESCRIPTOR(mess_d,"");
X`0C
X/***************************************************************************
V***/
X/*
V                                                                         `20
V  */
X/*                        M A I N   P R O C E S S I N G
V                       */
X/*
V                                                                         `20
V  */
X/***************************************************************************
V***/
X
Xmain()
X
X`7B`09/*** main ***/                                      `20
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
X`09 ULONG`09  status,`09`09/* return code status holder`09      */
X`09`09  subproc_pid;`09`09/* PID of spawned subprocess`09      */
X `09 EXH_DEF  exh_blk = `7B0L,quit,0,0,0,0,&status`7D;
Xstatic`09 ADDR_RAN io_buffers;
X
X#ifndef PHOTO_MODE
X
X   get_args(&args); `09`09`09/* get run-time arguments`09      */
X
X   /* get logicals for the log and staging directories */
X
X   get_logicals(log_dir,stage_dir);
X
X#endif
X
X   if(args.retrieve)`09`09`09/* someone retrieving a logfile?      */
X      retrieve_log(stage_dir,&args,&tt_chan);
X   else if(args.delete)
X      delete_mlog(stage_dir,&tt_chan);`09/* deleting a mailed logfile?`09
V      */
X   else if(args.skim)
X      skim(stage_dir);`09`09`09/* skim old JOBLOG files`09      */
X   else
X   `7B
X      joblog_check();`09`09`09/* don't let user run JOBLOG twice    */
X
X      status = LIB$GET_EF(&tt_r_efn);
X
X      if(!(status & SS$_NORMAL))
X`09 LIB$STOP(status);
X
X      status = LIB$GET_EF(&wait_efn);
X
X      if(!(status & SS$_NORMAL))
X`09 LIB$STOP(status);
X
X      status = LIB$GET_EF(&ft_efn);
X
X      if(!(status & SS$_NORMAL))
X`09 LIB$STOP(status);
X
X      /* someone is actually logging a session here */
X
X      flags.verify = TRUE;`09`09/* assume we are verified to start    */
X      flags.time_stamp = args.time_stamp;
X
X      /* open the log file */
X
X      status = get_file(logfile,log_dir,&log_fab,&log_rab,&log_xabpro,&args,
X`09`09`09&flags);
X
X      if(status != RMS$_NORMAL)
X`09 LIB$STOP(JLG_NO_LOGFILE);`09/* major problems here`09`09      */
X
X      /* set up channels to everything we will need */
X
X      get_channels(&tt_chan,&ft_chan,&io_buffers);
X
X      /* set the pointers to the buffers that we will use */
X
X      ft_buf = (FT_BUF *) io_buffers.start;
X      tt_buf = (FT_BUF *) (io_buffers.start + PAGE_SIZE);
X      cr_buf = (FT_BUF *) (io_buffers.start + (PAGE_SIZE * 2));
X
X      /* write welcome message */
X
X      welcome(&args);
X
X      /* declare an exit handler */
X
X      status = SYS$DCLEXH(&exh_blk);
X
X      if(!(status & SS$_NORMAL))
X      `7B
X`09 kill_log();
X`09 LIB$STOP(JLG_NO_EXH);
X      `7D
X
X      /* spawn a subprocess that we can use */
X
X      spawn(&subproc_pid);
X
X      flags.logging = TRUE;  `09`09/* start out by logging stuff`09      */
X      flags.command = FALSE;
X
X      /* log the session */
X
X      log_session(ft_chan,tt_chan);
X   `7D
X
X`7D`09/*** main ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09get_args
X
X  Purpose:`09Get run-time arguments and store in structure.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09args`09`09`09command-line argument flags
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09none
X
X  Return Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09none
X
X****************************************************************************
V****
X****************************************************************************
V***/
X
Xstatic void get_args(ARG_DEF *args)
X
X`7B`09/*** get_args ***/
X`09     `09`09`09`09/********   LOCAL  VARIABLES   ********/
X`09 ULONG`09  status;`09`09/* return code status holder`09      */
X`09 USHORT`09  length;`09`09/* length of command line`09      */
Xstatic`09 char`09  command`5BCOMMAND_MAX+1`5D; /* for building a command to
V parse  */
Xstatic $DESCRIPTOR(cmdline_d,command);`09/* for parsing command line`09
V      */
Xstatic $DESCRIPTOR(delete_d,"DELETE");
Xstatic $DESCRIPTOR(expert_d,"EXPERT");
Xstatic $DESCRIPTOR(mail_d,"MAIL");
Xstatic $DESCRIPTOR(save_d,"SAVE");
Xstatic $DESCRIPTOR(print_d,"PRINT");
Xstatic $DESCRIPTOR(retrieve_d,"RETRIEVE");
Xstatic $DESCRIPTOR(skim_d,"SKIM");
Xstatic $DESCRIPTOR(time_stamp_d,"TIME_STAMP");
X
X
X   /* first get the command line */
X
X   status = LIB$GET_FOREIGN(&cmdline_d,0,&length,0);
X
X   if(!(status & SS$_NORMAL))
X      LIB$STOP(status);
X
X   /* insert the verb we need */
X
X   command`5Blength`5D = '\0';
X   strins(command,"JOBLOG",0);
X   cmdline_d.dsc$w_length = (USHORT) strlen(command);
X
X   /* now parse it so we can check for qualifiers */
X
X   status = CLI$DCL_PARSE(&cmdline_d,&joblog_cld,&LIB$GET_INPUT);
X
X   if(status != CLI$_NORMAL)
X      LIB$STOP(status);
X
X   if(CLI$PRESENT(&time_stamp_d) == CLI$_PRESENT)
X      args->time_stamp = TRUE;
X   else
X      args->time_stamp = FALSE;
X
X   if(CLI$PRESENT(&expert_d) == CLI$_PRESENT)
X      args->expert = TRUE;
X   else
X      args->expert = FALSE;
X
X   if(CLI$PRESENT(&print_d) == CLI$_PRESENT)
X      args->print = TRUE;
X   else
X      args->print = FALSE;
X
X   if(CLI$PRESENT(&retrieve_d) == CLI$_PRESENT)
X      args->retrieve = TRUE;
X   else
X      args->retrieve = FALSE;
X`20
X   if(CLI$PRESENT(&save_d) == CLI$_PRESENT)
X      args->save = TRUE;
X   else
X      args->save = FALSE;
X`20
X   if(CLI$PRESENT(&mail_d) == CLI$_PRESENT)
X      args->mail = TRUE;
X   else
X      args->mail = FALSE;
X`20
X   if(CLI$PRESENT(&skim_d) == CLI$_PRESENT)
X      args->skim = TRUE;
X   else
X      args->skim = FALSE;
X
X   if(CLI$PRESENT(&delete_d) == CLI$_PRESENT)
X      args->delete = TRUE;
X   else
X      args->delete = FALSE;
X
X   return;
X
X`7D`09/*** get_args ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09quit
X
X  Purpose:`09Exit handler used to clean up a few things.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09none
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09tt_chan`09`09`09`09`09X
X`09ft_chan`09`09`09`09`09X
X`09tty_save_char`09`09`09`09X
X`09log_fab`09`09`09`09`09X
X`09log_xabpro`09`09`09  X
X`09logfile`09`09`09`09`09X
X`09flags`09`09`09`09`09X
X`09stage_dir`09`09`09`09X
X`09args`09`09`09`09`09X
X`09mess_d`09`09`09`09  X`09X
X`09clean_exit`09`09   X
X`09privs`09`09`09`09  X`09X
X`09JLG_CANT_CANCEL_IO`09`09`09X
X`09JLG_NO_EXH`09`09`09`09X
X`09JLG_CANT_DASSGN`09`09`09`09X
X`09JLG_CANT_RESET`09`09`09`09X
X
X  Return Codes:
X
X`09Code`09`09`09Reason
X`09---- `09`09`09------
X`09none
X
X  Termination Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09status
X
X****************************************************************************
V****
X****************************************************************************
V***/
X
Xstatic void quit(void)
X
X`7B`09/*** quit ***/
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
Xstatic`09 ULONG`09  status,`09`09/* return code status holder`09      */
X`09`09  length;`09`09/* length of device char. block`09      */
Xstatic`09 EXH_DEF  exh2_blk = `7B0L,quit2,0,0,0,0,&status`7D;
X
X
X#ifndef PHOTO_MODE
X
X   privs.prv$v_sysprv = ON;`09`09/* need SYSPRV to close the log file  */
X
X   status = SYS$SETPRV(ON,&privs,FALSE,NULL);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      LIB$SIGNAL(status);
X      return;
X   `7D
X
X   /* set the protection to override any default the user might've set */
X
X   log_xabpro.xab$w_pro = ((XAB$M_NOREAD `7C XAB$M_NOWRITE `7C XAB$M_NOEXE `
V7C
X`09`09`09    XAB$M_NODEL) << XAB$V_GRP) `7C ((XAB$M_NOREAD `7C
X`09`09`09    XAB$M_NOWRITE `7C XAB$M_NOEXE `7C XAB$M_NODEL)
X`09`09`09    << XAB$V_WLD);
X
X#endif
X
X   status = SYS$CLOSE(&log_fab);`09/* close the log file`09`09      */
X
X   if(status != RMS$_NORMAL)
X   `7B
X      delete_log(logfile);
X      LIB$STOP(status);
X   `7D
X
X#ifndef PHOTO_MODE
X
X   /* turn SYSPRV off */
X
X   status = SYS$SETPRV(OFF,&privs,FALSE,NULL);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      LIB$SIGNAL(status);
X      return;
X   `7D
X
X   privs.prv$v_sysprv = OFF;
X
X#endif
X
X   if(clean_exit == FALSE)
X   `7B
X      /* oops, we had problems here; someone must've killed the process
X       * because we got here without detecting hangup on the FT device;
X       * this normally means that there is no TTY left to talk to so
X       * we just kill the logfile and get out
X       */
X
X      delete_log(logfile);
X      return;
X   `7D
X
X#ifndef PHOTO_MODE
X
X   /* declare ANOTHER exit handler to delete the log file in case the
X    * user decides to do something drastic like a disconnect between now
X    * and when ask_disposition() is called
X    */
X
X   status = SYS$DCLEXH(&exh2_blk);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      delete_log(logfile);
X      LIB$STOP(JLG_NO_EXH);
X   `7D
X
X#endif
X
X   /* clean up some things; start by cancelling I/O on all channels */
X
X   status = SYS$CANCEL(tt_chan);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      mess_d.dsc$a_pointer = "TTY";
X      mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer);
X      LIB$SIGNAL(JLG_CANT_CANCEL_IO,1L,&mess_d);
X   `7D
X
X   status = PTD$CANCEL(ft_chan);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      mess_d.dsc$a_pointer = "FT";
X      mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer);
X      LIB$SIGNAL(JLG_CANT_CANCEL_IO,1L,&mess_d);
X   `7D
X
X   /* now delete and deassign some stuff */
X
X   status = PTD$DELETE(ft_chan);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      mess_d.dsc$a_pointer = "FT";
X      mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer);
X      LIB$SIGNAL(JLG_CANT_DASSGN,1L,&mess_d);
X   `7D
X
X   /* set the terminal mode back to the way it was */
X   `20
X   length = (ULONG) sizeof(tty_save_char);
X
X   status = SYS$QIOW(0,tt_chan,IO$_SETMODE,0,0,0,&tty_save_char,length,0,0,0
V,
X`09`09     0);
X
X   if(!(status & SS$_NORMAL))
X      LIB$SIGNAL(JLG_CANT_RESET);
X
X#ifndef PHOTO_MODE
X
X   /* ask user what should happen */
X
X   ask_disposition(logfile,stage_dir,&flags,&args);
X
X   /* kill the secondary exit handler so that it doesn't kick in when we
X    * exit
X    */
X
X   status = SYS$CANEXH(&exh2_blk);
X
X   if(!(status & SS$_NORMAL))
X      LIB$SIGNAL(JLG_NO_EXH);
X
X#endif
X
X   my_puts("\nExiting JOBLOG.  Remember YOU ARE STILL LOGGED IN!!!\7\7\7\n")
V;
X   exit();
X
X`7D`09/*** quit ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09get_channels
X
X  Purpose:`09Assign channels to both the TTY and the FT device, SETMODE the
X`09`09TTY.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09tt_chan`09`09`09channel to TTY
X`09ft_chan`09`09`09channel to FT device
X`09io_buffers`09`09I/O buffers used by FT device
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09tt_d`09`09`09`09  X`09X
X`09ft_d`09`09`09`09  X
X`09tty_save_char`09`09`09  X
X`09ftname`09`09`09`09  X`09X`09
X
X  Return Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09none
X
X  Termination Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09status`09`09`09return code from various system calls
X
X****************************************************************************
V****
X****************************************************************************
V***/
X
Xstatic void get_channels(USHORT *tt_chan,USHORT *ft_chan,ADDR_RAN *io_buffer
Vs)
X                                          `20
X`7B`09/*** get_channels ***/
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
X`09 ULONG`09  status,`09`09/* return code status holder`09      */
X`09`09  length;`09`09/* length of tty_char block`09      */
X`09 IOSB_DEF iosb;`09`09`09/* I/O status block`09`09      */
X`09 SENS_DEF tty_char,`09`09/* TTY characteristics to set`09      */
X`09`09  ft_char;`09`09/* FT characteristics to set`09      */
Xstatic`09 ULONG`09  ft_num;`09`09/* device # of FT device`09      */
Xstatic`09 USHORT`09  ft_name_len;`09`09/* length of FT device name`09      *
V/
Xstatic`09 ITM_LST  items`5B`5D = `7B`09`09/* for getting FT characteristics
V     */
X`7Bsizeof(ftname),DVI$_DEVNAM,ftname,&ft_name_len`7D,
X`7B0,0,0L,0L`7D`7D;
X
X
X   /* get a channel for the user's TTY */
X
X   status = SYS$ASSIGN(&tt_d,tt_chan,0,0);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* now set the mode for the terminal */
X
X   length = sizeof(tty_char);`09`09/* get length of tty char. block      */
X
X   status = SYS$QIOW(0,*tt_chan,IO$_SENSEMODE,&iosb,0,0,&tty_char,length,0,0
V,
X`09`09    0,0);
X          `20
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* copy the current TTY mode so it can be restored later */
X
X   tty_save_char = tty_char;
X   ft_char = tty_char;`09`09`09/* for the FT device`09`09      */
X
X   /* now set up the characteristics we need to run */
X
X   tty_char.characts `7C= TT$M_NOECHO;
X
X   /* set the TTY to HOSTSYNC and TTSYNC; if we don't, vt220's will hang
X    * because of flow control problems
X    */
X
X   tty_char.characts `7C= TT$M_TTSYNC;
X   tty_char.characts `7C= TT$M_HOSTSYNC;
X   tty_char.ext_char `7C= TT2$M_PASTHRU;
X               `20
X   status = SYS$QIO(0,*tt_chan,IO$_SETMODE,&iosb,0,0,&tty_char,length,0,0,
X`09`09    0,0);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* expand the P0 region to make some I/O buffers */
X
X   status = SYS$EXPREG(NUM_IO_BUFFERS,io_buffers,0,0);
X
X   if(!(status & SS$_NORMAL))
X      LIB$STOP(status);
X
X   /* create an FT device */
X
X   status = PTD$CREATE(ft_chan,0,&ft_char,sizeof(ft_char),0,0,0,io_buffers);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* set up some AST's for good measure */
X
X   status = PTD$SET_EVENT_NOTIFICATION(*ft_chan,&xon_ast,0,0,PTD$C_SEND_XON)
V;
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   status = PTD$SET_EVENT_NOTIFICATION(*ft_chan,&xoff_ast,0,0,PTD$C_SEND_XOF
VF);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   status = PTD$SET_EVENT_NOTIFICATION(*ft_chan,&bell_ast,0,0,PTD$C_SEND_BEL
VL);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   status = PTD$SET_EVENT_NOTIFICATION(*ft_chan,&dev_chg_ast,0,0,
X`09`09`09`09       PTD$C_CHAR_CHANGED);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* get the device number of the FT device so we know what SYS$INPUT
X    * and SYS$OUTPUT are called when we call LIB$SPAWN()
X    */
X
X   status = SYS$GETDVI(0,*ft_chan,0,&items,&iosb,0,0,0);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* get rid of the leading underscore in the FT device name */
X
X   ftname`5Bft_name_len`5D = '\0';
X   strcpy(ftname,&ftname`5B1`5D);
X   ft_d.dsc$w_length = ft_name_len - 1;
X
X   return;
X
X`7D`09/*** get_channels ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09spawn
X
X  Purpose:`09Spawn a subprocess to talk to the FT device.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09pid`09`09`09returns PID of subprocess
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09privs`09`09`09`09  X`09X
X`09old_privs`09`09`09  X`09X
X`09ft_d`09`09`09`09`09X
X
X  Return Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09none
X
X  Termination Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09status`09`09`09return code from various system calls
X
X****************************************************************************
V****
X****************************************************************************
V***/
X               `20
Xstatic void spawn(ULONG *pid)
X
X`7B`09/*** spawn ***/
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
X`09 ULONG`09  status,`09`09/* return code status holder`09      */
X`09`09  current_pid,`09`09/* PID of current process`09      */
X`09`09  flags;`09`09/* flags for SPAWNing subprocess      */
X`09 long`09  item_code;`09`09/* for LIB$GETJPI()`09`09      */
X`09 short`09  length;`09`09/* length of process name`09      */
X`09 char`09  procname`5BPNAME_MAX+1`5D,/* current process name array`09
V      */
X`09`09  newname`5BPNAME_MAX+1`5D;`09/* process name for JOBLOG subprocess */
X$DESCRIPTOR(procname_d,procname);`09/* for getting process name`09      */
X$DESCRIPTOR(newname_d,newname);`09`09/* for setting process name`09      */
X$DESCRIPTOR(prompt_d,"Joblog> ");`09/* DCL prompt when in JOBLOG`09      */
X$DESCRIPTOR(format_d,"JOBLOG_!XL");
X
X
X   current_pid = getpid();`09`09/* get PID for current process`09      */
X
X   /* make the process name that we are going to use */
X
X   status = SYS$FAO(&format_d,&length,&newname_d,current_pid & 0xFFFF);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   newname_d.dsc$w_length = length;
X   newname`5Blength`5D = '\0';
X  `20
X   /* put the current process back to it's default privileges so that we can
X    * give them to the subprocess; don't worry, we'll put the parent process
X    * back the way it was AFTER we create the subprocess; first we turn off
X    * all privileges
X    */
X
X   memset((void *) &privs,0xFF,sizeof(privs));
X
X   status = SYS$SETPRV(OFF,&privs,FALSE,&old_privs);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* get the default privileges so that we can propagate them to
X    * the subprocess
X    */
X
X   item_code = JPI$_PROCPRIV;
X   status = LIB$GETJPI(&item_code,0,0,&privs);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* now enable the normal privs */
X
X   status = SYS$SETPRV(ON,&privs,FALSE,NULL);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* FINALLY!  we spawn a subprocess to talk to the FT device and set the p
Vrivs
X    * for it
X    */
X
X   flags = CLI$M_NOWAIT;
X
X   status = LIB$SPAWN(0,&ft_d,&ft_d,&flags,&newname_d,pid,0,0,
X`09`09      &subprocess_exit,0,&prompt_d,0);
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   /* set the privileges of the parent process back to what they are suppose
Vd
X    * to be
X    */
X
X   status = SYS$SETPRV(ON,&old_privs,FALSE,NULL);    `20
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X   `7D
X
X   return;
X
X`7D`09/*** spawn ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09ft_ast
X
X  Purpose:`09AST routine for FT device.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09none
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09tt_chan`09`09`09`09`09X
X`09ft_chan`09`09`09`09`09X
X`09ft_efn`09`09`09`09`09X
X`09ft_buf`09`09`09   X`09`09X
X`09log_rab`09`09`09`09`09X
X`09flags`09`09`09`09`09X
X`09mess_d`09`09`09`09  X`09X
X
X  Return Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09none
X
X  Termination Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09status`09`09`09problems queuing read on FT device
X`09JLG_CANT_QUEUE
X
X****************************************************************************
V****
X****************************************************************************
V***/
X
Xstatic void ft_ast(void)
X
X`7B`09/*** ft_ast ***/
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
Xstatic`09 ULONG`09  status;`09`09/* return code status holder`09      */
X
X
X   /* check that the read on the FT completed ok */
X
X   if(!(ft_buf->status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(ft_buf->status);
X   `7D
X
X   /* write what was read from the FT device to the TTY */
X
X   write_tt(tt_chan,ft_buf->data,(ULONG) ft_buf->count);
X
X   if(flags.logging)
X      write_log(ft_buf->data,ft_buf->count,&log_rab,&flags);
X
X   status = PTD$READ(ft_efn,ft_chan,&ft_ast,0,&(ft_buf->status),FT_DATA_MAX)
V;
X
X   if(!(status & SS$_NORMAL))
X   `7B
X      kill_log();
X      LIB$STOP(status);
X      mess_d.dsc$a_pointer = "read on FT device (in ast)";
X      mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer);
X      LIB$STOP(JLG_CANT_QUEUE,1L,&mess_d);
X   `7D
X
X   return;
X
X`7D`09/*** ft_ast ***/
X`0C
X/***************************************************************************
V****
X****************************************************************************
V****
X
X  Function:`09dev_chg_ast
X
X  Purpose:`09Called when the FT device characteristics are changed.  Here
X`09`09the TT characteristics are changed to match.
X
X  Formal Parameters:
X
X`09Name`09`09`09Description
X`09----`09`09`09-----------
X`09none
X
X  Global variables:
X
X`09Name`09`09`09Examine/Modify/Use/Read/Write
X`09----`09`09`09-----------------------------
X`09ft_chan`09`09`09`09`09X
X`09tt_chan`09`09`09`09`09X
X
X  Return Codes:
X
X`09Code`09 `09`09Reason
X`09----`09`09`09------
X`09none
X
X  Termination Codes:
X
X`09Code`09`09`09Reason
X`09----`09`09`09------
X`09status`09`09`09return code from SYS$QIO
X
X****************************************************************************
V****
X****************************************************************************
V***/
X
Xstatic void dev_chg_ast(void)
X
X`7B`09/*** dev_chg_ast ***/
X`09`09`09`09`09/********   LOCAL  VARIABLES   ********/
Xstatic`09 ULONG`09  status;`09`09/* return code status holder`09      */
Xstatic`09 USHORT`09  speed,`09`09/* speed of device`09`09      */
X`09`09  fill;`09`09`09/* fill count`09`09`09      */
Xstatic`09 SENS_DEF dev_char;`09`09/* for getting FT dev characteristics */
Xstatic`09 IO2_DEF  sense_iosb,
X`09`09  set_iosb;
X
X
X   /* get the FT device's characteristics */
X
X   status = SYS$QIO(0,ft_chan,IO$_SENSEMODE,&sense_iosb,0,0,&dev_char,
X`09`09    sizeof(dev_char),0,0,0,0);
X
X   if(!(status & SS$_NORMAL))
X      LIB$STOP(status);
X
X   dev_char.characts `7C= TT$M_NOECHO;`09/* make sure we're still NOECHO....
V   */
X   dev_char.ext_char `7C= TT2$M_PASTHRU;`09/* ....and PASTHRU....`09`09
V      */
X   speed = sense_iosb.t_speed `7C (sense_iosb.r_speed << 8);
+-+-+-+-+-+-+-+-  END  OF PART 2 +-+-+-+-+-+-+-+-
