How to Port
the FLEXnet Publisher Licensing Toolkit
to Linux


Russell Bateman
last update: 22 June 2010

Disclaimer

This is an unauthorized document that does not represent Flexera Software, their employees or products.

I do not certify any of this information as being accurate or otherwise correct. It originates from notes I made and maintained during my active porting exercise getting the Flexera licensing component running. It may not reflect up-to-date information or techniques. Every (feeble) effort has been made, however, to make this document of non-zero utility. If it helps by answering a question you had, then it has served its purpose.


Introduction

This document is about porting the Acresso/Flexera licencing toolkit to Linux. This toolkit is not freely available, but obtained via agreement from Flexera Software, formerly Acresso Software. These are notes on my experience porting the software to Linux using Flexera's toolkit for Linux.

Flexera's contractual support is done by a very congenial and helpful staff of competent engineers and other support personnel. What's already written for you works; corraling all the pieces and understanding what's going on is the challenge.

There is a great deal of work in integrating Flexera licensing into your product and hardly any help is to be had in this document which only details the Linux activities. I was not involved in setting up the corporate license server, implementing the corporate-specific license policies, the Windows work or even much of the JNIs we wrote for use by our product (which is written in Java). I did, however, port the JNIs from Windows to Linux, in particular shimming them against Microsoftisms such as strncpy_s().


Table of Contents

Important terminology
Flexera documents
Tookit layout
Layout
Notes on building the toolkit
Important Flexera files
Publisher-modified files
Make-generated objects
Linux development environment set-up
Steps to configuring the toolkit
 
Appendix: Miscellaneous notes
Appendix: How to port the Linux toolkit
Appendix: Sample dæmon init script
Appendix: Flexera activation exercises
Appendix: Build directory file listings
Appendix: Application makefile
Appendix: List of shared-object libraries
Appendix: Flexera errors

Important terminology

This area could use some serious fleshing out. In particular though, note the duality of license file and trusted storage. You will see this reflected in server/svr versus app here and there in the undertaking that was the Linux port.

 
license file a text file, usually with extension .lic, that contains license certificates from one or more publishers.
publisher Corporation or owner of a product incorporating Flexera licensing software by agreement. Synonym: vendor.
trusted storage A tamper-proof area on the system that stores license rights. This location is different than license files and requires a different mechanism for loading and managing license rights. Compare trusted storage with license file.
vendor See publisher.

Flexera documents

What doesn't lack is the multitude of Flexera documents. As these are surely proprietary, I will give an index to them, but I cannot offer them to you; the links here are inoperable:

In my work, I used the following documents in order of frequency. I spent far more time in the first one than in any other, though I perused all of them at one point or another during my work.

  1. Creating a Licensed Product
  2. C/C++ Function Reference
  3. License Administration Guide

Toolkit layout

Layout

The Linux toolkit is laid out in the following fashion:

     
INSTALL_DIR defined at installation time e.g: flexera
PLATFORM located in INSTALL_DIR e.g.: flexera/i86_lsb
machind located in INSTALL_DIR/machind e.g.: flexera/machind
examples located in INSTALL_DIR/examples e.g.: flexera/examples

Note: "lsb" refers to "Linux standard base." The toolkit comes with a 64-bit implementation which my employer had not licensed at the time. However, I began porting it until I discovered it wasn't going to be used. It is identical to the 32-bit port.


Notes on building the toolkit

The tookit's objective is to be customized with private, publisher-specific information when built. If you are implementing Flexera licensing in your product, you are the publisher (sometimes also called "vendor").

This information is secret, the object of a contractual agreement with Flexera, and is generated by the latter. The output of this process is a set of tools that are used to enable FLEXible licensing in a product.

Most of this is described in Creating a Licensed Product.


Important Flexera files

  1. makefile.act and makefile—for building either the server-activated licensing utilities or the license file-based model utilities (or both). Each clobbers the output from the other.
  2. lmrand1—a random number utility useful for generating random seeds.
  3. lmstrip—strips (or obfuscates) symbols in any object including shared objects. Use at the end of making your own objects such as a JNI (shared-object library).

Publisher-modified files

The following files must be edited to change the demo values, seeds, magic numbers, etc. to publisher-specific ones, most of which are contractually established with Flexera Software. Note that, for the path element (subdirectory), i86_lsb, it is x64_lsb on 64-bit Linux platforms. On 32-bit Windows this path element is i86_n3. Of course, the special values will (must) agree between all platform targets for your software.

In this document, "mycompany" represents the vendor's company name. If you work for Acme Software, Ltd., this might be "acme" or "acmesoft" for you.

These are all the files. No other files in the build directory (i86_lsb for 32-bit Windows) must be modified except for makefile.act and makefile in which macro DAEMON must be set to "mycompany".

  1. machind/activation/prep_xml/vendor_daemon.xml
    • machind/activation/prep_xml/vendor_daemon.xml (irrelevant to Linux work)
    • machind/activation/prep_xml/vendor_daemon_mac.xml (irrelevant to Linux work)
    • machind/activation/prep_xml/vendor_daemon_unix.xml
  2. machind/lm_code.h
  3. i86_lsb/lmcode.c
  4. i86_lsb/ActivationSettings/publisher.xml
  5. i86_lsb/mycompany.rc (irrelevant to Linux work)
  6. i86_lsb/makefile
  7. i86_lsb/makefile.act


  Important  
  • Encryption settings (in machind/lm_code.h and ActivationSettings/publisher.xml) are kept secret and not generally made available even within the vendor's ranks.
  •  
  • Settings and vendor name must not be changed for this will break all previously issued licenses and applications using those settings.

  1. machind/activation/pre_xml/vendor_daemon_unix.xml

    Change the following:

    • Attribute runtimeloadname in element items to "mycompany_libfnp.so"
    • Attribute path in subelement item of element items to "mycompany"

    Note that the Windows and Macintosh platforms versions of this file use different extensions (like .dll and .exe.), hence, are separate.

  2. machind/lm_code.h

    This is the main file; it contains the vendor-name definition, encryption keys given by Flexera, and other information used when signing licenses. See page 17 (9) of Creating a Licensed Product. In particular, change the following macros' definitions. (The values are secret and not detailed here.)

    Note that every C-preprocessor definition in this file changes in some way.

    • VENDOR_KEY1
    • VENDOR_KEY2
    • VENDOR_KEY3
    • VENDOR_KEY4
    • VENDOR_KEY5
    • VENDOR_NAME to "mycompany"
    • LM_SEED1
    • LM_SEED2
    • LM_STRENGTH
    • TRL_KEY1
    • TRL_KEY1
  3. i86_lsb/lmcode.c

    Edit this file and change the single occurrence of "demo" to "mycompany".

  4. i86_lsb/ActivationSettings/publisher.xml

    Edit the following elements. (The values are secret and not detailed here. They are set up, using lmrand1, at the beginning of the project by each vendor.)

    • VendorName
    • Hash
    • Seeds—add 8 Seed elements
  5. i86_lsb/makefile

    Add the following paragraph at the top of the file (after any headers):

    
      DAEMON = mycompany
    		

    ...and comment out (or delete) original definition of DAEMON. You may not really want to use this makefile, but use makefile.act instead. It is for creating solely a license file-based approach (rather than one that can use both license files AND remote, server-given licenses).

  6. i86_lsb/makefile.act

    Add the following paragraph at the top of the file (after any headers):

    
      DAEMON = mycompany
    		

    ...and comment out (or delete) original definition of DAEMON.


Make-generated objects

