On Unix it is easy to get your numeric UID and the GIDs of your primary group and secondary groups. You call the program
id simply. On OpenVMS it is not such easy to retrieve your numeric UIC which is OpenVMS’s equivalent to Unix’ UID and GID. With a bit DCL magic you can write a command procedure which tells you the UIC as easy as
id tells you your UID and GID on Unix. By programming this little command procedure you will also get introduced to lexical functions in DCL.
If you want to know your UID, your groups and the corresponding GIDs on Unix you use the command
id. For example:
$ id uid=1374(ogm) gid=20(users)
If you want to know only the numeric values of your UID and your (primary) GID you use the flags
$ id -u 1374 $ id -g 20
As a Unix guy challenged by the world of OpenVMS you will always hear something about the UIC (user identification code) on OpenVMS. It is a tuple
[group,member] which identifies an user or a group of users. With your Unix background you realize very soon it’s a similar concept to Unix’ UID and GID, but in some kind of a mixture. Unfortunately you do not find a command like Unix’
id to display this UIC on OpenVMS’ DCL interpreter (DEC Command Language). So let’s explore how to get a command procedure which will display us the UIC in the form of
[group,member] for the current user.
Constructing a Solution
On the DCL you have several lexical functions available. They follow the format
F$ is a prefix indicating that the following is a lexiacal function. The
Name tells what function to call. Inside the always present parentheses the arguments of the function find their place.
BTW: A complete reference of all lexical functions you will find in the HP OpenVMS DCL Dictionary.
Our solution begins with determining current user’s name. This purpose serves the lexical function
F$USER(). You can put the result into a symbol and show it afterwards:
$ ME = F$USER() $ SHOW SYMBOL ME [OLIVER]
Or you can print it directly:
$ WRITE SYS$OUTPUT F$USER() [OLIVER]
Now we need to map this determined user name to a numeric UIC. For this purpose exists the lexical function
F$IDENTIFIER(). For example:
$ UIC_INT = F$IDENTIFIER("OLIVER", "NAME_TO_NUMBER") $ SHOW SYMBOL UIC_INT UIC_INT = 4194305 Hex = 00400001 Octal = 00020000001
Now it is only one little step to convert this output into the required form of
[group,member]. To do so we use the lexical function
F$FAO() which converts characters and numeric values into ASCII strings.
F$FAO() operates in a similar way as
printf does on UNIX’ shell. To convert a long word integer to a numeric UIC in the format
F$FAO() provides the special sequence
!%U for its control string:
$ UIC = F$FAO("!%U", UIC_INT) $ SHOW SYMBOL UIC UIC = "[100,1]"
This looks well and looks like it can be composed with
F$USER() to one single command. Unfortunately there is one little detail to have an eye on.
Preparing the User Name
F$USER() returns the user name in brackets.
F$IDENTIFIER() expects in its first argument the user name without brackets. So we need to remove the brackets to provide a working solution.
There is the lexical function
F$EXTRACT() which extracts substrings from a given string. Its syntax is as follows and very simple to understand:
F$EXTRACT(sub_start, sub_length, from_string)
sub_start is the index of the first character of the substring within
sub_length is the length of the resulting substring.
from_string is the string from which the substring shall be extracted. For example:
$ WRITE SYS$OUTPUT F$EXTRACT(6,4,"APPLE TREE") TREE
Note: As you see the counting of characters in a string starts at zero.
With this lexical function it is easy to extract the user name and remove the brackets respectively from
F$USER()‘s output. To do so we simply need to determine the length of
F$USER()‘s output and subtract 2 (the brackets) from it.
The length of a string returns the lexical function
F$LENGTH(). To subtract 2 from the result we can use
F$STRING() evaluates the given string or numeric expression and returns the result as a string.
These ideas covered in DCL commands leads to this sequence:
$ WRITE SYS$OUTPUT F$USER() [OLIVER] $ WRITE SYS$OUTPUT F$LENGTH(F$USER()) 8 $ WRITE SYS$OUTPUT F$STRING(F$LENGTH(F$USER())-2) 6 $ WRITE SYS$OUTPUT F$EXTRACT(1,F$STRING(F$LENGTH(F$USER())-2),F$USER()) OLIVER
The last one is exactly what we were looking for.
Final Command Procedure
All this combined in one single command results in this command procedure:
$! Program: GETUIC.COM $! Purpose: Display UIC of current user. $! $! Copyright (c) 2013 Oliver Mueller, http://oliver-mueller.com $! All rights reserved. $! $ WRITE SYS$OUTPUT F$FAO("!%U", - F$IDENTIFIER( - F$EXTRACT(1, F$STRING(F$LENGTH(F$USER())-2), F$USER()), - "NAME_TO_NUMBER"))
Feel free to download
GETUIC.COM in this ZIP file.
Installation for All Users
Note: You will need the privilege
SYSPRV to install
GETUIC.COM for all users.
GETUIC.COM copy it to the location where your utilities normally reside, e.g. your own directory like
DKA0:[TOOLS], or a global one like
SYS$COMMON:[SYSEXE]. Afterward define a command by a symbol in
SYS$COMMON:[SYSMGR]SYLOGIN.COM. For example:
$ GETUIC :== @DKA0:[TOOLS]GETUIC.COM
$ GETUIC :== @SYS$COMMON:[SYSEXE]GETUIC.COM
You should restrict the access rights to this file by invoking this command:
$ SET SEC/PROT=(S:RWED,O:RWED,G:E,W:E) DKA0:[TOOLS]GETUIC.COM
$ SET SEC/PROT=(S:RWED,O:RWED,G:E,W:E) SYS$COMMON:[SYSEXE]GETUIC.COM
After a new login everybody is able to use
GETUIC as a command to determine her/his UIC. For example:
$ getuic [100,1]
Installation Just for Your Own
An installation just for your own user is much simpler. Copy
GETUIC.COM to your
SYS$LOGIN folder. (This is the folder in which you reside after login.) Edit or create the file
SYS$LOGIN:LOGIN.COM and put this line into it:
$ GETUIC :== @SYS$LOGIN:GETUIC.COM
Logout, login again and you are done! You can use the command
GETUIC now. For example:
$ getuic [100,1]