6

I wish to test a JDBC server implementation running under z/OS. The usual approach would be to define a JCL procedure and run this as a started task. The started task requires a user ID under which it would run. The JDBC jars are placed in a ZFS file system which has been mounted in OMVS.

The user for the started task requires certain RACF privileges This was provided with the following JCL

//RUNRACF  EXEC PGM=IKJEFT01
//SYSUADS  DD DSN=SYS1.UADS,DISP=SHR
//SYSLBC   DD DSN=SYS1.BRODCAST,DISP=SHR
//SYSTSPRT DD SYSOUT=*
//SYSTSIN  DD *
AU JDBCUSR NAME('JDBC STC USER') PASSWORD(JDBCUSR) -
    OWNER(IBMUSER) DFLTGRP(STCGROUP) -
    UACC(READ)  OMVS(HOME(/u/zfs4svr) PROGRAM(/bin/sh) UID(3005) -
FILEPROCMAX(131072))

RDEFINE STARTED SVRPROC.** STDATA(USER(JDBCUSR) GROUP(STCGROUP) -
TRUSTED(NO))

SETROPTS CLASSACT(STARTED)
SETROPTS RACLIST(STARTED) REFRESH

PERMIT BPX.SERVER ACCESS(READ) CLASS(FACILITY) -
  ID(JDBCUSR)

SETROPTS CLASSACT(FACILITY)
SETROPTS RACLIST(FACILITY) REFRESH

When I start the task the following error message turns up in SYSOUT:

JVMJZBL1001N JZOS batch Launcher Version: 2.4.4 2013-05-07
JVMJZBL1002N (C) Copyright IBM Corp. 2005, 2012
JVMJZBL1009E Child shell process exited without printing environment; //STDENV should not contain 'exit' JVMJZBL1042E JZOS batch launcher failed, return code=101

After looking this up and reading what the IBM support documentation had to say, I and my colleagues were pretty confused. I then tried starting the server as a straight forward job. The user for the job had system administrator privileges. This works and we can test the JDBC server. Trying to run the job with the user for the procedure results in the same error as shown above.

It's obvious that JDBCUSR lacks some privilege or other. To run the server as a started task I need to know what privileges are lacking. We certainly don't wish to give the started task user system admin rights.

Is there some way to find out what is missing? This is very frustrating.

Edit 11.10.2016

The following JCL is the JOB that does work when <user> has system admin privileges:

//V4JSRV   JOB USER=<user>,PASSWORD=<password>,REGION=200M
//*
//*******************************************************************
//* Call the server as a job
//*******************************************************************
//PROCS    JCLLIB ORDER=(ACHIM.JDBCSRV.CNTL)
//SRV      EXEC PROC=SRVPROC
//STDENV   DD DISP=SHR,DSN=ACHIM.JDBCSRV.CNTL(SRVENV)
//STRCTREP DD DISP=SHR,DSN=ACHIM.JDBCSRV.STRCTREP

The procedure looks like this:

//JDBCPROC  PROC JAVACLS='de.ubs.du.jdbcserver.Server',
//   ARGS='-p 5431 LOG-LEVEL=FINE',
//   LEPARM='',
//   LOGLVL='+T'
//JAVAJVM  EXEC PGM=JVMLDM70,REGION=200M,
//   PARM='&LEPARM/&LOGLVL &JAVACLS &ARGS'
//*JDBCPROC  PROC
//*JAVAJVM  EXEC PGM=JVMLDM70,REGION=200M,
//*   PARM='de.ubs.du.jdbcserver.Server -p 5431 LOG-LEVEL=FINE'
//STEPLIB  DD DSN=JVA700.SIEALNKE,DISP=SHR
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//CEEDUMP  DD SYSOUT=*
//ABNLIGNR DD DUMMY

As you can see the job does nothing more than run the procedure. When <user> is the username for the started procedure, the error above is produced, when it's an admin user, then the job runs normally. Obviously, to start it as a started task, the proc is copied to a public proc library (USER.PROCLIB to be precise).

There' nothing especially spectacular about any of this. In fact it is pretty banal. This is why we suspect that it's a RACF problem.