These are products of the make process:

    russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> ranlib *.a ; ranlib activation/lib/*.a
    russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> make -f makefile.act clean
    russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> make -f makefile.act
   *russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> make -f makefile.act libtsJavaAcc.so

or...

    russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> make -f makefile clean
    russ@rhel-32:~/flexera/fnptoolkit/11/7/0/linux/i86/i86_lsb> make -f makefile

* Probably corrected by the time you undertake this, it was necessary to invoke make explicitly for this library because no dependency existed in it to force its creation. (Note that this action causes the creation of libtsJavaAcc.so and libtsJavaAcc_libFNP.so. These are crucial in order to work against the trusted storage from Java. See Java Toolkit sample code, TSexample.java.)

  1. lmgrd—the license manager, colored to belong to the publisher.
  2. vendor dæmon—operates with lmadmin or lmgrd to serve up licenses. It can be built as either a license file or as trusted storage. Your vendor dæmon will carry the name you choose to represent your company, i.e.: "mycompany".
  3. lm_new.o—file containing publisher-specific parameters that must be linked into the FLEXenabled application binary. This file is produced by the C compiler from generated file lm_new.c, itself influenced by publisher-specific definitions in lm_code.h. The make process leaves this file deleted after consuming it in other products. It will have to be rebulit (using its makefile target) in the case a vendor-built object, such as a shared-object library (JNI in my case), must link it.
  4. serveractutil—binary executable (utility) that issues and "unissues" licensing server-obtained licenses.
  5. serveractutil_libFNP.so—shared-object library in support of previous product.
  6. appactutil—binary executable (utility) that issues and "unissues" localized, license file-based licenses.
  7. appactutil_libFNP.so—shared-object library in support of previous product.
  8. appactutil—binary executable (utility)
  9. lmdown, lmreread and lmstat—these are links on Linux to lmutil whereas on Windows, they are real (and separate) utilities.
  10. lm*—lots of other utilities I'm unfamiliar with and didn't ship with my product.
  11. libmyapplicsvrjni.so—the publisher-specific JNI for use in support of Java licensing code that runs on Linux, analogous to Windows DLL libmyapplicsvrjni.dll. This was used for server-originated licensing. You might not have one of these (and the name is arbitrarily chosen).
  12. libmyapplicaccjni.so—the publisher-specific JNI for use in support of Java licensing code that runs on Linux, analogous to Windows DLL libmyapplicaccjni.dll. This was used for local licensing (using license files). You might not have one of these.

Linux development environment set-up

Assuming the Linux platform directory is (arbitrarily chosen to be) flexera, Follow these steps on a clean copy of the toolkit installation. These instructions are from page 20 (12) of Creating a Licensed Product. This is done AFTER editing lm_code.h. See Appendix: How to Port Linux Toolkit.


Steps to configuring the toolkit

For all of these, see Publisher-modified files.

  1. Add vendor keys to toolkit.
  2. Add vendor name to toolkit.
  3. Define settings that enable publisher-specific encryption.

Some or all of the following steps will be required in practice to build the toolkit. Note that I entitled my application "myapp" while the company name is "mycompany".

  1. Set up Subversion on target (or CVS—depending on what you're using for source-code control).
  2. Check out myapp/licensing.
  3. Check out myapp/flexera/fnptoolkit/11.7.0.
  4. Create and run fix-up-for-build.sh in linux subdirectory. This script will erase all Flexera files that should be replaced with publisher versions. Run this as root (since the toolkit files are read-only).
        #!/bin/sh
        # This fixes up the Linux stuff with publisher-modifed files ready for building.
        TRUE=1
        FALSE=0
    
        ans="n"
    
           SHARED_I86_LSB=../shared/i86/i86_lsb
           SHARED_MACHIND=../shared/i86/machind
        SHARED_ACTIVATION=$SHARED_MACHIND/activation/prep_xml
         SHARED_PUBLISHER=$SHARED_I86_LSB/ActivationSettings
           TARGET_I86_LSB=./i86/i86_lsb
           TARGET_MACHIND=./i86/machind
        TARGET_ACTIVATION=$TARGET_MACHIND/activation/prep_xml
         TARGET_PUBLISHER=$TARGET_I86_LSB/ActivationSettings
    
        echo -n "Do you wish to copy publisher files over generic toolkit? [y/n]: "
        read ans
    
        if [ "$ans" = "y" ]; then
          cp -v $SHARED_ACTIVATION/vendor_daemon_unix.xml $TARGET_ACTIVATION
          cp -v $SHARED_MACHIND/lm_code.h                 $TARGET_MACHIND
          cp -v $SHARED_I86_LSB/lmcode.c                  $TARGET_I86_LSB
          cp -v $SHARED_I86_LSB/makefile                  $TARGET_I86_LSB
          cp -v $SHARED_I86_LSB/makefile.act              $TARGET_I86_LSB
          cp -v $SHARED_PUBLISHER/publisher.xml           $TARGET_PUBLISHER
        fi
        # vim: set tabstop=2 shiftwidth=2 expandtab:
    		
  5. Depending on your version of RedHat Enterprise Linux, gcc, SuSE Linux Enterprise Server, etc. it can be challenging to build Flexera. There are issues, for example, with gcc 4.1.2-46—or the version that RedHat 5.4 comes with (when you don't have a proper subscription as I do not). It is recommended that you build using an early-ish version, like gcc 4.0.4, because that will give you better coverage (for your customers that still field RedHat 4.x). Alernatively, you can do what I did—build on SLES 11 (I also played with openSuSE 11.x) using whatever compiler came with it. This alternative is not without its own nightmare.

    In /lib fix up a link to ld-linux.so.2 as shown below. This usually isn't necessary on RHEL, but it's necessary to run the build utilities on that platform and all others. The library that the utilities is looking for is named ld-lsb.s0.3. If it doesn't exist, create it. You should see something like this when you're done:

        russ@opensuse-32:~/myapp/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> ll /lib/*ld*
        -rwxr-xr-x 1 root root 125684 2009-10-26 09:17 /lib/ld-2.10.1.so
        lrwxrwxrwx 1 root root     12 2010-02-08 06:03 /lib/ld-linux.so.2 -> ld-2.10.1.so
        lrwxrwxrwx 1 root root     13 2010-02-08 15:18 /lib/ld-lsb.so.3 -> ld-linux.so.2
    			
  6. Go to myapp/flexera/fnptoolkit/linux/i86/i86_lsb and use this build script:
        #!/bin/sh
        # Quickie build-everything for Linux
        ranlib *a
        ranlib activation/lib/*.a
        make -f makefile.act clean
        make -f makefile.act
        #or: make -f makefile
    			
  7. From the i86_lsb subdirectory, step down into publisher and perform the install. You should see the echoed output as shown.
        russ@opensuse-32:~/myapp/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> pushd publisher
        russ@opensuse-32:~/myapp/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb/publisher> sudo ./install_fnp.sh
        Installing anchor service from ./FNPLicensingService/FNPLicensingService to /usr/local/share/acresso/service/11.7.0
    
        Checking system for trusted storage area...
        Configuring for Linux, Trusted Storage path /usr/local/share/macrovision/storage...
        Creating /usr/local/share/macrovision/storage...
        Setting permissions on /usr/local/share/macrovision/storage...
        Permissions set...
        Configuration completed successfully.
    	
  8. Return to the i86_lsb subdirectory and set up LD_LIBRARY_PATH to include that subdirectory and the one you were just in:
        russ@opensuse-32:~/myapp/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> export LD_LIBRARY_PATH="`pwd`:`pwd`/publisher"
    			
  9. From this point on, you can test your build by following the exercises in the appendix, Flexera Activation Exercises, some of which you've already done here.

Appendix: Miscellaneous Notes

What's explained here was simply not integrated at appropriate places (if any) in this document proper. Reading through here when you experience a problem could be useful.

  1. Flexera only supports ancient versions of Red Hat and SLES emitted when gcc 4.0.4 was the shipping compiler. This makes building their toolkit very challenging as it's not easy back-rev'ing to get that version of the compiler and supporting libraries and shared objects configured, especially on a working platform you care about.

    I found that this can be ignored. However, no version of tool stack seems to be adequate on Red Hat 5.4 and I've simply built solely on a SLES 11 whose gcc version is 4.3.2, then copyied the product thereof to Red Hat where it just works.

    It seems possible to build and to use the product of the build of the two JNI shared objects on Red Hat for Red Hat. However, this isn't too useful as a single build platform is more useful.

    Symptomatically, a bad gcc version (on RedHat) resulted in serveractutil blowing chunks when I tried to run it. Bringing in the one built on SLES with 4.3.2 worked just fine. Other products (like our JNI shared-objects, still other utilities) built using this version on RedHat seemed to work just fine, however.

  2. Utility lmnewgen is run to create lm_new.c. lmnewgen is itself generated based on lm_code.h, lsvendor.c, lmcode.c and modification to lsvendor.c by lmrand1.

    An error got during the build invoking lmnewgen is:

        ./lmnewgen mycompany -o lm_new.c
        v8.1+ FLEXnet, using TRL
        lc_init failed: Invalid key data supplied.
        FLEXnet Licensing error:-44,49
        For further information, refer to the FLEXnet Licensing documentation,
        available at "www.acresso.com".
        make: *** [lm_new.o] Error 1
    		

    It turned out later that file lmcode.c had an occurrence of string "demo" that had to be replaced by "mycompany". This is a note to warn that such "mysterious" problems may occur if the files the publisher must modify are not carefully written over the shipping toolkit files.

  3. In building my two JNI modules, lm_new.o must be linked. This product (of the Flexera toolkit build) is always deleted by the toolkit makefiles. The makefile forces it to be regenerated/recompiled by a special target.
     
  4. In linking my two JNI modules, static libraries were used to cover Flexera symbols. Because of Flexera not keeping up with support for modern (post-2007) Red Hat and SLES (in particular, they only support you if you build with gcc 4.0.4), it was found that libstdc++.a had to be linked in (statically, obviously) in order not to be missing __gxx_personality_v0. This library lives on /lib/gcc, but in different subdirectory paths depending on a) Linux distro and b) version of gcc.
  5.  
  6. A dæmon init script must be written and installed on the path /etc/init.d/lmgrd that governs the state of the Flexera licensing service. This script was added to Subversion on the path myapp/flexera/fnptoolkit/11.7.0/linux/i86/lmgrd. (Note to Windoz guys: Such scripts do not observe the format of ending in .sh.)

    During installation, the following command must be issued to install lmgrd permanently so as to be present after bouncing the host:

        chkconfig --levels 35 lmgrd on
    			

    This script shouldn't accept arguments. The executable, lmgrd, accepts, in particular, -c for license files and -l for the pathname of the log file to use.

    Studying the doc closer, I see that -c either indicates a file or indicates a search path. The developer doc isn't as clear on this point as it could be. Thus,

        lmgrd -c $MYAPP_HOME/bin/myapp_ts.lic 

    and

        lmgrd -c $MYAPP_HOME/bin 

    or

        lmgrd -c $MYAPP_HOME/bin;$MYAPP_HOME/elsewhere 

    are valid, while

        lmgrd -c $MYAPP_HOME/bin/myapp_ts.lic;$MYAPP_HOME/bin/rhel-32.lic 

    is not a valid command line. This makes perfect sense now (and you probably already understood it that way).

    However, it appears I'm unable to use myapp_ts.lic (shipping, default license file) in bin when bad file, rhel-32.lic, is present. At least, the log doesn't give warm fuzzies about it using myapp_ts.lic after it indicates its revulsion with (alternative, test file) rhel-32.lic.

    Additional note: I don't remember whether the path delimiter for a list of subdirectories is ":" or ";" (as I have it here).

  7. For "black," therefore, it is sufficient to drop the license file into $MYAPP_HOME/bin and bounce the dæmon. lmgrd goes looking for any license file on the path named by the -c option.
  8.  
  9. When it comes time to port the dæmon init script (lmgrd) to Solaris, which script mechanism doesn't exist, here's the Solaris Service Management Facility Quickstart Guide to help.
  10.  
  11. "lmgrd oder lmadmin, es ist die Frage !" lmadmin appears to be the favored solution though this was not really clear at first and it was too late in my release cycle to switch horses. It offers a web interface, was introduced in Flexera 11.6 and cannot be used with components earlier than 9.2. I will correct this oversight for next release.
  12.  
  13. There are many files that must be "scraped" from my development area and copied when the application is installed on Linux. These tend to end up in
    • $MYAPP_HOME/bin (most)
    • /etc/init.d/lmgrd (to wit: this file)
    • elsewhere?

    It's really a question of personal preference (beyond what's essential to the use of toolkitinstall.sh). I originally explored this question when I attempted to lump everything into a subdirectory named run early on in the project.

  14.  
  15. Files and actions for Linux licensing in $MYAPP_HOME/bin:, install_fnp.sh and toolkitinstall.sh:
    1. create new subdirectory $MYAPP_HOME/bin/publisher
    2. copy fnptoolkit/11.7.0/linux/i86/i86_lsb/publisher/toolkitinstall.sh into new subdirectory
    3. copy fnptoolkit/11.7.0/linux/i86/i86_lsb/*.yaa (this is just one file for now, but in theory it could be more) to $MYAPP_HOME/bin
    4. execute $MY_HOME/bin/publisher/toolkitinstall.sh
    5.  
    6. create new subdirectory $MYAPP_HOME/bin/FNPLicensingService
    7. copy fnptoolkit/11.7.0/linux/i86/i86_lsb/publisher/install_fnp.sh into $MYAPP_HOME/bin; make it executable
    8. copy fnptoolkit/11.7.0/linux/i86/i86_lsb/publisher/FNPLicensingService/FNPLicensingService into the new subdirectory of the same name
    9. execute $MYAPP_HOME/bin/install_fnp.sh BEFORE starting the lmgrd dæmon.

    (Relocate this higher in the document because it's formally part of the work to be done?)

  16.  
  17. LD_LIBRARY_PATH must be set in order to run

    In the dæmon init script, this is done...

        cd $MYAPP_HOME/bin
        .
        .
        .
        export LD_LIBRARY_PATH=`pwd`
    		
  18.  
  19. After a license is activated (via soapUI, etc.), lmreread is called to sync up the trusted store and the operation server. If this doesn't happen, then isLicensedFeature() will return false (in soapUI as elsewhere). Remember, you can cause these scripts and binaries to be run from your application code, in my case, from my JNI.

    Also, lmreread tends to get called at, like, midnight in a running application in order to avoid letting things get stale. (Is my application doing this?)

    One of the ways this can happen is for lmutil, to which lmreread, lmdown and lmstat are linked (in $MYAPP_HOME/bin), to be zero-length. This is a binary shipped to us from Flexera, not something we compile or link.


Appendix: How to port the Linux toolkit

(Methodology)

  1. Start with a new toolkit (no modifications). Explode the tarball in a new development subdirectory.
  2. Switch to subdirectory i86_lsb and attempt to execute utility lmrand1. If it will not execute, this means your Linux platform is not supported by your Flexera contract.
  3. In i86_lsb, change makefile and makefile.act to replace "demo" with "mycompany".
  4. In machind, change header file lm_code.h manifest constants to the TRL and vendor key values given in the contract. Best practice: simply port this header from Windows.
  5. Replace the "demo" keyword with the company name (based on a contract value) where applicable, i.e.: i86_lsb/lmcode.c.

    If you fail to do this step, lmnewgen at very least will yield an error about "invalid key data" and the build will fail.

  6. Include i86_lsb/ActivationSettings/publisher.xml based on contract.
  7. Include the preptool configuration file machind/activation/prep_xml/vendor_daemon_unix.xml with "demo" replaced.
  8. Perform the build thus:
        rbateman@slc-bateman-karmic:~/dev/flexera> cd i86_lsb                
        rbateman@slc-bateman-karmic:~/dev/flexera> ranlib *.a                
        rbateman@slc-bateman-karmic:~/dev/flexera> ranlib activation/lib/*.a 
        rbateman@slc-bateman-karmic:~/dev/flexera> make -f makefile.act clean
        rbateman@slc-bateman-karmic:~/dev/flexera> make -f makefile.act      
        rbateman@slc-bateman-karmic:~/dev/flexera> make -f makefile          
    		

Note: On 64-bit, path i86_lsb above is instead x64_lsb.


Appendix: Sample dæmon init script

The purpose of this script is to control the license manager, lmgrd, for the operations start, stop, restart and status. This sample should convey the important points. For a basic discussion of these scripts, see here.

Note two points. First, since version 11.6, Flexera has moved on to prefer license management using lmadmin. The documents did not weight this fact too heavily against using lmgrd. Second, you should create a special user, in the mold of tomcat, by which lmadmin is controlled, to wit: lmadmin. This closes a slight security hole in the strategy I first adopted (of controlling lmgrd from the root user).

    #!/bin/bash
    # chkconfig: 35 20 80
    # description: MyCompany license manager
    # processname: lmgrd

    # =============================================================================
    MYAPP_COPYRIGHT="Copyright (c) 2010 by MyCompany, Inc. All rights reserved."
      MYAPP_VERSION=4.0.0
    #
    #         Define DEBUG_LMGRD (as any value) to get some status on the console.
    #
    NAME=lmgrd
    #          Start/stop/restart/etc. the Flexera/MyCompany license manager daemon.
    #          The hard-coded magic in this script consists of $NAME,
    #          $LICENSE_FILES, $LOGFILE_PATH and $LMGRD_OPTIONS.
    #
    #          During Linux installation, the following command is issued:
    #          chkconfig --levels 35 lmgrd on     [RHEL]
    #          chkconfig             lmgrd 3      [SLES]
    #
    #          $MYAPP_HOME must be set and accurate before this script is executed.
    #          This script should set it. If the script isn't there, it's likely
    #          not a proper installation and it will have to be set by hand.
    if [ -f "/etc/default/myapp" ]; then
      . /etc/default/myapp
    fi

    LICENSE_FILES=$MYAPP_HOME/bin
     LOGFILE_PATH=$MYAPP_HOME/logs/Licensing/license_svc.log
    #
    #          These are pretty much the only, possible options and they cannot be
    #          passed to the script. If LMGRD_OPTIONS is already set in the
    #          environment, then it will override these here.
    if [ -z "$LMGRD_OPTIONS" ]; then
      LMGRD_OPTIONS="-c $LICENSE_FILES -l $LOGFILE_PATH"
    fi
    #
    #          Platform support
    #          Deal with what platform we're running on: we claim to support Red
    #          Hat Enterprise Linux and SuSE Linux Enterprise Server. We'll be
    #          doing Solaris later, but there will be no sign of that in here since
    #          the daemon init script is a purely Linux phenomenon.
    if [ -f "/etc/rc.d/init.d/functions" ]; then
      PLATFORM="RHEL"
      . /etc/rc.d/init.d/functions
    elif [ -f /etc/rc.status ] ; then
      PLATFORM="SLES"
      . /etc/rc.status
    else
      echo "Platform is unsupported."
      exit 0
    fi
    #
    #          (Note: this document is entabbed at 2.)
    # =============================================================================
              TRUE=1
             FALSE=0
       EXIT_STATUS=0
    daemon_running=$FALSE

    DoUsage()
    {
      echo "Usage: /etc/init.d/lmgrd {start|stop|restart|status}"
      echo
      echo "Unless overridden, license files are on the path:"
      echo "    $MYAPP_HOME/bin"
      echo "and the log file for this service is at:"
      echo "    $LOGFILE_PATH"
      echo
      DoVersion
    }

    DoVersion()
    {
      echo "lmgrd: myapp version $MYAPP_VERSION"
      echo $MYAPP_COPYRIGHT
    }

    SeeIfDaemonIsRunning()
    {
      # Determine whether the daemon already happens to be running since it's
      # important depending on what operation this script is to undertake. Note:
      # we don't have to test this ps command because we know both Red Hat and SuSE
      # support it. If other Linux platform support is added, we might have to use
      # a different one and parse it differently too. (Ask Russ Bateman.)
      PS_CMD="ps -e -o pid,args"

      # Get the list of processes whose status contains "lmgrd" and filter out the
      # ones due to grep, [g]vi[m], this script executing, etc. (mostly happening
      # during initial bring up and testing) because they don't count as instances
      # of this daemon running.
      #                    find daemon  no greps       no sh -x     no editing
      proc_list=`$PS_CMD | grep $NAME | grep -v grep | grep -v sh | grep -v vi`

      # Some presumably real instances to sort through (almost certainly never more
      # than one single process). Here's the business end of this function:
      # producing a process id or a list of process ids.
      procs=`echo $proc_list | awk '{print $1}'`

      # If we're left with anything, then it means the daemon is running!
      if [ -n "$procs" ]; then
        daemon_running=$TRUE
      else
        daemon_running=$FALSE
      fi
    }

    start()
    {
      echo -n "Starting $NAME: "

      case "$PLATFORM" in
        "RHEL")          daemon               ./$NAME $LMGRD_OPTIONS                ;;
        "SLES") /sbin/startproc $MYAPP_HOME/bin/$NAME $LMGRD_OPTIONS ; rc_status -v ;;
      esac

      EXIT_STATUS=$?

      echo
      [ $EXIT_STATUS -eq 0 ] && touch /var/lock/subsys/$NAME;
    }

    stop()
    {
      echo -n "Stopping $NAME: "

      case "$PLATFORM" in
        "RHEL")       killproc $NAME                  ;;
        "SLES") /sbin/killproc $MYAPP_HOME/bin/$NAME  ;;
      esac

      EXIT_STATUS=$?
      # at very least, Red Hat wants the lock file removed, so we'll do it for all
      rm -f /var/lock/subsys/$NAME
      echo

      if [ "$PLATFORM" = "SLES" ]; then
        rc_status -v
      fi
    }

    getstatus()
    {
      echo -n "Checking $NAME: "

      case "$PLATFORM" in
        "RHEL")          status                 $NAME                 ;;
        "SLES") /sbin/checkproc $MYAPP_HOME/bin/$NAME ; rc_status -v  ;;
      esac

      EXIT_STATUS=$?
    }

    ShowDebugStatus()
    {
      echo "           NAME = $NAME"
      echo "  LICENSE_FILES = $LICENSE_FILES"
      echo "   LOGFILE_PATH = $LOGFILE_PATH"
      echo "  LMGRD_OPTIONS = $LMGRD_OPTIONS"
      echo "       PLATFORM = $PLATFORM"
      echo "LD_LIBRARY_PATH = $LD_LIBRARY_PATH"
      echo " daemon_running = $daemon_running"
    }

    # -----------------------------------------------------------------------------
    # Script entry point...
    # -----------------------------------------------------------------------------
    # Switch to the daemon's home directory to do all of this...
    cd $MYAPP_HOME/bin

    if [ $? -ne 0 ]; then
      echo "Unable to find $NAME's directory."
      exit 1
    fi

    # Ensure the daemon exists...
    if [ ! -x "$NAME" ]; then
      echo "$NAME could not be found."
      exit 1
    fi

    # Enforce that only root can do this...
    if [ "`id | sed 's/uid=\([0-9]*\).*/\1/'`" -ne 0 ] ; then
      echo "This script can only be run by root."
      exit
    fi

    # Cover the modern options: either way, we don't continue on. We assume a
    # minimal level of competence here: we're not idiot-proofing this script. If
    # they want help or the version, it will be the first and probably only thing
    # passed.
    arg=$1
    if [ "$arg" = "--help" ]; then
      DoUsage
      exit 0
    elif [ "$arg" = "--version" ]; then
      DoVersion
      exit 0
    fi

    # Parse command-line arguments if any: there would not usually be any.
    while getopts "hc:l:v" opt; do
      case $opt in
        h) DoUsage    ; exit 0                          ;;
        v) DoVersion  ; exit 0                          ;;
        *) echo "WARNING: Ignoring invalid option ($1)" ;;
      esac
    done

    operation=$1
    EXIT_STATUS=0

    # Determine what platform (OS) is underneath us and check to see if the daemon
    # is already running.
    SeeIfDaemonIsRunning

    # In order to have all the needed resources, we must tell the loader where to
    # look--right here in $MYAPP_HOME/bin.
    export LD_LIBRARY_PATH="`pwd`:$MYAPP_HOME/esb:$MYAPP_HOME/esb/lib"

    if [ -n "$DEBUG_LMGRD" ]; then
      ShowDebugStatus
    fi

    # Here's what we really came to do...
    case "$operation" in
      start)    # -----------------------------------------------------------------
        if [ $daemon_running -eq $FALSE ]; then
          start
        else
          echo "$NAME appears already to be running."
          if [ "$PLATFORM" = "SLES" ]; then
            rc_status -s
          fi
        fi
        ;;

      stop)     # -----------------------------------------------------------------
        if [ $daemon_running -eq $TRUE ]; then
          stop
        else
          echo "$NAME does not appear to be running."
          if [ "$PLATFORM" = "SLES" ]; then
            rc_status -s
          fi
        fi
        ;;

      restart)  # -----------------------------------------------------------------
        if [ $daemon_running -eq $TRUE ]; then
          stop
          sleep 1
        fi
        start
        EXIT_STATUS=$?
        ;;

      status)   # -----------------------------------------------------------------
        getstatus
        ;;

      *)        # -----------------------------------------------------------------
        echo "Usage: $NAME {start|stop|restart|status}"
        exit 1
    esac

    case "$PLATFORM" in
      "RHEL") exit $EXIT_STATUS ;;
      "SLES") rc_exit           ;;
    esac

