	.TITLE	SET_PRCNAM
	.IDENT	/03-000/
;
;  Copyright 1991 by Hunter Goatley.  This code may be freely distributed
;  and modified for non-commercial purposes as long as this copyright notice
;  is retained.
;
;++
;
;  Facility:	SET_PRCNAM
;
;  Author:	Hunter Goatley
;
;  Date:	August 13, 1986
;
;  Functional Description:
;
;	This program will set the process name for any process on the system.
;
;	An exercise for learning about the PCB vector table and what
;	information is stored for each active process.
;
;	Very little (if any) practical use.
;
;  Modified by:
;
;	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.
;
;--
	.SUBTITLE	Data area

	.LIBRARY	/SYS$LIBRARY:LIB.MLB/
	.LINK		"SYS$SYSTEM:SYS.STB"/selective_search

	.DSABL	GLOBAL				; Declare external references
	.ENABL	SUPPRESSION			; Don't list unreferenced syms
	.NOSHOW	BINARY				; Turn off binary in listings
;
;  External system routines:
;
	.EXTRN	LIB$GET_INPUT			; Read from SYS$INPUT
	.EXTRN	OTS$CVT_TZ_L			; Convert ASCII to hex
;
;  Global variables used here:
;
	.EXTRN	SCH$GL_PIXWIDTH			; Width of PIX field in EPID
	.EXTRN	SCH$GL_PCBVEC			; Vector of PCB address
	.EXTRN	SCH$GL_MAXPIX			; Maximum PIX for system
	.EXTRN	SCH$GL_SWPPID			; PID of SWAPPER process
	.EXTRN	SCH$AR_NULLPCB			; PCB address for NULL process

	$DSCDEF					; Descriptor symbols
	$PHDDEF					; Process header symbols
	$PCBDEF					; Process control block symbols
	$SSDEF					; System service status symbols



	.SHOW	BINARY				; Include binary in listings
	.PSECT	_SET_PRCNAM_DATA,NOEXE,WRT,LONG,SHR

PRCNAM_D:	.WORD	PCB$S_LNAME-1		; New process name descriptor
		.BYTE	DSC$K_DTYPE_T		; ...
		.BYTE	DSC$K_CLASS_S		; ...
		.ADDRESS .+4			; ...
		.BLKB	PCB$S_LNAME		; ...  Buffer

EPID_D:		.WORD	8			; ASCII PID descriptor
		.BYTE	DSC$K_DTYPE_T		; ...
		.BYTE	DSC$K_CLASS_S		; ...
		.ADDRESS .+4			; ...
		.BLKB	8			; ...  Buffer

EPID:		.LONG	0			; The PID of the target process

PID_PROMPT:	.LONG	3			; LIB$GET_INPUT argument list
		.ADDRESS EPID_D			; ...  Buffer to receive PID
		.ADDRESS 10$			; ...  The prompt
		.ADDRESS EPID_D			; ...  Buffer to receive length
	10$:	.ASCID	/Enter the PID of the target process: /

PRCNAM_PROMPT:	.LONG	3			; LIB$GET_INPUT argument list
		.ADDRESS PRCNAM_D		; ...  Buffer to receive name
		.ADDRESS 10$			; ...  The prompt
		.ADDRESS PRCNAM_D		; ...  Buffer to receive length
	10$:	.ASCID	/Enter the new process name: /

CVTPID:		.LONG	2			; OTS$CVT_TZ_L argument list
		.ADDRESS EPID_D			; ...  ASCII PID address
		.ADDRESS EPID			; ...  Hex PID address

KSET_ARGS:	.LONG	2			; KERNEL_SET_PRCNAM arg. list
		.ADDRESS EPID			; ...  The PID to change
		.ADDRESS PRCNAM_D		; ...  The new process name


