Saturday, July 18, 2020

OpenVMS: Purge/Delete Expired Licenses and Clean Up LMF DB License Database

Supratim Sanyal's Blog: OpenVMS VAX License PAK


This is a thread from the comp.os.vms newsgroup. The archived conversation is at:


---

comp.os.vms ›
LICENSE PURGE ?
7 posts by 6 authors 

Peter LANGSTOEGER
3/14/01
Since the VMS hobbyist program is there (many thanks for that !!), I have
a bunch of licenses loaded which starts to terminate now. And I start to
feel tired of deleting yet another expired license...
Is there a LMF command to delete all expired licenses at once ?

--
Peter "EPLAN" LANGSTOEGER           Tel.    +43 1 81111-2651
Network and OpenVMS system manager  Fax.    +43 1 81111-888
<<< KAPSCH AG  Wagenseilgasse 1     E-mail  ep...@kapsch.net
A-1121 VIENNA  AUSTRIA              "I'm not a pessimist, I'm a realist"

Click here to Reply

Martin Vorlaender
3/14/01
Peter LANGSTOEGER (ep...@kapsch.net) wrote:
> Since the VMS hobbyist program is there (many thanks for that !!), I have
> a bunch of licenses loaded which starts to terminate now. And I start to
> feel tired of deleting yet another expired license...
>
> Is there a LMF command to delete all expired licenses at once ?
I solved (or circumvented) that problem by issuing a $ LICENSE CREATE
before executing the command procedures that register the new hobbyist
licenses. But then, the hobbyist licenses are the only ones on my system.

I guess one could write a quick perl script to look over OPERATOR.LOG
and issue appropriate $ LICENSE DELETE commands.

cu,
  Martin
--
One OS to rule them all       | Martin Vorlaender  |  VMS & WNT programmer
One OS to find them           | work: m...@pdv-systeme.de
One OS to bring them all      |   http://www.pdv-systeme.de/users/martinv/
And in the Darkness bind them.| home: mar...@radiogaga.harz.de


Hunter Goatley
3/14/01
On 15 Mar 2001 00:45:53 +0100, ep...@kapsch.net (Peter LANGSTOEGER) wrote:
>Since the VMS hobbyist program is there (many thanks for that !!), I have
>a bunch of licenses loaded which starts to terminate now. And I start to
>feel tired of deleting yet another expired license...
>
>Is there a LMF command to delete all expired licenses at once ?
>
$ delete sys$system:lmf$license.ldb;*
A bit drastic, but it works.

$ LICENSE DELETE *

also works, but, again, is a bit drastic.  Less drastic, and one
that will probably do exactly what you want (delete the hobbyist
licenses and leave any other intact):

$ LICENSE DELETE */AUTHORIZATION=DECUS-USA-*

or whatever common authorization string they have.

Or:

$ LICENSE DISABLE */AUTHOR=DECUS-USA-*
$ LICENSE DELETE */STATUS=DISABLED

Hunter
------
Hunter Goatley, Process Software, http://www.process.com/
goath...@goatley.com     http://www.goatley.com/hunter/


Robert Deininger
3/15/01
In article <3ab0...@news.kapsch.co.at>, ep...@kapsch.net wrote:
> Since the VMS hobbyist program is there (many thanks for that !!), I have
> a bunch of licenses loaded which starts to terminate now. And I start to
> feel tired of deleting yet another expired license...
>
> Is there a LMF command to delete all expired licenses at once ?
There's a LICENSE DELETE/STATUS=DISABLED
There's a LICENSE LIST/BEFORE/TERMINATION
Alas, there's no LICENSE DELETE/BEFORE/TERMINATION

I've made a command file that parses the output of
   LICENSE LIST/FULL/BEFORE/TERM,
generates a bunch of LICENSE DISABLE commands, and does
   LICENSE DELETE/STATUS=DISABLED.

This will get rid of terminated licenses and leave the others intact.

I can email or post the command file if there's interest.

--
Robert Deininger
rdein...@mindspring.com


Robert Deininger
3/15/01
In article
<rdeininger-15...@user-2ivec5u.dialup.mindspring.com>,
rdein...@mindspring.com (Robert Deininger) wrote:

> I can email or post the command file if there's interest.

I've gotten a couple of requests, so I'll just post the following
use-at-your-own-risk DCL.

There are two files below.

JRDDCL.COM is pretty much stolen from Hoff's book; I've only typed in what
I've needed so far, so it isn't the whole library.  The main utility
depends on these routines.  You'll have to decide where to keep the
library on your system. The second routine defines a symbol to locate the
library; you'll want to adjust that definition.  You can also change all
occurances of "jrd" to your own initials if you want.