Appendix: Flexera Activation Exercises

Here's how to create, generate or otherwise activate a Flexera license. It might be useful to comment on what's going on here, but I probably won't get around to it, so just pay attention. A few mistakes (later corrected) were left in for the pedigogical opportunity they create. Commands typed are in maroon, bold.

In the following, though built there, activation could not, for some reason, be accomplished on SLES, so the output from the build was copied to RHEL where it worked. The only mystery is the run directory. That's where I copied all the scripts, executables and shared-object libraries in an early attempt to isolate the files I wanted to ship from among the toolkit files.

    /* do an on-line activation here... */
    russ@sles-32:~/dev/flexera/i86_lsb> pu publisher/
    ~/dev/flexera/i86_lsb/publisher ~/dev/flexera/i86_lsb ~
    russ@sles-32:~/dev/flexera/i86_lsb/publisher> sudo ./install_fnp.sh

    We trust you have received the usual lecture from the local System
    Administrator. It usually boils down to these three things:

    	#1) Respect the privacy of others.
    	#2) Think before you type.
    	#3) With great power comes great responsibility.

    root's password:
    Installing anchor service from
    ./FNPLicensingService/FNPLicensingService to
    /usr/local/share/acresso/service/11.7.0

    Checking system for trusted storage area...
    Configuring for Linux, Trusted Storage path
    /usr/local/share/macrovision/storage...
    Creating /usr/local/share/macrovision/storage...
    Setting permissions on /usr/local/share/macrovision/storage...
    Permissions set...
    Configuration completed successfully.

    russ@sles-32:~/dev/flexera/i86_lsb/publisher> po
    ~/dev/flexera/i86_lsb ~
    russ@sles-32:~/dev/flexera/i86_lsb> echo $LD_LIBRARY_PATH

    russ@sles-32:~/dev/flexera/i86_lsb> ./serveractutil -view
    ERROR: Activation library initialization failed
    russ@sles-32:~/dev/flexera/i86_lsb> export LD_LIBRARY_PATH=`pwd`
    russ@sles-32:~/dev/flexera/i86_lsb> ./serveractutil -view
    No fulfillment records in trusted storage

    ------------------------------------------------------------------
    s@sles-32:~/dev/flexera/i86_lsb> ./serveractutil -served -comm soap -commServer \
    	http://provo-mycompany:8888/flexnet/services/ActivationService?wsdl \
    	-entitlementID act2 -concurrent 1
    Generating transfer request using:
    Entitlement ID = act2
    Expiration = 31-dec-2020
    Activatable Count = 0
    Activatable Overdraft Count = 0
    Concurrent Count = 1
    Concurrent Overdraft Count = 0
    Hybrid Count = 0
    Hybrid Overdraft Count = 0
    Repair Count = 0
    Status: 4, Creating request
    Status: 5, Request created
    ERROR: flxActSvrActivationSend - (0,0,0)


    -----------------------------------------------------------------

    /* now turn to Red Hat Enterprise Linux... */

    s@rhel-32:~/dev/run> ./serveractutil -served -comm soap -commServer \
    	http://provo-mycompany:8888/flexnet/services/ActivationService?wsdl \
    	-entitlementID act2 -concurrent 1
    Generating transfer request using:
         	Entitlement ID = act2
         	Expiration = 31-dec-2020
         	Activatable Count = 0
         	Activatable Overdraft Count = 0
         	Concurrent Count = 1
         	Concurrent Overdraft Count = 0
         	Hybrid Count = 0
         	Hybrid Overdraft Count = 0
         	Repair Count = 0
    Status: 4, Creating request
    Status: 5, Request created
    Status: 6, Context created
    Status: 7, Connected to remote server
    Status: 8, Request Sent
    Status: 9, Polling for response
    Status: 10, Waiting for response
    Status: 9, Polling for response
    Status: 11, Done
    Status: 6, Context created
    Status: 7, Connected to remote server
    Status: 8, Request Sent
    Status: 9, Polling for response
    Status: 10, Waiting for response
    Status: 9, Polling for response
    Status: 11, Done
    TRANSFER REQUEST SUCCESSFULLY PROCESSED



    --------------------------------------------------------------------
    Trust Flags: FULLY TRUSTED
    Fulfillment Type: PUBLISHER ACTIVATION
    Status: ENABLED
    Fulfillment ID: FID_78cfb529_12677ca0665__7fef
    Entitlement ID: act2
    Product ID: NAME=myapp;VERSION=3.1
    Suite ID: NONE
    Expiration date: 14-Mar-2010
    Concurrent: 1
    Concurrent overdraft:0
    Hybrid: 0
    Hybrid overdraft: 0
    Activatable: 0
    Activatable overdraft: 0
    Repairs: 0
    Feature line(s):
    INCREMENT MYAPP_Datastore mycompany 3.1 14-mar-2010 1 DUP_GROUP=V \
        	ISSUED=29-jan-2010 START=28-jan-2010 SIGN="010A 58C3 66EA E9E1 \
        	AAA1 6152 1922 0049 8752 1A24 3B5E 0C15 9487 6280 5932 18EB \
        	8B85 628E 22C6 6126 7909 30E5 410A 27BB A9DF B96B 3E70 9A51 \
        	339A D86C"
    INCREMENT MYAPP_Console mycompany 3.1 14-mar-2010 1 DUP_GROUP=NONE \
        	ISSUED=29-jan-2010 START=28-jan-2010 SIGN="15A9 BD07 7E59 A2D1 \
        	8F32 86A7 67F0 0ACE 30D1 D95A 81AA 7E4A C31F 1A06 A761 1E45 \
        	6DFF 53D5 6450 813D CC04 8FD6 3B37 79D9 47D4 AE1A 6971 C580 \
        	0D6B AAAE"
    INCREMENT MYAPP_Reporting mycompany 3.1 14-mar-2010 3 DUP_GROUP=V \
        	ISSUED=29-jan-2010 START=28-jan-2010 SIGN="17BB 6BB1 0D66 2165 \
        	7388 9DD9 23CF 765A DDB3 02C4 FF97 F71F 27D7 1E7F 6BE5 0454 \
        	2F77 1FBD B3DA 88CE 64CE 1A62 D7AA 7ADF 3773 1B44 1CFE D62E \
        	A450 6822"
    INCREMENT RussFeature mycompany 2 14-mar-2010 1 DUP_GROUP=UV \
        	ISSUED=29-jan-2010 START=28-jan-2010 SIGN="0A22 10E6 0004 D486 \
        	BCF1 9FD1 A347 D6FE 0637 EB8D 4313 C3B3 3539 155E 9BB5 0712 \
        	D775 A6B4 A3A5 2EFA 72A1 4325 F5C5 4E39 1213 88F0 F81F 510F \
        	992D 58DC"
    --------------------------------------------------------------------

    s@rhel-32:~/dev/run> ./serveractutil -return FID_78cfb529_12677ca0665__7fef \
    	-comm soap -commServer http://provo-mycompany:8888/flexnet/services/ActivationService?wsdl
    russ@rhel-32:~/dev/run> ./serveractutil -view


    russ@sles-32:~/dev/flexera/i86_lsb> ./serveractutil -view
    ERROR: Activation library initialization failed
    russ@sles-32:~/dev/flexera/i86_lsb> export LD_LIBRARY_PATH=/home/russ/dev/flexera/i86_lsb


    /* manual activation... */
    russ@rhel-32:~/dev/run> ./serveractutil -served -entitlementID act1 -concurrent 1 \
    	-gen manual-activation.xml
    ERROR: Activation library initialization failed
    russ@rhel-32:~/dev/run> export LD_LIBRARY_PATH=/home/russ/dev/run
    russ@rhel-32:~/dev/run> ./serveractutil -served -entitlementID act1 -concurrent 1 \
    	-gen manual-activation.xml
    Generating transfer request using:
        	Entitlement ID = act1
        	Expiration = 31-dec-2020
        	Activatable Count = 0
        	Activatable Overdraft Count = 0
        	Concurrent Count = 1
        	Concurrent Overdraft Count = 0
        	Hybrid Count = 0
        	Hybrid Overdraft Count = 0
        	Repair Count = 0

    Writing signed activation request to manual-activation.xml
    russ@rhel-32:~/dev/run> ll
    total 61624
    -rwxr-xr-x 1 russ russ 5753384 Jan 29 11:52 appactutil_libFNP.so
    -rwxr-xr-x 1 russ russ 5753184 Jan 29 11:53 mycompany_libFNP.so
    -rwxr-xr-x 1 russ russ 5753176 Jan 29 11:52 demo_libFNP.so
    -rwxr-xr-x 1 russ russ 5752892 Jan 29 11:52 ezcalc_libFNP.so
    -rwxr-xr-x 1 russ russ 5778304 Jan 29 11:53 ezcalcsdt_libFNP.so
    -rwxr-xr-x 1 russ russ 1422072 Jan 29 11:52 FnpCommsSoap.so
    drwxr-xr-x 2 russ russ    4096 Jan 29 11:52 FNPLicensingService
    -rwxr-xr-x 1 russ russ    2303 Jan 29 11:52 install_fnp.sh
    -rwxr-xr-x 1 russ russ 2802144 Jan 29 11:52 libresponsegen.so
    -rwxr-xr-x 1 russ russ 5752868 Jan 29 11:53 libtsJavaAcc_libFNP.so
    -rwxr-xr-x 1 russ russ  109768 Jan 29 11:52 libtsJavaAcc.so
    -rwxr-xr-x 1 russ russ 5753284 Jan 29 11:52 lmflex_libFNP.so
    -rw-rw-r-- 1 russ russ    1860 Feb  1 09:46 manual-activation.xml
    -rwxr-xr-x 1 russ russ  959165 Jan 29 14:39 serveractutil
    -rwxr-xr-x 1 russ russ 5753008 Jan 29 11:52 serveractutil_libFNP.so
    -rwxr-xr-x 1 russ russ 5748728 Jan 29 11:52 tsreset_app_libFNP.so
    -rwxr-xr-x 1 russ russ 5748720 Jan 29 11:52 tsreset_svr_libFNP.so