;
;  The code PSECT is left writable so we can copy the process name to a
;  temporary buffer in this PSECT.
;
	.PSECT	_SET_PRCNAM_CODE,EXE,WRT,LONG,PIC,SHR
	.ENTRY	SET_PRCNAM,^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>

	CALLG	PID_PROMPT,G^LIB$GET_INPUT	; Get the target process's PID
	BLBC	R0,10$				; Branch on error
	CALLG	CVTPID,G^OTS$CVT_TZ_L		; Convert PID from ASCII to hex
	BLBC	R0,10$				; Branch on error
	CALLG	PRCNAM_PROMPT,G^LIB$GET_INPUT	; Get the new process name
	BLBC	R0,10$				; Branch on error
	$CMKRNL_S -				; Go to kernel mode to change
		ROUTIN=KERNEL_SET_PRCNAM,-	; ... the process name
		ARGLST=KSET_ARGS		; ...
 10$:	RET					; Return to caller

.PAGE
	.SUBTITLE	KERNEL_SET_PRCNAM routine
;+
;
;  Routine:	KERNEL_SET_PRCNAM
;
;  Functional description:
;
;	This  routine  executes in kernel mode to change the process name
;	for a specified process. It accesses the PCBs for  all  processes
;	in  the  system  via  the PCB vector table in system memory.  The
;	name cannot be set if a if another member of the target process's
;	group has the same name.
;
;  Inputs:
;
;	4(AP)	- Address of the EPID of the target process
;	8(AP)	- Descriptor address for the new process name
;
;  Implicit inputs:
;
;	SCH$GL_PCBVEC, SCH$GL_MAXPIX, SCH$GL_PIXWIDTH
;
;  Outputs:
;	None.
;
;  Returns:
;
;	R0	- Status
;		  SS$_NORMAL - Routine successfully completed
;		  SS$_DUPLNAM - The specified name duplicates one
;				already specified within that group
;		  SS$_NONEXPR - Nonexistent process (there was no
;				process matching the specified PID)
;
;+
KSP_PID = 4
KSP_NAM = 8

	.ENTRY	KERNEL_SET_PRCNAM,^M<R2,R3,R4,R5,R6,R7>
;
;  To avoid having to lock down the data area containing the new process
;  name, copy it to the space provided at the end of this routine.  This
;  buffer will be faulted-in via the "poor-man's lockdown", ensuring that
;  its access won't cause a pagefault.  Note that it is stored as ASCIC.
;
	MOVL	KSP_NAM(AP),R0			; Get the descriptor address
	MOVAB	130$,R2				; Load address of temp. buffer
	MOVZWL	(R0),R1				; Get length of process name
	CMPW	#<PCB$S_LNAME-1>,R1		; Is the name too long?
	BGEQU	10$				; Branch if it's OK
	MOVL	#<PCB$S_LNAME-1>,R1		; Set the maximum length
 10$:	MOVL	4(R0),R0			; R3 -> string itself
	MOVB	R1,(R2)+			; Store the length byte
 20$:	MOVB	(R0)+,(R2)+			; Copy the string to temp
	SOBGTR	R1,20$				; Loop until all copied

	MOVL	@KSP_PID(AP),R6			; Copy the target PID to R6
;
;  Our PCB address is still in R4 ($CMKRNL put it there).
;
;  Fault in the critical code and grab the SCHED (scheduler) spinlock.
;
 30$:
.IF DEFINED PCB$L_CPU_ID			; - VMS V5.x code
	TSTB	140$				; Fault in critical code
	LOCK	LOCKNAME=SCHED,-		; Grab the Scheduler spinlock
		SAVIPL=-(SP)			; ...  and raise the IPL
.IFF						; - VMS V4.x code
	DSBINT	140$				; Disable interrupts
.ENDC						; .IF
;
;  Get the group number of the target process
;
	TSTL	R6				; Was a target PID specified?
	BNEQ	40$				; If PID ^= 0, go look for PCB
	MOVL	PCB$L_EPID(R4),R6		; If 0, use current process PCB
 40$:	MOVL	G^SCH$GL_PIXWIDTH,R0		; Get the width (in bits) of the
						; ...  process index
	MOVL	G^SCH$GL_PCBVEC,R7		; Get the PCB vector table addr