DISABLE_TERMINATED_LICENSES.COM is the utility that disables all the
terminated license PAKs.  It leave the LICENSE DELETE for you to do by
hand.  Since I'm parsing text output from LICENSE LIST, it may go wrong if
the format changes, or if you have PAKs that don't follow the pattern I
expect.  I STRONGLY suggest you accept the default options to make a copy
of the license file before changing it, and to view the generated command
file before it runs.  This has been tested on CSLG licences.  It's
supposed to work with hobbyist PAKs as well, but I haven't tested since
mine haven't expired yet.

This would be moot if the LICENSE folks would add the qualifiers that LIST
knows to other commands like DISABLE and DELETE.

Here's the stuff.  You may have to de-wrap a few lines.


JRDDCL.COM:

$!   DCL subroutine library
$!      Modelled after the example in "Writing Real Programs in DCL, 2nd
$!      Edition."
$
$  jrddcl__status = %x10000000
$  jrddcl__success = jrddcl__status + %x0001
$  on control_y then exit jrddcl__status + %x0004
$  on warning then exit $status .or. %x10000000
$
$  display = "write sys$output"
$  goto 'p1'
$
$! Title:   Ask a Question
$
$! Synopsis:   This subroutine asks the user a question and returns
$!    the answer.  The prompt for the question is composed
$!    of a query string and optionally a default answer.
$
$! Parameters: P2: A global symbol to receive the answer.
$!    P3: The data type of the answer.  B for boolean
$!        (yes,no); I for integer; S for string.
$!    P4: The query string for the question.  It must end
$!        with a punctuation character and no space.
$!    P5: The default answer (optional; if not specified
$!        then an answer must be entered).
$!    P6: A comma-separated list of options:
$!       H: Display help before asking question.
$!       S: Skip a line before asking question.
$!       U: Upcase the input string.
$!       Z: Allow Ctrl/Z as an nswer.
$!    P7: The help specifier (optional).  It must be in
$!        in the form "procedure [parameter...]".  The
$!        procedure is invoked with the @-sign command.
$
$ASK:
$
$  signal = "@" + f$environment("PROCEDURE") + " signal ask"
$  if p3 .eqs. "B" .and. p5 .nes. "" .and. f$type(p5) .eqs. "INTEGER"
$       then
$     p5 = f$element(p5,"/","NO/YES")
$  endif
$  if p5 .nes. ""
$  then
$     p4 = f$extract(0,f$len(p4)-1,p4) + -
           " [" + p5 + "]" + f$extract(f$len(p4)-1,1,p4)
$  endif
$  if f$locate("S",p6) .ne. f$length(p6) then display ""
$  if f$locate("H",p6) .ne. f$length(p6) then @'p7'
$
$a10: read sys$command/prompt="''p4' " input/end_of_file=a_eof
$  if input .eqs. "" then input = p5
$  input = f$edit(input,"TRIM")  
$  if input .eqs. ""
$  then
$     signal w inputreq "Please enter a value; there is no default."
$  else if input .eqs. "?"
$  then
$     if p7 .nes. "" then @'p7'
$     if p7 .eqs. "" then display "There is no help for this question."
$  else
$     goto a_'p3'
$a_B:    input = f$edit(input,"UPCASE")
$     if f$locate(input,"YES") .eq. 0 .or. -
         f$locate(input,"NO") .eq. 0
$     then
$        input = input .and. 1
$        goto a19
$     else
$        signal w yesnoreq "Please answer YES or NO."
$     endif
$     goto a15
$
$a_I:    if f$type(input) .eqs. "INTEGER"
$     then
$        input = f$integer(input)
$        goto a19
$     else
$        signal w intreq "The input must be an integer."
$     endif
$     goto a15
$
$a_S:    if f$locate("U",p6) .ne. f$length(p6)
$     then
$        input = f$edit(input,"UPCASE")
$     endif
$     goto a19
$a15:
$  endif
$  endif
$  goto a10
$a_eof:
$  input = "^Z"
$  if f$locate("Z",p6) .ne. f$length(p6) then goto a19
$  signal i invctrlz "End-of-file is not a valid response."
$  goto a10
$a19:
$  'p2' == input
$  exit jrddcl__success
$
$! Title:   Signal an Informational or Error Message
$
$! Synopsis:   This subroutine "signals" a message, producing one
$!    or more message lines in the standard OpenVMS format.
$!    It also exits with a status whose severity matches
$!    that of the message.
$
$! Parameters: P2: The message facitlity code.
$!    P3: The message serverity (S, I, W, E, or F).
$!    P4: The message identification.
$!    P5: The message text.
$!    Pn: Optional message lines or status codes whose
$!        corresponding message lines are to me included.
$
$! Status:  The severity of the exit status is equal to the
$!    message severity, except in the case of warnings.
$!    If the message severity is W, and informational
$!    severity is included in the status so that the
$!    caller's error handler is not invoked.
$
$SIGNAL:
$
$  prefix = f$fao("%!AS-!AS-!AS, ",p2,p3,p4)
$  i = 4
$s10:    i = i + 1
$     if i .gt. 8 then goto s19
$     if p'i' .eqs. "" then goto s19
$     text = p'i'
$     if f$type(text) .eqs. "INTEGER"
$     then
$        text = f$message(text)
$     endif
$     if f$ext(0,1,text) .nes. "%" then text = prefix + text
$     if i .gt. 5 then text [0,1] := "-"
$     display text
$     goto s10
$s19:
$  if p3 .eqs. "W" then p3 = "I"
$  exit jrddcl__status + f$locate(p3,"WSEIF")
$


