%TITLE 'SET_PRCNAM' MODULE SET_PRCNAM (MAIN = main, IDENT = 'V5.0') = BEGIN !++ ! ! Facility: SET_PRCNAM ! ! Author: Hunter Goatley ! Copyright © 1994, MadGoat Software. All Rights Reserved. ! ! Date: August 6, 1991 ! ! Abstract: ! ! This program will change the process name for any process on the ! system. Following normal VMS restrictions, the name must be unique ! within a UIC group. ! ! Very little (if any) practical use. ! ! Modified by: ! ! V5.0 Hunter Goatley 9-AUG-1994 22:46 ! Ported to run on OpenVMS AXP. The BLISS code actually ! required no changes, but the method of locking down the ! code had to be redone. ! ! Added messages, CLI$ interface, cleaned up code. ! ! 04-000 Hunter Goatley 6-AUG-1991 17:26 ! BLISS-32 rewrite. ! ! 03-000 Hunter Goatley 28-APR-1991 08:13 ! Rewrite for DECUS seminar. ! ! 02-000 Hunter Goatley 2-AUG-1988 11:42 ! Converted for use under VMS V5.0. ! ! 01-000 Hunter Goatley August 13, 1986 ! Original version. ! !-- LIBRARY 'SYS$LIBRARY:LIB'; !Pull stuff from LIB SWITCHES ADDRESSING_MODE (EXTERNAL = GENERAL, NONEXTERNAL = WORD_RELATIVE); FORWARD ROUTINE main, !Main entry point kernel_set_prcnam; !Kernel-mode routine EXTERNAL ROUTINE CLI$DCL_PARSE, !Parse a DCL command line CLI$GET_VALUE, !Get a value from command line CLI$PRESENT, !Check for presence on cmd line LIB$GET_FOREIGN, !Get foreign command line LIB$GET_INPUT, !Read from SYS$INPUT OTS$CVT_TZ_L, !Convert ASCII to hex STR$CONCAT, !Concatenate strings lock_nonpaged_code; !Routine to lock down code EXTERNAL set_prcnam_cld, !The CLI$ table SETPN__INVPID, SETPN__TRUNC, SETPN__CHANGED, CLI$_NOCOMD; ! ! MACROS ! MACRO errchk(status) = IF NOT(.status) THEN RETURN (.status)%; ROUTINE main = BEGIN LOCAL str : $BBLOCK [DSC$K_S_BLN], epid : UNSIGNED LONG, !Buffer for hex EPID kset_args : VECTOR[3,LONG] !Argument list for INITIAL (2, epid, str), !... kernel_set_prcnam status; $INIT_DYNDESC (str); status = LIB$GET_FOREIGN (str); errchk (status); status = STR$CONCAT (str, %ASCID'SETPN ', str); !Build command line errchk (status); status = CLI$DCL_PARSE (str, set_prcnam_cld, LIB$GET_INPUT); IF (.status EQLU CLI$_NOCOMD) THEN RETURN (SS$_NORMAL); errchk (status); status = CLI$GET_VALUE (%ASCID'PID', str); !Get the PID errchk(status); status = OTS$CVT_TZ_L (str, epid); IF NOT (.status) THEN SIGNAL (SETPN__INVPID); status = CLI$GET_VALUE (%ASCID'NAME', str); !Get the new name errchk(status); IF (.str [DSC$W_LENGTH] GTRU 15) THEN SIGNAL (SETPN__TRUNC); ! ! Lock down the pages contained code that is to be executed ! at elevated IPL. ! status = LOCK_NONPAGED_CODE(); errchk(status); status = $CMKRNL (ROUTIN = kernel_set_prcnam, ARGLST = kset_args); IF CLI$PRESENT (%ASCID'LOG') THEN SIGNAL (SETPN__CHANGED, 3, .epid, (IF (.str [DSC$W_LENGTH] GTRU 15) THEN 15 ELSE .str [DSC$W_LENGTH]), .str [DSC$A_POINTER]); RETURN (.status); !Return the status END; !End of routine %IF %BLISS(BLISS32E) %THEN !On AXP, use fancy macro $DECLARE_PSECT (EXEC$NONPAGED_CODE); %ELSE !On VAX, just change CODE PSECT PSECT CODE = EXEC$NONPAGED_CODE; %FI %SBTTL 'KERNEL_SET_PRCNAM' GLOBAL ROUTINE kernel_set_prcnam (epid_a, name_a) = BEGIN !+ ! ! Routine: KERNEL_SET_PRCNAM ! ! Functional Description: ! ! This routine actually changes the process name in the target process's ! PCB. ! ! Environment: ! ! Kernel-mode, elevated IPL (SCHED spinlock). ! ! Formal parameters: ! ! epid_a - Address of the longword containing the extended PID ! of the target process. ! name_a - Address of the descriptor for the new process name. ! ! Implicit inputs: ! ! CTL$GL_PCB : Address of PCB for current process ! SCH$AR_NULLPCB : Address of PCB for NULL process ! SCH$GL_PCBVEC : Base address of PCB vector table ! SCH$GL_MAXPIX : Maximum process index ! SCH$GL_PIXWIDTH : Width in PID of process index ! ! Outputs: ! ! None. ! ! Returns: ! ! R0 - Status ! SS$_NORMAL - Success ! SS$_NONEXPR - Non-existent process ! SS$_DUPLNAM - Duplicate name ! ! Side effects: ! ! Grabs the SCHED spinlock; may change the process name for a process. ! !- BIND epid = .epid_a : UNSIGNED LONG, name = .name_a : $BBLOCK; LOCAL local_name : $BBLOCK[PCB$S_LNAME]; REGISTER src_ptr : REF $BBLOCK, dest_ptr : REF $BBLOCK, target_pcb : REF $BBLOCK, pcb : REF $BBLOCK, group, work, pid, status; EXTERNAL CTL$GL_PCB : REF $BBLOCK, SCH$AR_NULLPCB : UNSIGNED LONG, SCH$GL_PCBVEC : REF VECTOR, SCH$GL_MAXPIX : UNSIGNED LONG, SCH$GL_PIXWIDTH : UNSIGNED LONG; src_ptr = .name[DSC$A_POINTER]; !Get the string address work = .name[DSC$W_LENGTH]; !Get the string length IF (.work GTRU PCB$S_LNAME-1) !If the string is too long, THEN !... truncate it work = PCB$S_LNAME - 1; !... ! ! Copy the string to our stack to prevent page faults. ! dest_ptr = local_name; CH$WCHAR_A(.work,dest_ptr); DECR i FROM .work TO 1 DO CH$WCHAR_A(CH$RCHAR_A(src_ptr), dest_ptr); pid = .epid; $SYS_LOCK (LOCKNAME = SCHED); !Grab SCHED spinlock IF (.pid EQLU 0) !If the EPID is 0, then use THEN !... the current process BEGIN !... target_pcb = .CTL$GL_PCB; !... pid = .target_pcb[PCB$L_EPID]; !... END; ! ! Validate the PID. This is done by extracting the process index from ! the PID and verifying that it is not greater than the MAXPIX and that ! it is greater than the PIX for SWAPPER (1). If both of these ! are true, the specified EPID is compared with the EPID of the process ! whose PCB is occupying the PCB slot in SCH$GL_PCBVEC. If the EPIDs ! differ, the PID is invalid. ! work = .SCH$GL_PIXWIDTH; !Get the process index width work = .pid<0,.work,0>; !Get the process index IF ((.work LEQU .SCH$GL_MAXPIX) AND !If the PIX is <=MAXPIX and (.work GEQU 2)) AND !... > 2, and if the EPID (BEGIN !... matches the EPID target_pcb = .SCH$GL_PCBVEC[.work]; !... in that PCB, get the group .target_pcb[PCB$L_EPID] !... number of that process END EQLU .pid) !... THEN !... group = .target_pcb[PCB$W_GRP] !... Save the group number ELSE !... Otherwise, release the BEGIN !... SCHED spinlock and return status = SS$_NONEXPR; !... an error $SYS_UNLOCK (LOCKNAME = SCHED, !Release SCHED spinlock NEWIPL = 0); !... RETURN (.status); !... END; ! ! Check to make sure the new process name does not duplicate one already ! used by another member of the same group. This is accomplished by stepping ! through the PCB vector table and comparing the new name with the name ! of each process belonging to the PID process's group. ! INCR j FROM 2 TO .SCH$GL_MAXPIX DO !Step through the PCB vector BEGIN !... table pcb = .SCH$GL_PCBVEC[.j]; !Get a PCB IF (.pcb NEQU .SCH$AR_NULLPCB) AND !If it doesn't point to NULL (.pcb[PCB$W_GRP] EQLU .group) AND !... and groups are equal (.pcb NEQU .target_pcb) !... and it's not same process, THEN !... then compare the names BEGIN ! ! Here, we found a member of the same group. Check the prcnam. ! src_ptr = local_name; !Point to the name dest_ptr = pcb[PCB$T_LNAME]; !Point to the name in PCB work = CH$RCHAR_A(src_ptr); !Get the length of the name IF (.work EQLU CH$RCHAR_A(dest_ptr)) !If lengths are same.... THEN ! ! This section compares the two process names to see if the ! new name is already in use. I could have used a CH$EQL ! or something to compare the strings, but I didn't want to ! use CMPC3 on a 1--16 byte string. Is this any better? ! Probably not.... ! WHILE (.work GTRU 0) DO BEGIN IF (CH$RCHAR_A(src_ptr) EQLU CH$RCHAR_A(dest_ptr)) THEN work = .work - 1 ELSE EXITLOOP; END; IF (.work EQLU 0) !If the strings were equal THEN !... then return an error BEGIN status = SS$_DUPLNAM; $SYS_UNLOCK (LOCKNAME = SCHED, !Release SCHED spinlock NEWIPL = 0); RETURN (.status); END; END; END; ! ! Here we have a valid PID *and* no duplicate names. Go ahead and copy ! the new process name to the PCB. ! dest_ptr = target_pcb[PCB$T_LNAME]; !Point to PCB area src_ptr = local_name; !Point to local copy work = CH$RCHAR(.src_ptr); !Get the length DECR i FROM .work TO 0 DO !Copy the entire string CH$WCHAR_A(CH$RCHAR_A(src_ptr),dest_ptr); !... size byte) status = SS$_NORMAL; !Set success status $SYS_UNLOCK (LOCKNAME = SCHED, NEWIPL = 0); !Release SCHED spinlock RETURN (.status); !Return the status END; END !End of module SET_PRCNAM ELUDOM !End of module