At this point (in the manual activation), I turned to the browser at address http://provo-mycompany:8888, username/password admin/admin, then clicked on the Activate Licenses tab, then Trusted Activations -> Manual Activation, then I uploaded the manual activation I got (manual-activation.xml) and saved the result to file responseXML.xml (which was the proposed default). Then, I ran another command as shown here, then finally checked to see if a license was there (and viewable) as usual:

    russ@rhel-32:~/dev/run> ./serveractutil -process responseXML.xml

    Reading request from responseXML.xml
    SUCCESSFULLY PROCESSED RESPONSE
    russ@rhel-32:~/dev/run> ./serveractutil -view

    --------------------------------------------------------------------
    Trust Flags: FULLY TRUSTED
    Fulfillment Type: PUBLISHER ACTIVATION
    Status: ENABLED
    Fulfillment ID: FID_10900660_1268a6250b0__7ffa
    Entitlement ID: act1
    Product ID: NAME=myapp;VERSION=3.1
    Suite ID: NONE
    Expiration date: 17-Mar-2010
    Concurrent: 1
    Concurrent overdraft:0
    Hybrid: 0
    Hybrid overdraft: 0
    Activatable: 0
    Activatable overdraft: 0
    Repairs: 0
    Feature line(s):
    INCREMENT MYAPP_Datastore mycompany 3.1 17-mar-2010 1 DUP_GROUP=V \
        	ISSUED=1-feb-2010 START=31-jan-2010 SIGN="0BA9 BFE4 CC75 66A8 \
        	2BE2 3571 C844 A957 B0A9 B609 F619 2969 59D0 6FDB 30E7 0D43 \
        	460F AE79 3F74 4D22 9A36 E726 7794 8D41 9A9A 51BD E278 97EF \
        	E920 7F73"
    INCREMENT MYAPP_Console mycompany 3.1 17-mar-2010 1 DUP_GROUP=NONE \
        	ISSUED=1-feb-2010 START=31-jan-2010 SIGN="1A7C 6982 51BD 800D \
        	C8DF 5D57 5E70 413E 2C84 1024 5DA1 9BB9 1515 BE44 09D7 1020 \
        	8F5F 658F D90C DF2B 5A0D 7F4B 86D7 1EAC BA8F 5A4D 4221 E227 \
        	26A6 3FF2"
    INCREMENT MYAPP_Reporting mycompany 3.1 17-mar-2010 3 DUP_GROUP=V \
        	ISSUED=1-feb-2010 START=31-jan-2010 SIGN="00B9 6F94 DC04 0336 \
        	A4D7 3A02 E212 F8D8 1F94 AA16 E7D6 9667 58E7 67B6 6E1C 1FC5 \
        	95DB E215 2DB0 9925 4993 5F00 B6BD 4F2D 93EB E6E4 F2B0 42C3 \
        	9E5B DFA9"
    INCREMENT RussFeature mycompany 2 17-mar-2010 1 DUP_GROUP=UV \
        	ISSUED=1-feb-2010 START=31-jan-2010 SIGN="06CB A443 88C0 EBE7 \
        	7A79 52C7 C36E 5ED0 A9B7 1E13 6521 AEE8 E758 3828 C4AB 1F18 \
        	0963 A34E F533 20B6 F84E 2292 D4FC EB11 20CD 6CB3 102E 89C9 \
        	A4E0 84AE"
    --------------------------------------------------------------------