DISABLE_TERMINATED_LICENSES.COM:

$! Title:   Disable Terminated Licenses
$
$! Synopsis:   This command file disables all the terminated licenses
$!    in the active license database, which is defined by
$!    the current value of LMF$LICENSE.
$
$! Parameters: None
$
$! Author:  Robert Deininger
$! Created: January, 2001
$
$
$! Define some simple status codes.
$
$ lic__status  = %x10000000
$ lic__success = lic__status + %x0001
$ lic__ctrly   = lic__status + %x000C
$
$! Set up interrupt and error handlers.
$
$ status = lic__success
$ on control_y then goto control_y
$ on warning then goto error
$
$! Define some useful symbols.
$ say = "write sys$output"
$ jrdcall = "@jrddcl.com"     !!! <<<---- adjust this as needed
$
$! The real work starts here.
$
$ tempfile1 = "terminated.lis;"
$ tempfile2 = "disable_terminated.com;"
$
$ current_ldb = f$search(f$trnlnm("lmf$license"))
$
$ type sys$input

 Utility to DISABLE all the terminated licenses in the active
 license database...

 The active database is:
$ say "   ",current_ldb
$ type sys$input

 This utility makes many changes to the license database.  Do you
 want a backup copy of the database file saved before changes
 are made?
$10:
$ on warning then goto 10
$ jrdcall ask lic__answer b "Save a backup copy?" "YES" U,S
$ on warning then goto error
$
$ if lic__answer
$ then
$    current_ldb = current_ldb - f$parse(current_ldb,,,"version")
$    say ""
$    copy/log 'current_ldb' 'current_ldb'
$    current_ldb = f$search(f$trnlnm("lmf$license"))
$    say ""
$    say " The new highest version will be modified."
$ endif
$
$ say " Finding terminated licenses..."
$
$! Get a list of terminated licenses.
$ license list/before/terminated/full/output='tempfile1'
$
$ say " Making a command file to disable licenses..."
$
$! Open the input and output files.
$ open/read  tempfile1 'tempfile1'
$ open/write tempfile2 'tempfile2'
$
$ target_string = "-----------------------"
$main_loop:
$ gosub find_string
$ if input_string .nes. ""
$ then
$!   We have read the "header" line for a single license.
$!   Look for expected beginnings on the next 4 lines, and save the good
$!   parts.
$
$    get_string = "Issuer:"
$    gosub get_string
$    if result_string .nes. ""
$    then
$       issuer = result_string
$    else
$       goto main_loop
$    endif
$
$    get_string = "Authorization:"
$    gosub get_string
$    if result_string .nes. ""
$    then
$       authorization = result_string
$    else
$       goto main_loop
$    endif
$
$    get_string = "Product Name:"
$    gosub get_string
$    if result_string .nes. ""
$    then
$       product_name = result_string
$    else
$       goto main_loop
$    endif
$
$    get_string = "Producer:"
$    gosub get_string
$    if result_string .nes. ""
$    then
$       producer = result_string
$    else
$       goto main_loop
$    endif
$
$    ! We have the 4 important pieces of information we wanted.  Generate
$    ! a LICENSE DISABLE command.
$    gosub write_command
$
$    goto main_loop
$ endif
$
$! We have processed the whole input file.
$ close tempfile1
$ write tempfile2 "$ exit"
$ close tempfile2
$
$20:
$ on warning then goto 20
$ jrdcall ask lic__answer b "Do you want to view the command file?" -
             "YES" U,S