Edit (2) 11.10.2016

It's not a solution as yet, but I have managed to localize the problem. The started procedure functions if it is assigned the TRUSTED attribute. This effectively means the started task is treated as a "super user" in z/OS Unix (in other words it has root privileges). So now it is a matter of determining just what our server needs, that to date is only available when run by a super user. When I find out, I'll post a solution.

Edit (3) 12.12.2016

After adding the trace (see modified proc above), the following error occurs:

JVMJZBL2999T ->invokeMain()                                                           
JVMJZBL2999T javaClassName: 'de.ubs.du.jdbcserver.Server'                              
JVMJZBL2999T Arg 1='-p'                                                                
JVMJZBL2999T Arg 2='5431'                                                              
JVMJZBL2999T Arg 3='LOG-LEVEL=FINE'                                                    
JVMJZBL1023N Invoking de.ubs.du.jdbcserver.Server.main()...                            
JVMJZBL1056I Arguments to main...                                                      
JVMJZBL1057I -p                                                                        
JVMJZBL1057I 5431                                                                      
JVMJZBL1057I LOG-LEVEL=FINE                                                            
JVMJZBL2999T -> JniUtil.convert()                                                      
JVMJZBL2999T <- JniUtil.convert()                                                      
JVMJZBL2008E Could not find or load class: de.ubs.du.jdbcserver.Server                 
JVMJZBL2999T -> JniUtil.writeStackTrace()                                              
JVMJZBL2007E Stack trace follows:                                                      
java.lang.NoClassDefFoundError: de.ubs.du.jdbcserver.Server                            
Caused by: java.lang.ClassNotFoundException: de.ubs.du.jdbcserver.Server               
.at java.net.URLClassLoader.findClass(URLClassLoader.java:588)                         
.at java.lang.ClassLoader.loadClassHelper(ClassLoader.java:756)                        
.at java.lang.ClassLoader.loadClass(ClassLoader.java:724)                              
.at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:313)                      
.at java.lang.ClassLoader.loadClass(ClassLoader.java:703)                              
JVMJZBL2999T <- JniUtil.writeStackTrace()                                              

JVMJZBL2999T <- invokeMain()                                                           
JVMJZBL2999T <- run()                                                                  
JVMJZBL2999T -> cleanup()                                                              
JVMJZBL1014I Waiting for non-deamon Java threads to finish before exiting...           
JVMJZBL2999T JvmExitHook entered with exitCode=0, javaMainReturnedOrThrewException=0   
JVMJZBL1042E JZOS batch launcher failed, return code=100                               
JVMJZBL2999T DestroyJavaVM elapsed time=0.031311 seconds, cpu time=0.021000 seconds    
JVMJZBL2999I JZOS batch launcher elapsed time=7 seconds, cpu time=5.090000 seconds     
JVMJZBL1047W JZOS batch launcher completed with Java exception, return code=100        
JVMJZBL2999T <- cleanup()

Just why we're getting this run time error is unclear. At this stage it no longer looks like a permissions problem.

  • I'm not so sure that the JDBCUSR necessarily lacks authority. My guess is that it's a difference in the environment profile for that userid vs. the ones that work. Or maybe it's just something odd in the started task JCL that you didn't show, but if you used the same JCL with a different user id, then that's probably not it. – randomScott Oct 11 '16 at 02:52
  • I have edited the original query to include the job JCL and the proc. One thing that my colleagues have mentioned is the possibility that there is some RACF permission which is required in order for a user to run Java programs in z/OS. A permission that the admin user has but is lacking for the started task user (or anybody else on our system, for that matter). – Achim Schmitz Oct 11 '16 at 06:12
  • Seems randomScott is correct. I haven't had much time to devote to this problem, since we can test using the system admin log in ID. Never-the-less I did manage to get a trace out by making some changes to the proc. The result is shown under Edit (3). The NoClassDefFound is a bit hard to figure, since the class is exactly there where you'd expect it to be. When I figure it out I'll post my findings. – Achim Schmitz Dec 12 '16 at 14:05

1 Answers1

0