Successful license activation

Here is an illustration of successful, SOAP-based license activation as viewed from soapUI.


Appendix: Build directory file listings

Directory listing of i86_lsb after make -f makefile.act clean. So, these are the fundamental files (that are not created by the make process):

    russ@rhel-32:~/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> ll
    total 76816
    drwxrwxr-x 5 russ russ     4096 Mar  3 14:09 activation
    drwxrwxr-x 3 russ russ     4096 Mar  3 14:09 ActivationSettings
    -rw-rw-r-- 1 russ russ    43253 Mar 16 08:37 aksusbd-redhat-1.8.1-3.i386.rpm
    -rw-rw-r-- 1 russ russ    44154 Mar 16 08:37 aksusbd-suse-1.8.1-3.i386.rpm
    -rwxr-xr-x 1 russ russ  5753116 Mar 18 10:26 appactutil_libFNP.so
    -rw-rw-r-- 1 russ russ    53704 Mar 18 10:25 appActUtil.o
    -rw-rw-r-- 1 russ russ     8272 Mar  3 14:09 asrgen.o
    -rwxr-xr-x 1 russ russ  5752932 Mar 18 10:26 mycompany_libFNP.so
    -rw-rw-r-- 1 russ russ      180 Mar  3 14:09 counted.lic
    -rw-rw-r-- 1 russ russ    26688 Mar  3 14:09 cvdconfig
    -rw-rw-r-- 1 russ russ  1062140 Mar  3 14:09 demo
    -rw-rw-r-- 1 russ russ  5753176 Mar  3 14:09 demo_libFNP.so
    -rw-rw-r-- 1 russ russ      143 Mar  3 14:09 expired.lic
    -rw-rw-r-- 1 russ russ    15202 Mar 18 10:25 libcrvs.a
    -rw-rw-r-- 1 russ russ    15250 Mar 18 10:25 libcrvs_pic.a
    -rw-rw-r-- 1 russ russ   105724 Mar 18 10:25 libFNPload.a
    -rw-rw-r-- 1 russ russ   116024 Mar 18 10:25 libFNPload_pic.a
    -rw-rw-r-- 1 russ russ  1025428 Mar 18 10:25 liblmgr.a
    -rw-rw-r-- 1 russ russ   357998 Mar 18 10:25 liblmgr_as.a
    -rw-rw-r-- 1 russ russ   159984 Mar 18 10:25 liblmgrd.a
    -rw-rw-r-- 1 russ russ  1937928 Mar 18 10:25 liblmgr_dongle.a
    -rw-rw-r-- 1 russ russ     1106 Mar 18 10:25 liblmgr_dongle_stub.a
    -rw-rw-r-- 1 russ russ  1024124 Mar 18 10:25 liblmgr_nomt.a
    -rw-rw-r-- 1 russ russ  1101088 Mar 18 10:25 liblmgr_nomt_pic.a
    -rw-rw-r-- 1 russ russ  1093784 Mar 18 10:25 liblmgr_nomt_pic_trl.a
    -rw-rw-r-- 1 russ russ  1017236 Mar 18 10:25 liblmgr_nomt_trl.a
    -rw-rw-r-- 1 russ russ  1102312 Mar 18 10:25 liblmgr_pic.a
    -rw-rw-r-- 1 russ russ  1095008 Mar 18 10:25 liblmgr_pic_trl.a
    -rw-rw-r-- 1 russ russ   112308 Mar 18 10:25 liblmgr_s.a
    -rw-rw-r-- 1 russ russ  1018540 Mar 18 10:25 liblmgr_trl.a
    -rw-rw-r-- 1 russ russ   186172 Mar 18 10:25 liblmutil.a
    -rw-rw-r-- 1 russ russ   883470 Mar 18 10:25 libsb.a
    -rw-rw-r-- 1 russ russ   930958 Mar 18 10:25 libsb_pic.a
    -rw-rw-r-- 1 russ russ  5752868 Mar  3 14:09 libtsJavaAcc_libFNP.so
    -rw-rw-r-- 1 russ russ   109768 Mar  3 14:09 libtsJavaAcc.so
    drwxrwxr-x 9 russ russ     4096 Mar 11 10:59 lmadmin
    -rwxr-xr-x 1 russ russ  5753256 Mar 18 10:25 lmflex_libFNP.so
    -rwxrwxr-x 1 russ russ   874068 Mar  3 14:09 lmgrd
    -rw-rw-r-- 1 russ russ    38044 Mar  3 14:09 lmnewgen.o
    -rwxrwxr-x 1 russ russ   140748 Mar  3 14:09 lmrand1
    -rw-rw-r-- 1 russ russ    18328 Mar 18 10:26 lmsign.o
    -rwxrwxr-x 1 russ russ   104388 Mar  3 14:09 lmstrip
    -rwxrwxr-x 1 russ russ  1001868 Mar 18 10:25 lmutil
    -rw-rw-r-- 1 russ russ     1063 Mar  3 14:09 ls_getActivationsStub.o
    -rw-rw-r-- 1 russ russ     6206 Mar  3 14:09 makefile
    -rw-rw-r-- 1 russ russ     9386 Mar  3 14:09 makefile.act
    -rw-rw-r-- 1 russ russ 11508058 Mar  3 14:09 preparchive_11.7.0.yaa
    -rwxrwxr-x 1 russ russ  2607680 Mar  3 14:09 preptool
    drwxrwxr-x 7 russ russ     4096 Mar 15 09:40 publisher
    -rw-rw-r-- 1 russ russ    30856 Mar 18 10:26 sdtdata.o
    -rw-rw-r-- 1 russ russ     3672 Mar 18 10:26 sdtdefs.o
    -rwxr-xr-x 1 russ russ  5753412 Mar 18 10:26 serveractutil_libFNP.so
    -rw-rw-r-- 1 russ russ    44276 Mar 18 10:26 serverActUtil.o
    -rwxr-xr-x 1 russ russ   495400 Mar 18 10:25 tsreset_app
    -rwxr-xr-x 1 russ russ  5748512 Mar 18 10:25 tsreset_app_libFNP.so
    -rwxr-xr-x 1 russ russ   495400 Mar 18 10:25 tsreset_svr
    -rwxr-xr-x 1 russ russ  5748592 Mar 18 10:25 tsreset_svr_libFNP.so
    -rw-rw-r-- 1 russ russ      141 Mar  3 14:09 uncounted.lic

