Discussion:
PASE and Environment Variables
(too old to reply)
George Shaw
2009-10-15 16:05:26 UTC
Permalink
I'm in the process of evaluating the porting of one of our products for
PASE. The AIX code uses fork() to create child processes, but it seems that
the environment variables that are an integral part of the product are not
propagated to the child process.

I've noticed the same problem in qp2term, where a simple program that prints
out environment variables shows that they are not propagated from the
qp2term command line to the executed program.

In a related product that is native to the AS/400, we use spawnp() to create
processes, and this can be configured to propagate environment variables, so
presumably there is not a technical problem with this.

I've not found any documentation that describes how fork() works under PASE
in this respect, nor anything that describes an alternative API or technique
that we can use in order to implement this. Can anybody help?
George Shaw
2009-10-15 16:33:25 UTC
Permalink
My apologies. My problem is not with fork(), but with qp2term, qp2shell and
qsh.

fork() propagates environment variables correctly.

If environment variables are created using a .profile file in the home
directory, then these are picked up when starting the interactive shell,
i.e. using the strqsh or qp2term command line, and executing echo.

But if you execute a custom program from the qp2term command line, or
execute the program from the qcmd command line using qsh or qp2shell, then
the custom program does not find the environment variables.

So the problem is how to execute a custom (AIX) program from qcmd, and to
get the program to see environment variables.
Post by George Shaw
I'm in the process of evaluating the porting of one of our products for
PASE. The AIX code uses fork() to create child processes, but it seems that
the environment variables that are an integral part of the product are not
propagated to the child process.
I've noticed the same problem in qp2term, where a simple program that prints
out environment variables shows that they are not propagated from the
qp2term command line to the executed program.
In a related product that is native to the AS/400, we use spawnp() to create
processes, and this can be configured to propagate environment variables, so
presumably there is not a technical problem with this.
I've not found any documentation that describes how fork() works under PASE
in this respect, nor anything that describes an alternative API or technique
that we can use in order to implement this. Can anybody help?
Mike Amos
2009-10-15 17:02:29 UTC
Permalink
George,

I'm not sure that I understand your problem. I set an env var in an
interactive i5 session (i.e. QCMD) as follows,

ADDENVVAR ENVVAR(myenvvar) VALUE("test")

I then invoked qp2term using 'call qp2term' and entered 'env' with the
following output under qp2term. As you can see, myenvvar is correctly
set to "test".

_=/QOpenSys/usr/bin/env
LANG=en_US
PASE_LANG=en_US
QIBM_PASE_DESCRIPTOR_STDIO=T
PATH=/QOpenSys/usr/bin:/usr/ccs/bin:/QOpenSys/usr/bin/X11:/usr/sbin:.:/usr/bin
ROWS=17
QIBM_DESCRIPTOR_STDIN=CRLN=Y
COLUMNS=132
PASE_PATH=/QOpenSys/usr/bin:/usr/ccs/bin:/QOpenSys/usr/bin/X11:/usr/sbin:.:/usr/bin
LC__FASTMSG=true
LOGNAME=MYUID
LOCPATH=/usr/lib/nls/loc
PASE_LC__FASTMSG=true
QIBM_USE_DESCRIPTOR_STDIO=I
QIBM_IFS_OPEN_MAX=66000
QIBM_PASE_CCSID=819
PASE_SHELL=/QOpenSys/usr/bin/bsh
SHELL=/QOpenSys/usr/bin/sh
PASE_LOCPATH=/usr/lib/nls/loc
HOME=/home/MYUID
PASE_TZ=EST5EDT,M3.2.0,M11.1.0
PASE_NLSPATH=/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat:/usr/lib/nls/msg/en_US/%N:/usr/lib/nls/msg/en_US/%N.cat
PWD=/home/MYUID
TZ=EST5EDT,M3.2.0,M11.1.0
myenvvar="test"
NLSPATH=/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat:/usr/lib/nls/msg/en_US/%N:/usr/lib/nls/msg/en_US/%N.cat

I then invoked qp2shell using
call qp2shell '/QOpenSys/home/MYUID/ls.sh'

where ls.sh contains

#!/bin/sh
#
set -xv
env > /home/MYUID/envout.txt

and found the following in /home/MYUID/envout.txt.