Finally I've had time to go back to this problem. The original problem was rather obscure. After looking at multiple forums it finally became clear that there was an error in the member ACHIM.JDBCSRV.CNTL(SRVENV). It contained the line:

. /etc/profile

Removing this fixed the first error, which was caused by the implicit "exit" at the end of any bash script. If you're doing something similar and really require the settings in the /etc/profile script, then I can only suggest you copy the contents of the script into you //STDENV data.

Thereafter a new error appeared:

java.lang.NoClassDefFoundError: de.ubs.du.jdbcserver.Server

This was shown in edit (3), above. This did turn out to be a permissions problem. In the job to set up the RACF permissions there is the following in the SYSTSIN DD:

OMVS(HOME(/u/zfs4svr)...

This specifies a mount point for the ZFS file system containing the jars used by JDBCUSR, when the task is started. The corresponding mount job was run by an admin user. The relevant job steps are:

//REPRO    EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN    DD *
  DELETE '<HLQ>.JDBCSRV.ZFS'
  SET MAXCC = 0
  DEFINE CLUSTER ( -
     NAME('<HLQ>.JDBCSRV.ZFS') -
     LINEAR CYL(50 1) -
     SHAREOPTIONS(3,3) -
  )
  REPRO INDATASET(<HLQ>.JDBCSRV.REPRO) -
         OUTDATASET(<HLQ>.JDBCSRV.ZFS)
//****************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
//    PARM='SH mkdir -p /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//*************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
//    PARM='SH chown -R JDBCUSR:STCGROUP /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//**************************************************
//SHELLCMD EXEC PGM=BPXBATCH,COND=(4,LT),
//    PARM='SH chmod -R 770 /u/zfs4fb'
//SYSPRINT DD SYSOUT=*
//SYSOUT   DD SYSOUT=*
//STDOUT   DD SYSOUT=*
//STDERR   DD SYSOUT=*
//**************************************************
//MOUNT    EXEC PGM=IKJEFT01,COND=(4,LT)
//SYSTSPRT DD SYSOUT=*
//SYSTSIN  DD *
  MOUNT -
     FILESYSTEM('''<HLQ>.JDBCSRV.ZFS''') -
     TYPE(HFS) -
     MODE(RDWR) -
     MOUNTPOINT('/u/zfs4fb')        

The difficulty here was the fact that the owner and rights for /u/zfs4fb are set to allow JDBCUSR access, however, the packages within are still owned by the user who runs the job. We changed the read/write access for the contents directly in OMVS. That fixed the problem. To fix this in the script, the order of the jobsteps needs to be changed. In this case, placing the 2 //SHELCMD steps with the chmod and chown commands after the //MOUNT step correctsd the problem

There were other issues with our task. In the initialization of the server, the property user.dir is used. I'm not sure just where, but it seems to have to do with the JVM for z/OS. It took a bit of tinkering, since we couldn't determine where the value comes from. When run as a job submitted by an admin user (IBMUSER) the value was "/u/ibmuser". However, when run as a started task, the value was ".", which caused the error:

java.lang.ExceptionInInitializerError                         
.at java.lang.J9VMInternals.initialize(J9VMInternals.java:258)
...
Caused by: java.lang.RuntimeException: default directory must be absolute 
.at sun.nio.fs.UnixFileSystem.<init>(UnixFileSystem.java:55)              
...

The fix was to place the command cd /u/zfs4fb at the end of the //STDENV environment script. This can actually be any directory for which the STC user (in this case JDBCUSR) has read permission.

Hope this tour of discovery helps someone else trying to come to terms with similar issues.

  • If your `/etc/profile` is causing errors, I would try to debug that. It will effect all interactive logins by default. – chicks Apr 10 '17 at 13:47
  • The `/etc/profile` in itself only sets some environment variables and the umask, none of which is actually relevant for the server or the proc which invokes it. The problem lies in the fact that it is sourced in the environment script for the proc. An sourced script always has an implicit "exit" at the end causing an error message: //STDENV should not contain 'exit'. I guess I should explain that in my answer. – Achim Schmitz Apr 12 '17 at 08:16