After make -f makefile.act:

    russ@rhel-32:~/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> ll
    total 98200
    drwxrwxr-x 5 russ russ     4096 Mar  3 14:09 activation
    drwxrwxr-x 3 russ russ     4096 Mar  3 14:09 ActivationSettings
    -rw-rw-r-- 1 russ russ    43253 Mar 16 08:37 aksusbd-redhat-1.8.1-3.i386.rpm
    -rw-rw-r-- 1 russ russ    44154 Mar 16 08:37 aksusbd-suse-1.8.1-3.i386.rpm
    -rwxr-xr-x 1 russ russ   955081 Mar 18 10:25 appactutil
    -rwxr-xr-x 1 russ russ  5753116 Mar 18 10:26 appactutil_libFNP.so
    -rw-rw-r-- 1 russ russ    53704 Mar 18 10:25 appActUtil.o
    -rwxrwxr-x 1 russ russ   719724 Mar 18 10:26 asrgen
    -rw-rw-r-- 1 russ russ     8272 Mar  3 14:09 asrgen.o
    -rwxr-xr-x 1 russ russ  1043436 Mar 18 10:26 mycompany
    -rwxr-xr-x 1 russ russ  5752932 Mar 18 10:26 mycompany_libFNP.so
    -rw-rw-r-- 1 russ russ      180 Mar  3 14:09 counted.lic
    -rw-rw-r-- 1 russ russ    26688 Mar  3 14:09 cvdconfig
    -rw-rw-r-- 1 russ russ  1062140 Mar  3 14:09 demo
    -rw-rw-r-- 1 russ russ  5753176 Mar  3 14:09 demo_libFNP.so
    -rw-rw-r-- 1 russ russ      143 Mar  3 14:09 expired.lic
    -rwxr-xr-x 1 russ russ   882776 Mar 18 10:26 ezcalc
    -rwxr-xr-x 1 russ russ  5753028 Mar 18 10:26 ezcalc_libFNP.so
    -rw-rw-r-- 1 russ russ    25500 Mar 18 10:26 ezcalc.o
    -rwxr-xr-x 1 russ russ   918923 Mar 18 10:26 ezcalcsdt
    -rwxr-xr-x 1 russ russ  5778552 Mar 18 10:26 ezcalcsdt_libFNP.so
    -rw-rw-r-- 1 russ russ    31644 Mar 18 10:26 ezcalcsdt.o
    -rw-rw-r-- 1 russ russ    15202 Mar 18 10:25 libcrvs.a
    -rw-rw-r-- 1 russ russ    15250 Mar 18 10:25 libcrvs_pic.a
    -rw-rw-r-- 1 russ russ   105724 Mar 18 10:25 libFNPload.a
    -rw-rw-r-- 1 russ russ   116024 Mar 18 10:25 libFNPload_pic.a
    -rw-rw-r-- 1 russ russ  1025428 Mar 18 10:25 liblmgr.a
    -rw-rw-r-- 1 russ russ   357998 Mar 18 10:25 liblmgr_as.a
    -rw-rw-r-- 1 russ russ   159984 Mar 18 10:25 liblmgrd.a
    -rw-rw-r-- 1 russ russ  1937928 Mar 18 10:25 liblmgr_dongle.a
    -rw-rw-r-- 1 russ russ     1106 Mar 18 10:25 liblmgr_dongle_stub.a
    -rw-rw-r-- 1 russ russ  1024124 Mar 18 10:25 liblmgr_nomt.a
    -rw-rw-r-- 1 russ russ  1101088 Mar 18 10:25 liblmgr_nomt_pic.a
    -rw-rw-r-- 1 russ russ  1093784 Mar 18 10:25 liblmgr_nomt_pic_trl.a
    -rw-rw-r-- 1 russ russ  1017236 Mar 18 10:25 liblmgr_nomt_trl.a
    -rw-rw-r-- 1 russ russ  1102312 Mar 18 10:25 liblmgr_pic.a
    -rw-rw-r-- 1 russ russ  1095008 Mar 18 10:25 liblmgr_pic_trl.a
    -rw-rw-r-- 1 russ russ   112308 Mar 18 10:25 liblmgr_s.a
    -rw-rw-r-- 1 russ russ  1018540 Mar 18 10:25 liblmgr_trl.a
    -rw-rw-r-- 1 russ russ    18482 Mar 18 10:26 liblmsign.a
    -rw-rw-r-- 1 russ russ   186172 Mar 18 10:25 liblmutil.a
    -rw-rw-r-- 1 russ russ   883470 Mar 18 10:25 libsb.a
    -rw-rw-r-- 1 russ russ   930958 Mar 18 10:25 libsb_pic.a
    -rw-rw-r-- 1 russ russ  5752868 Mar  3 14:09 libtsJavaAcc_libFNP.so
    -rw-rw-r-- 1 russ russ   109768 Mar  3 14:09 libtsJavaAcc.so
    drwxrwxr-x 9 russ russ     4096 Mar 11 10:59 lmadmin
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmborrow -> lmutil
    -rw-rw-r-- 1 russ russ     1173 Mar 18 10:26 lmcode.c
    -rw-rw-r-- 1 russ russ     4820 Mar 18 10:26 lmcode.o
    -rwxrwxr-x 1 russ russ   719894 Mar 18 10:25 lmcrypt
    -rw-rw-r-- 1 russ russ    28812 Mar 18 10:25 lmcrypt.o
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmdiag -> lmutil
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmdown -> lmutil
    -rwxr-xr-x 1 russ russ   747400 Mar 18 10:25 lmflex
    -rwxr-xr-x 1 russ russ  5753256 Mar 18 10:25 lmflex_libFNP.so
    -rwxrwxr-x 1 russ russ   874068 Mar  3 14:09 lmgrd
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmhostid -> lmutil
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lminstall -> lmutil
    -rw-rw-r-- 1 russ russ   163877 Mar 18 10:26 lm_new.c
    -rwxrwxr-x 1 russ russ   738576 Mar 18 10:26 lmnewgen
    -rw-rw-r-- 1 russ russ    38044 Mar  3 14:09 lmnewgen.o
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmnewlog -> lmutil
    -rw-rw-r-- 1 russ russ    91980 Mar 18 10:26 lm_new_pic.o
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmpath -> lmutil
    -rw-rw-r-- 1 russ russ      617 Mar 18 10:26 lmprikey.h
    -rwxrwxr-x 1 russ russ   140748 Mar  3 14:09 lmrand1
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmremove -> lmutil
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmreread -> lmutil
    -rw-rw-r-- 1 russ russ      241 Mar 18 10:26 lmseeds.h
    -rw-rw-r-- 1 russ russ    18328 Mar 18 10:26 lmsign.o
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmstat -> lmutil
    -rwxrwxr-x 1 russ russ   104388 Mar  3 14:09 lmstrip
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmswitch -> lmutil
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmswitchr -> lmutil
    -rwxrwxr-x 1 russ russ  1001868 Mar 18 10:25 lmutil
    lrwxrwxrwx 1 russ russ        6 Mar 18 10:26 lmver -> lmutil
    -rw-rw-r-- 1 russ russ     1063 Mar  3 14:09 ls_getActivationsStub.o
    -rw-rw-r-- 1 russ russ    15036 Mar 18 10:26 lsvendor.o
    -rw-rw-r-- 1 russ russ     6206 Mar  3 14:09 makefile
    -rw-rw-r-- 1 russ russ     9386 Mar  3 14:09 makefile.act
    -rw-rw-r-- 1 russ russ 11508058 Mar  3 14:09 preparchive_11.7.0.yaa
    -rwxrwxr-x 1 russ russ  2607680 Mar  3 14:09 preptool
    drwxrwxr-x 7 russ russ     4096 Mar 15 09:40 publisher
    -rw-rw-r-- 1 russ russ    30856 Mar 18 10:26 sdtdata.o
    -rw-rw-r-- 1 russ russ     3672 Mar 18 10:26 sdtdefs.o
    -rwxr-xr-x 1 russ russ   939401 Mar 18 10:26 serveractutil
    -rwxr-xr-x 1 russ russ  5753412 Mar 18 10:26 serveractutil_libFNP.so
    -rw-rw-r-- 1 russ russ    44276 Mar 18 10:26 serverActUtil.o
    -rwxr-xr-x 1 russ russ   495400 Mar 18 10:25 tsreset_app
    -rwxr-xr-x 1 russ russ  5748512 Mar 18 10:25 tsreset_app_libFNP.so
    -rwxr-xr-x 1 russ russ   495400 Mar 18 10:25 tsreset_svr
    -rwxr-xr-x 1 russ russ  5748592 Mar 18 10:25 tsreset_svr_libFNP.so
    -rw-rw-r-- 1 russ russ      141 Mar  3 14:09 uncounted.lic