;
;  We could JSB  G^EXE$EPID_TO_IPID to convert the PID from an EPID to IPID,
;  but it's not necessary.  We can compare the specified EPID with the EPID in
;  the target PCB.
;
	EXTZV	#0,R0,R6,R5			; Get the process index
	CMPL	G^SCH$GL_MAXPIX,R5		; Is the process index > max?
	BLSSU	50$				; Yes -- not valid PID
	CMPW	G^SCH$GL_SWPPID,R5		; NULL and SWAPPER are illegal
	BGEQ	50$				; ...  Branch to return error
	MOVL	(R7)[R5],R0			; Get the target PCB address
	CMPL	PCB$L_EPID(R0),R6		; Compare the two PIDs
	BEQL	60$				; If not equal, nonexistent proc
 50$:	BRW	110$				; Branch to return error
 60$:	MOVZWL	PCB$W_GRP(R0),R3		; Get the target group number
;
;  Check to make sure the new process name does not duplicate one already
;  used by a 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.
;
	MOVL	G^SCH$GL_MAXPIX,R4		; Get the maximum proc index
;
;  Start searching at the bottom of the vector table
;
 70$:	MOVL	(R7)[R4],R0			; Get a PCB address
	CMPL	G^SCH$AR_NULLPCB,R0		; Point to NULL?
	BEQL	90$				; Yes---no need to check it
	CMPW	PCB$W_GRP(R0),R3		; Is the process in target grp?
	BNEQ	90$				; No -- try next PCB
;
;  Here, we've found another process in this group.  Compare the process
;  names to make sure we there's no conflict.
;
	CMPL	R0,R6				; Is it the target process?
	BEQL	90$				; Branch if so; no need to check
	MOVAB	130$,R1				; Point to temp. buffer
	MOVZBL	(R1)+,R2			; Get the length
	MOVAB	PCB$T_LNAME(R0),R0		; Point to the name
	CMPB	R2,(R0)+			; Are the lengths the same
	BNEQ	90$				; No?  Try next PCB
 80$:	CMPB	(R1)+,(R0)+			; Compare each byte in names
	BNEQ	90$				; Branch when not equal
	SOBGTR	R2,80$				; Loop until all bytes compared
	MOVL	#SS$_DUPLNAM,R0			; No -- duplicate name
	BRB	120$				; Return to caller
 90$:	SOBGTR	R4,70$				; Loop until all PCBs checked
;
;  If here, valid PID AND no duplicate names
;
	MOVL	(R7)[R5],R0			; Get the PCB address of target
	CMPL	PCB$L_EPID(R0),R6		; Do the PIDs still match?
						; (Has the process been deleted
						; ... before we got here?)
	BNEQ	110$				; No -- nonexistent process
	MOVAB	130$,R1				; R1 -> new process name
	MOVZBL	(R1),R3				; Get the length
	MOVAB	PCB$T_LNAME(R0),R2		; R2 -> process name in PCB
 100$:	MOVB	(R1)+,(R2)+			; Copy the prc name to the PCB
	SOBGEQ	R3,100$				; Loop until all copied
	MOVZWL	#SS$_NORMAL,R0			; Set normal status
	BRB	120$				; Return to caller
 110$:	MOVZWL	#SS$_NONEXPR,R0			; Set non-existent process msg
 120$:
.IF DEFINED PCB$L_CPU_ID			; - VMS V5.x code
	UNLOCK	LOCKNAME=SCHED,-		; Release the scheduler spinlock
		NEWIPL=(SP)+,-			; ... and lower IPL
		CONDITION=RESTORE		; ...
.IFF						; - VMS V4.x code
	ENBINT					; Enable interrupts
.ENDC						; .IF
	RET					; Return to caller

 130$:	.BLKB	PCB$S_LNAME			; Space for the new process name

 140$:	.LONG	IPL$_SYNCH			; Synchronization IPL
	ASSUME	<.-30$> LE 512			; Make sure it's all one page

	.END	SET_PRCNAM






















































