$ on warning then goto error
$
$ if lic__answer
$ then
$    type/page 'tempfile2'
$ endif
$
$30:
$ on warning then goto 30
$ jrdcall ask lic__answer b -
     "Do you want to exectute these commands to modify the license database?" -
     "" U,S
$ on warning then goto error
$
$ if lic__answer
$ then
$    @'tempfile2'
     type sys$input

 Disabling is complete.

 You may want to execute
   $ LICENSE DELETE */STATUS=DISABLED/LOG
 to completely remove all disabled licenses from the database.
$
$ else
$    say ""
$    say " Modifications cancelled."
$ endif
$
$ goto cleanup
$
$CONTROL_Y:
$ status = lic__ctrly
$ goto cleanup
$
$ERROR:
$ status = $status
$ goto cleanup
$
$CLEANUP:
$ if f$search(tempfile1) .nes. "" then delete/nolog/noconfirm 'tempfile1'*
$ if f$search(tempfile2) .nes. "" then delete/nolog/noconfirm 'tempfile2'*
$
$ if f$type(lic__answer) .nes. "" then delete/symbol/global/nolog lic__answer
$
$ exit status .or. %x10000000
$
$FIND_STRING:
$! This subroutine reads lines from tempfile1 until it obtains a line that
$! begins with target_string.  It returns with input_string equal to the
$! entire input line, or the null string if the end of the file was reached
$! without finding the target.
$
$find_loop:
$ read/end_of_file=end_of_file tempfile1 input_string
$ if f$locate(target_string,input_string) .eq. 0
$ then
$    ! The current string begins with the target.
$    return ! (FIND_STRING)
$ else
$    goto find_loop
$ endif
$
$end_of_file:
$ input_string = ""
$ return ! (FIND_STRING)
$
$GET_STRING:
$! This subroutine reads a line from tempfile1, checks that it starts
$! with get_string, and returns in result_string the last part of the string.
$! The "last part" is the second element delimited by " ", after the part
$! matching get_string is removed.
$
$ read tempfile1 input_string
$ if f$locate(get_string,input_string) .eq. 0
$ then
$    ! The current string begins with the target.
$    temp = f$edit((input_string - get_string),"compress")
$    result_string = f$element(1," ",temp)
$
$ else
$    say "Unexpected line.  Expected ''get_string', found:"
$    say line
$    say ""
$
$    result_string = ""
$ endif
$
$ return ! (GET_STRING)
$
$WRITE_COMMAND:
$! This subroutine writes a single "license disable" command to tempfile2,
$! using the information in symbols PRODUCT_NAME, AUTHORIZATION, ISSUER,
$! and PRODUCER.
$
$ write tempfile2 "$ license disable/log ''product_name' -"
$ write tempfile2 "    /authorization=''authorization' -"
$ write tempfile2 "    /issuer=''issuer' -"
$ write tempfile2 "    /producer=''producer'"
$ write tempfile2 "$"
$
$ return ! (WRITE_COMMAND)


