-+-+-+-+-+-+-+-+ START OF PART 2 -+-+-+-+-+-+-+-+ Xstatic $DESCRIPTOR(cmdline_d,command);`09/* for parsing command line`09 V */ Xstatic $DESCRIPTOR(buf_d,buffer);`09/* buffer for getting values`09 */ 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`09py_chan`09`09`09`09`09X X`09py_mbx_chan`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`09filename`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 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; Xstatic`09 union`09 prvdef _align(longword) privs; 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(logfile); X LIB$STOP(status); X `7D 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 PY 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(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 kill_log(); X LIB$STOP(JLG_NO_EXH); X `7D X X privs.prv$v_cmkrnl = ON; 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#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 = SYS$CANCEL(py_chan); X X if(!(status & SS$_NORMAL)) X `7B X mess_d.dsc$a_pointer = "PTY"; 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 = SYS$CANCEL(py_mbx_chan); X X if(!(status & SS$_NORMAL)) X `7B X mess_d.dsc$a_pointer = "PTY mailbox"; 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 = SYS$DASSGN(py_chan); X X if(!(status & SS$_NORMAL)) X `7B X mess_d.dsc$a_pointer = "PTY"; 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 status = SYS$DASSGN(py_mbx_chan); X X if(!(status & SS$_NORMAL)) X `7B X mess_d.dsc$a_pointer = "PTY mailbox"; 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 /* turn off SYSPRV and CMKRNL before exiting; since we specified them X * as temporary, they'll be disabled when the image exits anyway but X * let's be conscientious X */ X X status = SYS$SETPRV(OFF,&privs,FALSE,NULL); 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 PTY, SETMODE the TTY X`09`09and SETCHAR the PTY. X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09tt_chan`09`09`09channel to TTY X`09py_chan`09`09`09channel to PTY control device X`09py_mbx_chan`09`09channel to PTY control device mailbox X`09`09`09`09used to detect hangup X X Global variables: X X`09Name`09`09`09Examine/Modify/Use/Read/Write X`09----`09`09`09----------------------------- X`09py_d`09`09`09`09`09X X`09tt_d`09`09`09`09`09X X`09tw_d`09`09`09`09 X`09X X`09tty_save_char`09`09`09 X 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 *py_chan,USHORT *py_mbx_chan V) 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 twa_char;`09`09/* TWA characteristics to set`09 */ Xstatic`09 ULONG`09 py_num;`09`09/* device # of PTY control device */ Xstatic`09 USHORT`09 dvi_length;`09`09/* length of PY characteristics`09 V */ Xstatic`09 ITM_LST items`5B`5D = `7B`09`09/* for getting PTY characteristics V */ X`7B4,DVI$_DEVDEPEND,&py_num,&dvi_length`7D, X`7B0,0,0L,0L`7D`7D; Xstatic $DESCRIPTOR(format_d,"TWA!ZL:");`09/* for making device number`09 V */ 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 twa_char = tty_char;`09`09`09/* for the TW device`09`09 */ X X /* now set up the characteristics we need to run */ X X/* X tty_char.tt$v_echo = FALSE; 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/* X tty_char.characts `7C= TT$M_TTSYNC `7C TT$M_HOSTSYNC; X tty_char.tt$v_sync = TRUE; X tty_char.tt$v_hostsync = TRUE; X tty_char.tt$v_echo = TRUE; 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 /* now get a channel for the PTY */ X X status = LIB$ASN_WTH_MBX(&py_d,0,0,py_chan,py_mbx_chan); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(status); X `7D X X /* get the device-dependent characteristics */ X X status = SYS$GETDVI(0,*py_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 the device number of the PTY and use it to make the name of the X * associated control device so we can assign a channel to it X */ X X status = SYS$FAO(&format_d,&length,&tw_d,py_num); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(status); X `7D X X tw_d.dsc$a_pointer`5Blength`5D = '\0';`09/* make it a string`09`09 * V/ X tw_d.dsc$w_length = length; X X status = SYS$ASSIGN(&tw_d,&tw_chan,0,0); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(status); X `7D X X /* set the characteristics of the TWA to be the same as the user's X * real terminal X */ X X status = SYS$QIO(0,tw_chan,IO$_SETCHAR,0,0,0,&twa_char,length,0,0,0,0); X X if(status != SS$_NORMAL `7C`7C status == SS$_NOPRIV) X `7B X#ifdef PHOTO_MODE X LIB$SIGNAL(JLG_CANT_PROPAGATE); X#else X kill_log(); X LIB$STOP(status); X#endif X `7D X X /* throw away the channel to the TWA because keeping it messes stuff up * V/ X X status = SYS$DASSGN(tw_chan); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(status); X `7D 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 PTY. X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09twname`09`09`09name of TW device X`09pid`09`09`09returns PID of subprocess X`09oldprivs`09`09default privileges of user 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 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(char *twname,ULONG *pid,union prvdef *oldprivs) 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 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(pty_d,"");`09`09`09/* PTY name and number`09`09 */ X$DESCRIPTOR(prompt_d,"Joblog> ");`09/* DCL prompt when in JOBLOG`09 */ X$DESCRIPTOR(format_d,"JOBLOG_!XL"); Xstatic`09 union`09 prvdef _align(longword) privs; 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 pty_d.dsc$w_length = strlen(twname); X pty_d.dsc$a_pointer = twname; 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,oldprivs); 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 status = LIB$GETJPI(&JPI$_PROCPRIV,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 PTY and set the privs X * for it X */ X X flags = CLI$M_NOWAIT; X X status = LIB$SPAWN(0,&pty_d,&pty_d,&flags,&newname_d,pid,0,0,0,0, X`09`09 &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,oldprivs,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:`09py_ast X X Purpose:`09AST routine for PTY control 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`09py_buf`09`09`09`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`09py_read_iosb`09`09 X`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`09problems queuing read on PTY X`09JLG_CANT_QUEUE X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic void py_ast(void) X X`7B`09/*** py_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 length;`09`09/* length read from PTY`09`09 */ X X X length = py_read_iosb.count + py_read_iosb.term_count; X X if(!(py_read_iosb.status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(py_read_iosb.status); X mess_d.dsc$a_pointer = "iosb.status bad in py_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 /* write what was read from the PY device to the TTY */ X X write_tt(tt_chan,py_buf,(ULONG) length); X X if(flags.logging) X write_log(py_buf,length,&log_rab,&flags); X X status = SYS$QIO(0,py_chan,IO$_READVBLK,&py_read_iosb,&py_ast,0,py_buf, X`09`09 PY_BUF_MAX,0,0,0,0); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X LIB$STOP(status); X mess_d.dsc$a_pointer = "read on PY 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/*** py_ast ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09dev_chg_ast X X Purpose:`09Called when the TW 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`09py_line_iosb`09`09`09`09X X`09py_chan`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`09JLG_CANT_QUEUE 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 */ X`09`09 length;`09`09/* length of characteristics block */ Xstatic`09 SENS_DEF dev_char;`09`09/* for getting PY dev characteristics */ X X X /* here we would get the device characteristics of the TW device; the X * problem is that when a channel is assigned to the TW device after the X * processed is spawned, things get hosed up pretty quickly; if we WERE X * going to change the TT characteristics to match the TW, would need X * to make sure that the TT is still set to NOECHO, TTSYNC, HOSTSYNC, X * and PASTHRU; see get_channels() for more info X */ X X /* requeue the AST */ X X status = SYS$QIOW(0,py_chan,IO$_SETMODE,&py_line_iosb,0,0,&dev_chg_ast, X`09`09 0,0,3,0,0); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X mess_d.dsc$a_pointer = "SETMODE QIO to PY device"; 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/*** dev_chg_ast ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09xon_ast X X Purpose:`09Called when XON is detected on the PTY. 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`09py_chan`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`09JLG_CANT_REQUEUE`09can't requeue XON AST to PY device X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic void xon_ast(void) X X`7B`09/*** xon_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 xon_char;`09`09/* char to write to the TTY`09 */ Xstatic`09 IOSB_DEF iosb;`09`09`09/* I/O status block`09`09 */ X X X /* normally we would get here after an XOFF has been delivered from X * the PY device and we would be in hiber state; we would just issue X * a SYS$WAKE, requeue the XON AST, and continue; that is, if we were X * doing this :-`7D X */ X X /* requeue the AST */ X X status = SYS$QIOW(0,py_chan,IO$_SETMODE,&iosb,0,0,&xon_ast,0,0,1,0,0); X X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X mess_d.dsc$a_pointer = "XON AST to PY device"; X mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer); X LIB$STOP(JLG_CANT_REQUEUE,1L,&mess_d); X `7D X X return; X X`7D`09/*** xon_ast ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09xoff_ast X X Purpose:`09Called when XOFF is detected on the PY 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`09py_chan`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`09JLG_CANT_REQUEUE`09can't requeue XOFF AST to PY device X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic void xoff_ast(void) X X`7B`09/*** xoff_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 xoff_char;`09`09/* char to write to the TTY`09 */ Xstatic`09 IOSB_DEF iosb;`09`09`09/* I/O status block`09`09 */ X X X /* getting here means the PY device is barfing on input; we should hiber X * until an XON AST is delivered; we could either requeue the XOFF AST X * here before the hiber or we could requeue it in the XON AST; we'll X * do it here since we aren't really doing anything with XOFF anyway X */ X X status = SYS$QIOW(0,py_chan,IO$_SETMODE,&iosb,0,0,xon_ast,0,0,2,0,0); X X if(!(status & SS$_NORMAL)) X `7B X mess_d.dsc$a_pointer = "XOFF AST QIO to PY device"; X mess_d.dsc$w_length = (USHORT) strlen(mess_d.dsc$a_pointer); X LIB$STOP(JLG_CANT_REQUEUE,1L,&mess_d); X `7D X X return; X X`7D`09/*** xoff_ast ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09write_py X X Purpose:`09Write data from TTY to the PTY X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09channel`09`09`09channel to write to X`09buffer`09`09`09buffer to write X`09length`09`09`09length of buffer to write`09 X `09iosb`09`09`09I/O status block for PY 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`09iosb->status`09`09error return in I/O status block X`09SS$_NORMAL X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic ULONG write_py(short channel,char *buffer,ULONG length,IOSB_DEF *iosb V) X X`7B`09/*** write_py ***/ X`09`09`09`09`09/******** LOCAL VARIABLES ********/ Xstatic`09 ULONG`09 status;`09`09/* return code status holder`09 */ X X X status = SYS$QIOW(0,channel,IO$_WRITEVBLK,iosb,0,0,buffer,length,0,0,0,0) V; X X if(status != SS$_NORMAL && status != SS$_DATAOVERUN) X `7B X LIB$SIGNAL(status); X return(status); X `7D X X if(iosb->status != SS$_NORMAL && iosb->status != SS$_DATAOVERUN) X `7B X LIB$SIGNAL(iosb->status); X return(iosb->status); X `7D X X return(SS$_NORMAL); X X`7D`09/*** write_py ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09write_tt X X Purpose:`09Write to the TTY X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09channel`09`09`09channel to write to X`09buffer`09`09`09buffer to write X`09length`09`09`09length of buffer to write`09 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`09status`09`09`09from SYS$QIO or IOSB of write to TTY X X Termination Codes: X X`09Code`09`09`09Reason X`09----`09`09`09------ X`09none X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic ULONG write_tt(short channel,char *buffer,ULONG length) X X`7B`09/*** write_tt ***/ X`09`09`09`09`09/******** LOCAL VARIABLES ********/ Xstatic`09 ULONG`09 status;`09`09/* return code status holder`09 */ Xstatic`09 IOSB_DEF iosb;`09`09`09/* I/O status block`09`09 */ X X X status = SYS$QIOW(0,channel,IO$_WRITEVBLK,&iosb,0,0,buffer,length,0,0,0,0 V); X X if(!(status & SS$_NORMAL)) X return(status); X X if(iosb.status != SS$_NORMAL) X return(iosb.status); X X /* make sure the right number of characters were written */ X X if((ULONG) iosb.count != length) X return(SS$_NOWRT);`09`09/* didn't write the right amount */ X X return(SS$_NORMAL); X X`7D`09/*** write_tt ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09get_stamp X X Purpose:`09Create the time stamp string. X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09stamp_buf`09`09where to put time stamp string 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`09stamp_buf`09`09pointer to where time stamp is X X Termination Codes: X X`09Code`09`09`09Reason X`09----`09`09`09------ X`09status`09`09`09return code from SYS$ASCTIM if it fails X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic char *get_stamp(char *stamp_buf) X X`7B`09/*** get_stamp ***/ X`09`09`09`09`09/******** LOCAL VARIABLES ********/ Xstatic`09 ULONG`09 status;`09`09/* return code status holder`09 */ Xstatic`09 char`09 time_buf`5BTIME_MAX+1`5D;`09/* array for holding time str Ving */ Xstatic $DESCRIPTOR(time_d,time_buf);`09/* for getting time value`09 */ X X X status = SYS$ASCTIM(0,&time_d,0,0); X X if(!(status & SS$_NORMAL)) X LIB$STOP(status); X X time_buf`5Btime_d.dsc$w_length`5D = '\0'; X cat(stamp_buf,"`5B",time_buf,"`5D"); X X return(stamp_buf);`09`09`09/* return pointer to time stamp str. */ X X`7D`09/*** get_stamp ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09write_log X X Purpose:`09Write the specified line to the log file. X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09line`09`09`09buffer to be written X`09length`09`09`09length of buffer to be written X`09log_rab`09`09`09RAB of log file X`09flags`09`09`09current flag structure X X Global variables: X X`09Name`09`09`09Examine/Modify/Use/Read/Write X`09----`09`09`09----------------------------- X`09stamp_buf`09`09`09`09X`09 X 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`09write to log file failed X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic void write_log(char *line,USHORT length,struct RAB *log_rab, X`09`09 FLAG_DEF *flags) X X`7B`09/*** write_log ***/ X`09`09`09`09`09/******** LOCAL VARIABLES ********/ X`09 ULONG`09 status;`09`09/* return code status holder`09 */ X`09 USHORT`09 i;`09`09`09/* loop and array index`09`09 */ Xstatic`09 USHORT`09 buf_cnt = 0;`09`09/* number of characters in buffer V */ Xstatic`09 char`09 rec_buf`5BMAX_REC+1`5D,`09/* for constructing record to w Vrite */ X`09`09 ch,`09`09`09/* for saving current character`09 */ X`09`09 lastch = -1;`09`09/* last character`09`09 */ X X X for (i = 0; i < length; i++) X `7B X ch = line`5Bi`5D; /* get the current char */ X X if((ch == LINE_FEED && lastch >= 0) `7C`7C buf_cnt >= MAX_REC - 1) X `7B X`09 /* either starting a new line or the buffer is full */ X X`09 log_rab->rab$l_rbf= &rec_buf;`09/* set up to write line`09`09 */ X log_rab->rab$w_rsz= buf_cnt; X X status = SYS$PUT(log_rab,0,0); X X`09 if(status != RMS$_NORMAL) X`09 `7B X`09 kill_log(); X`09 LIB$STOP(status); X`09 `7D X X if(flags->command && flags->time_stamp) X`09 `7B X`09 /* write the time stamp to the file */ X X`09 log_rab->rab$l_rbf= &stamp_buf; X log_rab->rab$w_rsz= strlen(stamp_buf); X X status = SYS$PUT(log_rab,0,0); X X`09 if(status != RMS$_NORMAL) X`09 LIB$STOP(status); X X`09 flags->command = FALSE; X`09 `7D X X`09 buf_cnt = 0;`09`09`09/* start the new line`09`09 */ X`09 rec_buf`5B0`5D = '\0';`09`09/* make it a string`09`09 */ X `7D X`20 X /* CR starting line? */ X X if((lastch == LINE_FEED `7C`7C lastch < 0) && ch == CARRIAGE_RETURN) X continue;`09`09`09/* yes, ignore it`09`09 */ X X /* don't want these on file (is this the way it should be???) */ X X if(ch != LINE_FEED && ch != CARRIAGE_RETURN && ch != 0) X `7B X`09 rec_buf`5Bbuf_cnt++`5D = ch; X`09 rec_buf`5Bbuf_cnt`5D = '\0'; X `7D X X lastch = ch;`09`09`09/* remember the last character`09 */ X `7D X X return; X X`7D`09/*** write_log ***/ X`0C X/*************************************************************************** V**** X**************************************************************************** V**** X X Function:`09log_session X X Purpose:`09This is actually the heart of the program. QIOW's are used X`09`09to read data from the PTY control device and write the data X`09`09to the TTY and to the log file if logging is enabled. X X Formal Parameters: X X`09Name`09`09`09Description X`09----`09`09`09----------- X`09py_chan`09`09`09channel to PTY device X`09tt_chan`09`09`09channel to TTY device X`09py_mbx_chan`09`09channeo to PTY termination mailbox X X Global variables: X X`09Name`09`09`09Examine/Modify/Use/Read/Write X`09----`09`09`09----------------------------- X`09mess_d`09`09`09`09 X`09X X`09tt_read_iosb`09`09`09`09X X`09py_write_iosb`09`09`09`09X X`09stamp_buf`09`09`09`09X X`09py_efn`09`09`09`09`09X X`09py_mbx_iosb`09`09`09`09X X`09py_mbx_buf`09`09`09`09X X`09flags`09`09`09 X`09 X X`09tt_r_efn`09`09`09`09X X`09wait_efn`09`09`09`09X X`09bintim`09`09`09`09`09X X`09tt_buf`09`09`09 X`09`09X X`09term_block`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`09JLG_CANT_QUEUE`09`09can't queue read to TT X`09JLG_CANT_WRITE`09`09can't write to PY X`09status X X**************************************************************************** V**** X**************************************************************************** V***/ X Xstatic void log_session(USHORT py_chan,USHORT tt_chan,USHORT py_mbx_chan) X X`7B`09/*** log_session ***/ X`09`09`09`09`09/******** LOCAL VARIABLES ********/ X`09 ULONG`09 status;`09`09/* return code status holder`09 */ X`09 USHORT length; Xstatic`09 char`09 log_enable`5B`5D = `7B"Logging has been ENABLED\r\n"`7D, X`09`09 log_disable`5B`5D = `7B"Logging has been DISABLED\r\n"`7D, X`09`09 stamp_enable`5B`5D = `7B"Time stamping has been ENABLED\r\n"`7D, X`09`09 stamp_disable`5B`5D = `7B"Time stamping has been DISABLED\r\n"`7D, X`09`09 cr`5B`5D = `7B"\015"`7D; X X X /* if we were really dedicated, we would queue AST's for XON, XOFF, and X * for detecting changes in the TW device charactistics (so we could X * propagate them to the TT device); since we're not overly concerned X * at this point, we'll just not do it; maybe sometime it'll be useful X */ X X /* queue a read to the PY termination mailbox to detect a hangup */ X X status = SYS$QIO(0,py_mbx_chan,IO$_READVBLK,&py_mbx_iosb,&py_mbx_ast,0, X`09`09 py_mbx_buf,sizeof(py_mbx_buf),0,0,0,0); X`20 X if(!(status & SS$_NORMAL)) X `7B X kill_log(); X mess_d.dsc$a_pointer = "AST to detect hangup"; 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 +-+-+-+-+-+-+-+- END OF PART 2 +-+-+-+-+-+-+-+-