The delta (file products built) is:

    appactutil
    asrgen
    mycompany (vendor dæmon)
    ezcalc
    ezcalc_libFNP.so
    ezcalc.o
    ezcalcsdt
    ezcalcsdt_libFNP.so
    ezcalcsdt.o
    liblmsign.a
    lmborrow
    lmcode.c
    lmcode.o
    lmcrypt
    lmcrypt.o
    lmdiag
    lmdown
    lmflex
    lmhostid
    lminstall
    lm_new.c
    lmnewgen
    lmnewlog
    lm_new_pic.o
    lmpath
    lmprikey.h
    lmremove
    lmreread
    lmseeds.h
    lmstat
    lmswitch
    lmswitchr
    lmver
    lsvendor.o
    serveractutil

Remember that lm_new.o is explicitly tossed by the makefile after it's done with it. If you need this file, you'll want to rebuild it again in your makefile. See below.


Appendix: Application makefile

So, imagine you're building all of this Flexera stuff into an executable that's going to be your application or, as in my case, my shared-object JNI. Here's what I did:

    #------------------------------------------------------------------------------
    # JNI makefile
    #
    # This makefile depends on environment variables being set:
    #
    # MYAPP_BLD_TOOLS - is defined relative to which it can find the Linux Toolkit
    # JAVA_HOME       - must be set to the JDK myapp is consuming
    # -----------------------------------------------------------------------------
    # Notes:
    #
    # This is the common-included portion of the shared-object makefiles. The macro
    # WHICH sorts out the distinction between the app and svr flavors.
    #
    # __stack_chk_fail_local() goes missing and inhibits the shared-object
    # libraries created by this makefile from loading. Unable to find a suitable
    # library to link, I tried to avoid the generation of a call to check for
    # stack-smashing by using the -fno-stack-protector option, however, this did
    # not work. So, linuxjni.c contains a no-op implementation of the symbol.
    #
    # Comment out $(STRIP) as the .so is built to make it possible to diagnose
    # reported missing symbols. This is a problem that crops up all too often.
    # Unless you eliminate symbol obfuscation, the missing symbol reported will
    # have all the clarity of "Symbol is missing: zzyzzx."
    #
    # How to get preprocessor output from g++ for helping to find and fix syntax
    # errors? Do this:
    #
    #    g++ -E $(CPPFLAGS) -c foo.c > foo.E
    #------------------------------------------------------------------------------
    LINUXDIR = ..

    ifdef MYAPP_BLD_TOOLS
    # This is formal build of myapp...
    TOOLKIT    = $(MYAPP_BLD_TOOLS)/../flexera/fnptoolkit/11.7.0
    LINUXDIR   = $(TOOLKIT)/linux/i86
    SHAREDDIR  = $(TOOLKIT)/shared/i86
    endif

    # Hand-resolve missing symbols! Originally, this software was being built on
    # SLES 11 and used on both SLES and RHEL. In order to satisfy symbols, tricks
    # had to be played with static libraries or the .so would not always load. Here
    # is the main trick:
    GCCLIBDIR  = /usr/lib/gcc/i586-suse-linux/4.3
    #GCCLIBDIR = /usr/lib/gcc/i386-redhat-linux/4.1.2 (if trying on RHEL)

    PREPTOOL   = $(LINUXDIR)/i86_lsb/preptool -v
    STRIP      = $(LINUXDIR)/i86_lsb/lmstrip

    ACTLIBDIR  = $(LINUXDIR)/i86_lsb/activation/lib
    DOTDIR     = $(LINUXDIR)/i86_lsb
    ACTLIB     = $(ACTLIBDIR)/libact.a
    CLIENTLIB  = $(DOTDIR)/liblmgr.a $(DOTDIR)/libcrvs.a $(DOTDIR)/libsb.a \
                 $(DOTDIR)/liblmgr_dongle_stub.a
    FNPLOADLIB = $(DOTDIR)/libFNPload.a
    XTRALIB    = -ldl
    THREADLIB  = -lpthread
    CPPLIB     = $(GCCLIBDIR)/libstdc++.a
    LIBRARIES  = $(ACTLIB) $(CLIENTLIB) $(FNPLOADLIB) $(XTRALIB) $(THREADLIB) \
                 $(CPPLIB)
    LM_NEW     = lm_new.o

    INCLUDES   = $(LINUXDIR)/machind/activation/include
    CFLAGS     = -I $(INCLUDES) -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I . -DLINUX
    CPPFLAGS   = -I $(INCLUDES) -I $(JAVA_HOME)/include -I $(JAVA_HOME)/include/linux -I . -DLINUX

    # (Uncomment symbol-stripping when it's time to release so our symbols are
    # obfuscated. In the meantime, we need to see the reals names so we can fix
    # them.)
    libmyapplicact$(WHICH).so:  linuxjni.o lm_new.o myapplicact$(WHICH).o licActCommon.o
        ld -shared -soname $@ -o $@  linuxjni.o lm_new.o myapplicact$(WHICH).o licActCommon.o  -lc \
        $(LIB_PATHS) $(LIBRARIES)
        cp $(SHAREDDIR)/publisher.xml ../Release
        cp $@    ../Release
        #$(STRIP) ../Release/$@
        ( cd ../Release ;                                \
           $(PREPTOOL)                                   \
           -p $(LINUXDIR)/i86_lsb/preparchive_11.7.0.yaa \
           ../conf/myapplicact$(WHICH)_so.xml )

    myapplicact$(WHICH).o:      myapplicact$(WHICH).cpp ../common/stdafx.h ../common/linuxjni.h
        gcc $(CFLAGS) -fPIC -c $<

    linuxjni.o:              ../common/linuxjni.c
        gcc $(CFLAGS) -fPIC -c $<

    licActCommon.o:          ../common/licActCommon.cpp ../common/stdafx.h \
        com_mycompany_myapp_licensing_fn_utilities_ActivationUtility$(WHICH)JNI.h
        g++ $(CPPFLAGS) -fPIC -c $<

    # We have to rebuild lm_new.o specially since the toolkit build deletes it at
    # the end.
    lm_new.o:
        ( cd $(TOOLKIT)/linux/i86/i86_lsb ; \
           $(MAKE) lm_new.o ;               \
           cp lm_new.o $(CURDIR) ;          \
           rm -f lm_new.o )

    linuxjni.c:    ../common/linuxjni.h

    com_mycompany_myapp_licensing_fn_utilities_ActivationUtility$(WHICH)JNI.h:

    .PHONY: clean \
        com_mycompany_myapp_licensing_fn_utilities_ActivationUtility$(WHICH)JNI.h

    clean:
        rm -f *.so *.o