_=/QOpenSys/usr/bin/env
LANG=en_US
PASE_LANG=en_US
PATH=/QOpenSys/usr/bin:/usr/ccs/bin:/QOpenSys/usr/bin/X11:/usr/sbin:.:/usr/bin
PASE_PATH=/QOpenSys/usr/bin:/usr/ccs/bin:/QOpenSys/usr/bin/X11:/usr/sbin:.:/usr/bin
LC__FASTMSG=true
LOGNAME=MYUID
LOCPATH=/usr/lib/nls/loc
PASE_LC__FASTMSG=true
QIBM_IFS_OPEN_MAX=66000
QIBM_PASE_CCSID=819
PASE_LOCPATH=/usr/lib/nls/loc
HOME=/home/MYUID
PASE_TZ=EST5EDT,M3.2.0,M11.1.0
PASE_NLSPATH=/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat:/usr/lib/nls/msg/en_US/%N:/usr/lib/nls/msg/en_US/%N.cat
PWD=/home/MYUID
TZ=EST5EDT,M3.2.0,M11.1.0
myenvvar="test"
NLSPATH=/usr/lib/nls/msg/%L/%N:/usr/lib/nls/msg/%L/%N.cat:/usr/lib/nls/msg/en_US/%N:/usr/lib/nls/msg/en_US/%N.cat

Again, the env var myenvvar correctly contains "test".

Does this help?
Post by George Shaw
My apologies. My problem is not with fork(), but with qp2term, qp2shell and
qsh.
fork() propagates environment variables correctly.
If environment variables are created using a .profile file in the home
directory, then these are picked up when starting the interactive shell,
i.e. using the strqsh or qp2term command line, and executing echo.
But if you execute a custom program from the qp2term command line, or
execute the program from the qcmd command line using qsh or qp2shell, then
the custom program does not find the environment variables.
So the problem is how to execute a custom (AIX) program from qcmd, and to
get the program to see environment variables.
Post by George Shaw
I'm in the process of evaluating the porting of one of our products for
PASE. The AIX code uses fork() to create child processes, but it seems
that
Post by George Shaw
the environment variables that are an integral part of the product are not
propagated to the child process.
I've noticed the same problem in qp2term, where a simple program that
prints
Post by George Shaw
out environment variables shows that they are not propagated from the
qp2term command line to the executed program.
In a related product that is native to the AS/400, we use spawnp() to
create
Post by George Shaw
processes, and this can be configured to propagate environment variables,
so
Post by George Shaw
presumably there is not a technical problem with this.
I've not found any documentation that describes how fork() works under
PASE
Post by George Shaw
in this respect, nor anything that describes an alternative API or
technique
Post by George Shaw
that we can use in order to implement this. Can anybody help?
George Shaw
2009-10-16 09:08:49 UTC
Permalink
The use of ILE environment variables certainly makes a difference, but
rather strange differences.

I'll try to summarise the empirical results, and maybe somebody can make
sense of them.

If I set my environment variable using ADDENVVAR, then:

1. Inside the terminal session (strqsh or qp2term), a program executing
getenv() will now return the value found in the .profile file, NOT the ILE
environment variable. If the ILE environment variable is not set, then it
does not return the value form .profile.
2. From the command line (qsh or qp2shell), a program executing getenv()
will return the ILE environment variable. So the ILE environment is
faithfully copied.

As a side issue, if I also have a second environment variable that is the
same name as the first, but with the prefix "PASE_" added, the first
environment variable is overridden by the prefixed variable. So:

1. Inside a terminal session, getenv() returns the prefixed variable from
.profile.
2. From the command line, getenv() returns the prefixed variable from the
ILE environment.

G.
George Timms
2009-10-15 23:44:50 UTC
Permalink
Post by George Shaw
My apologies. My problem is not with fork(), but with qp2term, qp2shell and
qsh.
fork() propagates environment variables correctly.
If environment variables are created using a .profile file in the home
directory, then these are picked up when starting the interactive shell,
i.e. using the strqsh or qp2term command line, and executing echo.
But if you execute a custom program from the qp2term command line, or
execute the program from the qcmd command line using qsh or qp2shell, then
the custom program does not find the environment variables.
So the problem is how to execute a custom (AIX) program from qcmd, and to
get the program to see environment variables.
Not sure I understand your problem, but a little background may help: ILE
and PASE maintain independent sets of environment variables. Setting a
variable in either environment has no (direct/immediate) effect on the other
environment.