Jim Agnew
3/20/01
I followed Mr. Robert Deininger's
kindly given com files, and when I tried to do the license delete/disabled * step, (or however it's spelled), lmf whined about being
greater than a 64K command..  I had about oh, 3,000 old licenses clogging up my db.  we simply edited the disable_licenses.com file
into a delete_licenses.com, and nuked them.

my license db did NOT shrink...  should I copy them over to a new file to reduce the file size, or just leave it.  

many thanks, my console is no longer incessantly beeping...

j.

- show quoted text -

Hoff Hoffman
3/20/01
In article <3AB7C29...@hsc.vcu.edu>, Jim Agnew <ag...@hsc.vcu.edu> writes:
:my license db did NOT shrink...  should I copy them over to a new file to
:reduce the file size, or just leave it.  
  The RMS indexed file storage allocation does not normally shrink without
  outside assistance.

  Having a larger-than-required indexed file containing deleted records
  is not (usually) of any particular consequence.  (Salient exceptions:
  severely oversized files when disk space is correspondingly severely
  constrained, large numbers of deleted records and other cruft built up
  within an indexed file when frequently accessed, etc.)

  You would need to CONVERT/RECLAIM or similar conversion, and not COPY,
  to remove the deleted records and to reorganize the internal structures
  of an RMS indexed file.

 ---------------------------- #include <rtfaq.h> -----------------------------
      For additional, please see the OpenVMS FAQ -- www.openvms.compaq.com    
 --------------------------- pure personal opinion ---------------------------
   Hoff (Stephen) Hoffman   OpenVMS Engineering   hoffman#xdelta.zko.dec.com

Saturday, July 4, 2020

Playing Audio Music (Big Ben Westminster Clock Chime) on Internal PC Speaker Connected to Motherboard Southbridge 8253 / 8254 PIT chip (Not Sound Card)

Supratim Sanyal's Blog: PC internal speaker buzzer beeper (beep speaker)
Motherboard with connected internal speaker

I have always built my own internet routers to serve as gateways to ISPs for my home and family. The last one - a Pentium-D based build - was getting challenged with 200 mbps uplinks to Verizon FiOS and Comcast xfinity. So I recently built a new router using a ASRock J4105B-ITX Mini ITX motherboard with Intel Gemini Lake Celeron J4105 quad-core processor,  8 GB of DDR4 SODIMM memory,  a four-port IBM Netxtreme gigabit ethernet adapter (removed for the picture above to show the piezo buzzer clearly),  a 120 GB SSD for storage and a InWin Mini-ITX case with power supply unit. The router works great, easily supporting two WAN gateways in failover / redundant mode and two gigabit private LAN subnets. The power requirements at just 10 watts TDP for the CPU and five more watts for the quad-port Netxtreme gigabit Ethernet adapter are a fraction of the Pentium-D build with 95 watts TDP just for the processor.

PC Motherboard Internal BIOS Alarm Speaker Buzzer - Piezo Beeper
PC internal Piezoelectric speaker »
Whenever I build a computer I make it a point to install a motherboard-connected speaker or a beeper. Unfortunately a lot of recent computer cases do not include this simple and cheap part, thus depriving builders of a basic tool for troubleshooting when the computer does not boot far enough to get to the BIOS screen. The mini-ITX case I bought for the router was also missing the speaker / buzzer, so I obtained and installed a piezo buzzer as you can see in the picture at the top of this post.

The ASRock motherboard has a header for the speaker (as do all motherboards I have come across, including ASUS and Dell motherboards over the last thirty years). Strangely, ASRock's BIOS had the internal speaker turned off by default. I turned it on manually, and was happy to hear the familiar single short beep at boot time: all systems go. Perhaps some people do not want their PCs to signal all is good when they boot or reboot their computer.

The router runs Ubuntu 20.04 LTS (Focal Fossa) operating system which serves as the virtualization hypervisor for a Sophos UTM 9 Home virtual machine that performs actual routing, firewall, IDS and IPS functions (the four physical ethernet ports on the Netxtreme are bridged into the virtual machine).

Of relevance to this post, Ubuntu provides a nifty PC Speaker device driver kernel module that allows command-line and shell script access to the internal speaker.  This module was was automatically included during installation, but was not being loaded by default during Focal Fossa boot. I added a simple "modprobe pcspkr" line in /etc/rc.local (and made it executable) to load it at boot-time. The driver provides access to the case speaker via a /dev/input/by-path/platform-pcspkr-event-spkr device which in my case is a link to "../event6".  It then becomes possible to write to it this device to play tones of specific frequencies and duration. Armed with a frequency lookup table for musical notes, entire tunes can then be played on the chassis / case speaker.  This method does not require writing to the processor's I/O ports that are connected to the Intel 8253 / 8254 Programmable Interval Timer (PIT) to which the case speaker is connected via an AND gate on Counter 2.

With the PC speaker kernel module loaded, we can use the convenient beep utility from beep package to play notes on the internal buzzer. "beep" needs to be invoked from the native root account (it does not work with sudo).

I wrote a cron-invoked bash shell script that plays the famous Westminster Chimes (Westminster Quarters) melody at each quarter, half, three-quarters and top of the hour.  The Westminster Chimes consists of four sequences of four notes each rendered by a bell in the bell tower. The first, second and third of the four sequences are played at fifteen minutes, thirty minutes and forty-five minutes past the hour.  All four sequences are played at the top of the hour, followed by all four bells ringing to count the hour.

Piezoelectric beepers are reported to work best at audio frequencies in the 1 to 5 KHz range. Mapping the Westminster Quarters notes to frequencies just around 1 KHz, here is the piezo buzzer playing at the top of the hour:



Here are root's crontab entries:

# Westminster chimes
0 * * * * /root/beep/westminster-pcspkr.sh -00 > /dev/null 2>&1
15 * * * * /root/beep/westminster-pcspkr.sh -15 > /dev/null 2>&1
30 * * * * /root/beep/westminster-pcspkr.sh -30 > /dev/null 2>&1
45 * * * * /root/beep/westminster-pcspkr.sh -45 > /dev/null 2>&1

and here is the shell script "/root/beep/westminster-pcspkr.sh":