List of shared-object libraries

These are the shared-object libraries to ship and whose parents must be included in the LD_LIBRARY_PATH specified when the lmgrd service is launched (see dæmon script). As might be apparent now, my application makes use of Apache ServiceMix.

    root@rhel-32:/opt/mycompany/myapp/bin> ll *.so
    -rwxrwxr-x 1 root root 5753080 Mar 24 05:01 appactutil_libFNP.so
    -rwxr-xr-x 1 root root 5753064 Mar 24 12:39 lmflex_libFNP.so

    -rwxrwxr-x 1 root root 5753340 Mar 24 05:00 mycompany_libFNP.so
    -rwxrwxr-x 1 root root 1422072 Mar 24 05:01 FnpCommsSoap.so
    -rwxrwxr-x 1 root root 5753228 Mar 24 05:00 serveractutil_libFNP.so

    root@rhel-32:/opt/mycompany/myapp/esb> ll *.so
    -rwxrwxr-x 1 root root 5752868 Mar 24 05:01 libtsJavaAcc_libFNP.so
    -rwxrwxr-x 1 root root  109768 Mar 24 05:01 libtsJavaAcc.so

    root@rhel-32:/opt/mycompany/myapp/esb/lib> ll *.so
    -rwxrwxr-x 1 root root 1422072 Mar 24 05:00 FnpCommsSoap.so
    -rwxrwxr-x 1 root root 5752844 Mar 24 05:01 libmyapplicactapp_libFNP.so (JNI support)
    -rwxrwxr-x 1 root root 1339278 Mar 24 05:01 libmyapplicactapp.so (JNI)
    -rwxrwxr-x 1 root root 5753384 Mar 24 05:01 libmyapplicactsvr_libFNP.so (JNI support)
    -rwxrwxr-x 1 root root 1376293 Mar 24 05:01 libmyapplicactsvr.so (JNI)
    -rwxrwxr-x 1 root root 5752868 Mar 24 05:00 libtsJavaAcc_libFNP.so
    -rwxrwxr-x 1 root root  109768 Mar 24 05:00 libtsJavaAcc.so
    -rwxrwxr-x 1 root root   11887 Mar 24 05:00 libwrapper.so

The Flexera toolkit thinks the list of shared-object libraries is (the find output has been seriously massaged here)...

    russ@rhel-32:~/myapp/flexera/fnptoolkit/11.7.0/linux/i86/i86_lsb> find . -name '*.so' -print
                 ./serveractutil_libFNP.so
                 ./libtsJavaAcc_libFNP.so
                 ./lmflex_libFNP.so
                 ./libtsJavaAcc.so
                 ./appactutil_libFNP.so
                 ./mycompany_libFNP.so
       ./publisher/FnpCommsSoap.so
       ./publisher/libresponsegen.so
                 ./demo_libFNP.so
                 ./tsreset_app_libFNP.so
    ./lmadmin/demo/demo_libFNP.so
                 ./tsreset_svr_libFNP.so

Ship the ones in green There is no reason to ship the Flexera demonstration stuff (demo_libFNP.so, etc.). Don't ship the trusted-storage reset utility as your customers will become very grumpy if they ever use it accidentally. Didn't need to ship libresponsegen.so (and don't know why).