API programs QP2SHELL, QP2SHELL2, and QP2TERM attempt to mitigate this
difference by automatically copying the ILE environment into the first
(non-fork) process that starts PASE. fork() child processes always inherit
the PASE environment, and PASE runtime arranges for the child to also
inherit the ILE environment that exists in the parent at the time of fork().

Similarly, the PASE "qsh" command is actually a script that invokes utility
/QOpenSys/usr/bin/system with the -e option to automatically copy all PASE
environment variables into the ILE process that runs the QShell command. ILE
spawn() will (by default, I believe) ensure that a child process inherits
the parent ILE environment, but will not inherit any PASE environment in the
parent process.
--
George Timms
IBM Rochester
Walt Madden
2009-10-16 01:00:45 UTC
Permalink
Post by George Shaw
My apologies. My problem is not with fork(), but with qp2term,
qp2shell and qsh.
fork() propagates environment variables correctly.
If environment variables are created using a .profile file in the home
directory, then these are picked up when starting the interactive
shell, i.e. using the strqsh or qp2term command line, and executing
echo.
But if you execute a custom program from the qp2term command line, or
execute the program from the qcmd command line using qsh or qp2shell,
then the custom program does not find the environment variables.
So the problem is how to execute a custom (AIX) program from qcmd,
and to get the program to see environment variables.
Setting environment variables from a .profile file is a function of running
a "login shell". You get a login shell by default when you run QSH or CALL
QP2TERM with no arguments.

The following CL should run both a login shell (designated by the minus '-'
character prior to the shell program name in the "/QOpenSys/usr/bin/-sh")
and the command you also want the shell to run (the -c followed by the
program pathname arguments):

CALL PGM(QP2TERM) PARM('/QOpenSys/usr/bin/-sh' '-c' '/QOpenSys/usr/bin/env')
--
-----
Walt Madden
IBM i software development
George Shaw
2009-10-16 08:42:42 UTC
Permalink
Post by Walt Madden
Setting environment variables from a .profile file is a function of running
a "login shell". You get a login shell by default when you run QSH or CALL
QP2TERM with no arguments.
The following CL should run both a login shell (designated by the minus '-'
character prior to the shell program name in the "/QOpenSys/usr/bin/-sh")
and the command you also want the shell to run (the -c followed by the
CALL PGM(QP2TERM) PARM('/QOpenSys/usr/bin/-sh' '-c'
'/QOpenSys/usr/bin/env')
Post by Walt Madden
--
-----
Walt Madden
IBM i software development
STRQSH
$
Post by Walt Madden
cat .profile
NEWENV=ZZZ
$
Post by Walt Madden
echo $NEWENV
ZZZ
$
Post by Walt Madden
shownewenv
NEWENV is <>
Post by Walt Madden
QSH CMD('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('/QOpenSys/usr/bin/-sh' '-c' 'shownewenv')
NEWENV is <>
Press ENTER to end terminal session

The shownewenv program is an AIX program that just prints out a
getenv("NEWENV").

FYI, we have an existing native application that reads from a file that we
use to hold environment variables, and then implements them with putenv().
If all else fails, then we can implement something similar. But in the PASE
environment, I'd prefer to minimise any bespoke programming, so that the
product is as similar to our AIX product as possible.

G.
George Timms
2009-10-16 14:18:17 UTC
Permalink
Post by George Shaw
Post by Walt Madden
STRQSH
$
Post by Walt Madden
cat .profile
NEWENV=ZZZ
$
Post by Walt Madden
echo $NEWENV
ZZZ
$
Post by Walt Madden
shownewenv
NEWENV is <>
Post by Walt Madden
QSH CMD('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('/QOpenSys/usr/bin/-sh' '-c' 'shownewenv')
NEWENV is <>
Press ENTER to end terminal session
The shownewenv program is an AIX program that just prints out a
getenv("NEWENV").
I tried to reproduce you experiment and it seemed to work for me. My guess
is that your .profile file has CRLF as the newline character. QShell
accepts this PC-ism, but PASE shells follow the UNIX standard of only LF at
linend, so the CR looks like an extra character that generally causes the
script to fail (shell program name in the bang comment becomes not found
because of the extra CR).

One other point, calling QP2SHELL from a CL command line to run any PASE
shell program is unreliable because shells require "forkable" descriptors,
but the descriptors used in an interactive job cannot be forked into a child
process (ILE runtime limitation). If you want to run a shell program from
CL command entry, we recommend either calling QP2TERM, or using the QSH CL
command, both of which setup forkable stdin/out/err descriptors (pipes that
are "wired" to a program that handles I/O to either 5250 display or spool
files in batch).

Unfortunately, the QSH CL command doesn't "understand" the UNIX syntax for a
login script (with the extra dash in front of the name), so you may need to
create a symbolic link with the dash as part of the name to avoid an error
that the command/file is not found.
--
George Timms
IBM Rochester
George Shaw
2009-10-16 16:17:50 UTC
Permalink
You were correct about using CRLF, but there is no change when I change this
is LF.

You also talk about scripts, but my shownewenv program is an AIX-compiled C
program. But then I get the same result for a script that echos the
environment variable defined in .profile.

This is on V5R3.

Can you post your working code, .profile and the command line syntax?

G.
Post by George Timms
Post by George Shaw
Post by Walt Madden
STRQSH
$
Post by Walt Madden
cat .profile
NEWENV=ZZZ
$
Post by Walt Madden
echo $NEWENV
ZZZ
$
Post by Walt Madden
shownewenv
NEWENV is <>
Post by Walt Madden
QSH CMD('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('shownewenv')
NEWENV is <>
Press ENTER to end terminal session
Post by Walt Madden
CALL PGM(QP2SHELL) PARM('/QOpenSys/usr/bin/-sh' '-c' 'shownewenv')
NEWENV is <>
Press ENTER to end terminal session
The shownewenv program is an AIX program that just prints out a
getenv("NEWENV").
I tried to reproduce you experiment and it seemed to work for me. My guess
is that your .profile file has CRLF as the newline character. QShell
accepts this PC-ism, but PASE shells follow the UNIX standard of only LF at
linend, so the CR looks like an extra character that generally causes the
script to fail (shell program name in the bang comment becomes not found
because of the extra CR).
One other point, calling QP2SHELL from a CL command line to run any PASE
shell program is unreliable because shells require "forkable" descriptors,
but the descriptors used in an interactive job cannot be forked into a child
process (ILE runtime limitation). If you want to run a shell program from
CL command entry, we recommend either calling QP2TERM, or using the QSH CL
command, both of which setup forkable stdin/out/err descriptors (pipes that
are "wired" to a program that handles I/O to either 5250 display or spool
files in batch).
Unfortunately, the QSH CL command doesn't "understand" the UNIX syntax for a
login script (with the extra dash in front of the name), so you may need to
create a symbolic link with the dash as part of the name to avoid an error
that the command/file is not found.
--
George Timms
IBM Rochester
Mike Amos
2009-10-16 17:04:57 UTC
Permalink
This may not be relevant to your current question, but just in case:

Something that I ran into when bringing up an environment for our
non-IBM i folks was the difference between the bsh and korn shells. As
to which gets executed, bsh or korn, seems to depend on the way PASE is
entered. If memory serves correct, call qp2term brings up the bsh shell
and entering PASE via SSH - IBM's free code - brings up the korn shell.
For korn, you need the .env file, not .profile. George or Walt will know
which is which and you can also tell from the SHELL env var.

At this point, I have not run home grown AIX code in the PASE
environment, only nested shell scripts and make files.

Mike
Post by Walt Madden
Post by George Shaw
My apologies. My problem is not with fork(), but with qp2term,
qp2shell and qsh.
fork() propagates environment variables correctly.
If environment variables are created using a .profile file in the home
directory, then these are picked up when starting the interactive
shell, i.e. using the strqsh or qp2term command line, and executing
echo.
But if you execute a custom program from the qp2term command line, or
execute the program from the qcmd command line using qsh or qp2shell,
then the custom program does not find the environment variables.
So the problem is how to execute a custom (AIX) program from qcmd,
and to get the program to see environment variables.
Setting environment variables from a .profile file is a function of running
a "login shell". You get a login shell by default when you run QSH or CALL
QP2TERM with no arguments.
The following CL should run both a login shell (designated by the minus '-'
character prior to the shell program name in the "/QOpenSys/usr/bin/-sh")
and the command you also want the shell to run (the -c followed by the
CALL PGM(QP2TERM) PARM('/QOpenSys/usr/bin/-sh' '-c' '/QOpenSys/usr/bin/env')
Loading...