Author Topic: Mac Address in Classic Rexx  (Read 601 times)

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Mac Address in Classic Rexx
« on: September 15, 2019, 07:43:43 am »
This code can list all my machines on the network (and send a wake upp call if they listen).
It doesn't however give me the hostname of the router/dhcp-server. Ideas how to?
 
Code: [Select]
/*
 * Filename: macaddr.cmd
 *   Author: JAN-ERIK
 *  Created: Mon Sep 10 2012
 *  Purpose: Retrieve MAC Address
 *  Changes: 2019-07-25, Added support for Router
 *           2019-09-14, Updated support for localhost
 *           2019-09-15, OS2ENVIRONMENT -> ENVIRONMENT
 */
stem = 'host.'
IF 0 < ARG() THEN
   count = rxGetMacAddr( ARG(1) )
ELSE
   count = rxGetMacAddr()
DO i = 1 TO count
    /*magic.cmd*/
    /*Wake on Lan in REXX*/
    /*MAC = '11:22:33:44:55:66';*/
    MAC = host.i.macaddr
    SAY host.i.name||':' host.i.ipaddr||':' MAC;
    X = TRANSLATE( 'abcdefghijkl', host.i.macaddr, 'ab:cd:ef:gh:ij:kl' )
    call RxFuncAdd 'SockLoadFuncs', 'rxsock', 'SockLoadFuncs';
    call SockLoadFuncs( '*' );
    SCT = SockSocket( 'AF_INET', 'SOCK_DGRAM', 'IPPROTO_UDP' );
    RC = SockSetSockOpt( SCT, 'SOL_SOCKET', 'SO_BROADCAST', '1' );
    RC = SockIOCtl( SCT, 'FIONBIO', '0' );
    adr.!family = 'AF_INET';
    /*adr.!addr   = '255.255.255.255';*/
    adr.!addr   = host.i.ipaddr
    adr.!port   = 9;
    S = COPIES( D2C(255) ,6 );
    T = COPIES( X ,16);
    G = COPIES( D2C(0) ,6 );
    RC = SockConnect( SCT, "adr.!" );
    STG = S||T||G;
    SAY STG
    RC = SockSend( SCT, STG );
    call SockSoClose SCT;
END
RETURN 0

rxGetMacAddr: PROCEDURE EXPOSE (stem) /*<COMPUTERNAME>*/
    isStem = ( RIGHT( stem, 1 )  = '.' )
    stemval = STRIP( stem, 'T', '.' )
    retval = 0
    i = 1
    /* No parameters given, list all computers */
    IF ARG() = 0 THEN
    DO
        DO WHILE QUEUED() > 0; PARSE PULL; END;
        /* Computers on network */
        '@NET VIEW 2>&1|RXQUEUE'
        DO WHILE QUEUED() > 0
            PARSE UPPER VALUE LINEIN( 'QUEUE:' ) WITH '\\'computer.i' '.
            /* Add computer to list */
            IF LENGTH( computer.i ) > 0 THEN i = i + 1
        END
        computer.0 = i - 1
    END
    ELSE DO
        /* Search for a specific computer */
        computer.0 = 1
        computer.1 = TRANSLATE( ARG(1) )
    END
    j = 0
    DO WHILE QUEUED() > 0; PARSE PULL; END;
    DO i = 1 TO computer.0
       IF computer.i = VALUE( 'HOSTNAME',, 'ENVIRONMENT' ) THEN
       DO
          '@NETSTAT -a 2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0
             PARSE UPPER VALUE LINEIN( 'QUEUE:' ) WITH 'ADDR 'ipnum' INTERFACE' .
             ipnum = STRIP( ipnum )
             IF ipnum <> '127.0.0.1' & ipnum <> '0.0.0.0' & ipnum <> '' THEN
                LEAVE
          END
          DO WHILE QUEUED() > 0; PARSE PULL; END;
          '@NETSTAT -n 2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0
             PARSE UPPER VALUE LINEIN( 'QUEUE:' ) WITH 'PHYSICAL ADDRESS' machex 'MTU' .
             machex = STRIP( machex )
             IF machex <> 0 & LENGTH( machex ) = 12 & LENGTH( ipnum ) > 7 THEN
             DO
                j = j + 1
                machex = TRANSLATE( 'ab:cd:ef:gh:ij:kl', machex, 'abcdefghijkl', ':' )
                IF isStem THEN
                   INTERPRET stemval'.j.name = computer.i;'||stemval'.j.macaddr = TRANSLATE( machex, "0", " " );'||stemval'.j.ipaddr = ipnum;'||stemval'.0 = j; retval = j'
                ELSE
                   retval = retval||computer.i||' '||TRANSLATE( machex, "0", " " )||' '||ipnum||D2C(13)||D2C(10)
             END
          END
       END
       ELSE DO
          '@PING '||TRANSLATE( computer.i )||' 1 1 2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0; PARSE PULL; END;
          '@ARP '||TRANSLATE( computer.i )||' 2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0
             PARSE UPPER VALUE SUBWORD( LINEIN( 'QUEUE:' ), 2 ) WITH machex +17 ipnum .
             IF LENGTH( machex ) = 17 & LENGTH( ipnum ) > 7 THEN
             DO
                j = j + 1
                IF isStem THEN
                   INTERPRET stemval'.j.name = computer.i;'||stemval'.j.macaddr = TRANSLATE( machex, "0", " " );'||stemval'.j.ipaddr = ipnum;'||stemval'.0 = j; retval = j'
                ELSE
                   retval = retval||computer.i||' '||TRANSLATE( machex, "0", " " )||' '||ipnum||D2C(13)||D2C(10)
             END
          END
       END
    END
    IF 1 < computer.0 THEN
    DO
        DO WHILE QUEUED() > 0; PARSE PULL; END;
        '@ARP -a 2>&1|RXQUEUE'
        DO WHILE QUEUED() > 0
           arp = LINEIN( 'QUEUE:' )
           IF 0 < POS( ':', arp ) & 3 < WORDS( arp ) THEN
           DO
              PARSE UPPER VALUE arp WITH iface +13 macad +17 ipadd rest
              DO i = 1 To VALUE( stemval'.0' )
                 /* Add computer to list */
                 IF TRANSLATE( macad, "0", " " ) = VALUE( stemval'.i.macaddr' ) THEN LEAVE i
              END
              IF VALUE( stemval'.0' ) < i THEN
              DO
                 IF isStem THEN
                    INTERPRET stemval'.i.name = STRIP( iface );'||stemval'.i.macaddr = TRANSLATE( macad, "0", " " );'||stemval'.i.ipaddr = STRIP( ipadd );'||stemval'.0 = i;retval = i'
                 ELSE
                    retval = retval||STRIP( iface )||' '||TRANSLATE( macad, "0", " " )||' '||ipadd||D2C(13)||D2C(10)
              END
           END
        END
    END
RETURN retval
« Last Edit: September 15, 2019, 08:51:02 am by Jan-Erik Lärka »

André Heldoorn

  • Hero Member
  • *****
  • Thank You
  • -Given: 117
  • -Receive: 19
  • Posts: 777
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #1 on: September 15, 2019, 08:19:36 am »
'@NET VIEW 2>&1|RXQUEUE'

VALUE( 'HOSTNAME',, 'OS2ENVIRONMENT' )

Two remarks not related to the question: not checking that NET exists can result in a RTFM SYS1041 error (no network, no argument) during an evaluation.

'ENVIRONMENT', please. Unless an author believes that supporting Microsoft OS/2 1.0 is more important than portable and shorter Rexx code. Both will work, but more Rexxes will support this without the superfluous 'OS2' prefix.

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #2 on: September 15, 2019, 09:07:31 am »
The documentation should be updated as the word must indicate that no deviation from that was/is allowed in OS/2. I've altered the code anyhow.

From OS/2 Procedures Language 2/REXX Reference
Quote
To use VALUE to manipulate OS/2 environment variables, selector must be the string 'OS2ENVIRONMENT' or an expression so evaluated. In this case, the variable name need not be a valid REXX symbol. When VALUE is used to set or change the value of an environment variable, the new value is retained after the REXX procedure ends.

Doug Bissett

  • Hero Member
  • *****
  • Thank You
  • -Given: 1
  • -Receive: 46
  • Posts: 1231
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #3 on: September 15, 2019, 08:01:19 pm »
Quote
rxGetMacAddr()

Do you not need to load support for this? I get absolutely nothing from running the program. Using TRACE ALL, it just falls through to the return.

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #4 on: September 16, 2019, 06:22:49 am »
It use the output of commands such as arp, net view, netstat etc. that's part of IBM File and Print.
It should be possible to adapt it to Samba server as well in the future when Samba can run right away after installation.

Add the line
Code: [Select]
call trace '?i'in the beginning of the code and run it.
Press Enter to continue and look at the output and you should see what it says.

Set the line to
Code: [Select]
call trace 'i'and thus leave out the ? (question mark) in the beginning of the code and run it with
Code: [Select]
macaddr>output.txtThen it output every row it execute without asking for confirmation.
The you can read the file output.txt and see where it fail.

« Last Edit: September 16, 2019, 06:00:37 pm by Jan-Erik Lärka »

Doug Bissett

  • Hero Member
  • *****
  • Thank You
  • -Given: 1
  • -Receive: 46
  • Posts: 1231
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #5 on: September 16, 2019, 07:09:04 pm »
Quote
The you can read the file output.txt and see where it fail.

No I can't. Output.txt is completely blank.

It appears that the problem is that this is for the antique IBM File, and Print client. Sorry, but you didn't say that. Let us know when it works with SAMBA, I can't even imagine why anybody is still using File and print Client. SAMBA has problems, but not as many as File and Print Client.

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #6 on: September 16, 2019, 10:55:52 pm »
IBM File and Print Client is reliable and integrate well with the system.

Samba trash the database and can't recover if one has to force a reboot.
A reliable fix for that and it may be possible to switch.

Andi B.

  • Sr. Member
  • ****
  • Thank You
  • -Given: 1
  • -Receive: 21
  • Posts: 434
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #7 on: September 17, 2019, 09:46:37 am »
Quote
I can't even imagine why anybody is still using File and print Client.
Cause it simply works and it is a lot faster than any other solution when used with many files. That's the reason why I'm still running it beside samba and ftp.

Doug Bissett

  • Hero Member
  • *****
  • Thank You
  • -Given: 1
  • -Receive: 46
  • Posts: 1231
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #8 on: September 17, 2019, 07:06:47 pm »
Quote
I can't even imagine why anybody is still using File and print Client.
Cause it simply works and it is a lot faster than any other solution when used with many files. That's the reason why I'm still running it beside samba and ftp.

I quit using File and print Client, years ago, when I started using files that are larger than 2 GB. Another reason why I abandoned it, was that windows won't work with it any more (probably Linux too). When I was testing it (many years ago), I found that the speed difference was hardly measurable, in fact SAMBA was probably slightly faster.

If File and print Client works, for you, and you are willing to accept the security risks, use it. It is not for me, any more.

Don't get me wrong, SAMBA has it's problems, but File and print Client hasn't worked, for me, for many years.

On the other hand, my favorite file transfer program is RSync. It is fast, super reliable, handles large files, and it is very efficient. It also works on the local system, as well as across the network, or even the internet.

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #9 on: September 18, 2019, 09:20:47 pm »
Samba (nmblookup.exe) apparently doesn't list the machines own mac address other than 00-00-0...

Jan-Erik Lärka

  • Global Moderator
  • Full Member
  • *****
  • Thank You
  • -Given: 8
  • -Receive: 15
  • Posts: 198
    • View Profile
Re: Mac Address in Classic Rexx
« Reply #10 on: October 11, 2019, 08:15:19 pm »
It should now run and only rely on the installed TCP/IP package.

2019 Oct 11, Now use TCPIP HOST command

Code: [Select]
/*
 * Filename: macaddr.cmd
 *   Author: JAN-ERIK
 *  Created: Mon Sep 10 2012
 *  Purpose: Retrieve MAC Address
 *  Changes: 2019-07-25, Added support for Router
 *           2019-09-14, Added support for localhost
 *           2019-09-15, OS2ENVIRONMENT -> ENVIRONMENT
 *           2019-10-11, Now use TCPIP HOST command
 */
stem = 'host.'
IF 0 < ARG() THEN
   count = rxGetMacAddr( ARG(1) )
ELSE
   count = rxGetMacAddr()
DO i = 1 TO count
    /*magic.cmd*/
    /*Wake on Lan in REXX*/
    /*MAC = '11:22:33:44:55:66';*/
    MAC = host.i.macaddr
    SAY host.i.name||':' host.i.ipaddr||':' MAC;
    X = TRANSLATE( 'abcdefghijkl', host.i.macaddr, 'ab:cd:ef:gh:ij:kl' )
    call RxFuncAdd 'SockLoadFuncs', 'rxsock', 'SockLoadFuncs';
    call SockLoadFuncs( '*' );
    SCT = SockSocket( 'AF_INET', 'SOCK_DGRAM', 'IPPROTO_UDP' );
    RC = SockSetSockOpt( SCT, 'SOL_SOCKET', 'SO_BROADCAST', '1' );
    RC = SockIOCtl( SCT, 'FIONBIO', '0' );
    adr.!family = 'AF_INET';
    /*adr.!addr   = '255.255.255.255';*/
    adr.!addr   = host.i.ipaddr
    adr.!port   = 9;
    S = COPIES( D2C(255) ,6 );
    T = COPIES( X ,16);
    G = COPIES( D2C(0) ,6 );
    RC = SockConnect( SCT, "adr.!" );
    STG = S||T||G;
    SAY STG
    RC = SockSend( SCT, STG );
    call SockSoClose SCT;
END
RETURN 0

rxGetMacAddr: PROCEDURE EXPOSE (stem) /*<COMPUTERNAME>*/
    isStem = ( RIGHT( stem, 1 )  = '.' )
    stemval = STRIP( stem, 'T', '.' )
    retval = 0
    i = 0
    /* No parameters given, list all computers */
    IF ARG() = 0 THEN
    DO
       DO WHILE QUEUED() > 0; PARSE PULL; END;
       '@PING 255.255.255.255 56 1 2>&1|RXQUEUE'
       DO WHILE QUEUED() > 0
          PARSE UPPER VALUE REVERSE( LINEIN( 'QUEUE:' ) ) WITH ' :'ipnumber.i' '.
          ipnumber.i = STRIP( REVERSE( ipnumber.i ) )
          IF 7 < LENGTH( ipnumber.i ) THEN
             i = i + 1
          ipnumber.0 = i - 1
       END
       ipnumber.i = VALUE( 'HOSTNAME',, 'ENVIRONMENT' )
       ipnumber.0 = i
       j = 1
       DO i = 1 TO ipnumber.0
          '@HOST' ipnumber.i '2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0
             PARSE UPPER VALUE LINEIN( 'QUEUE:' ) WITH ipnumber.j' = 'hostname.j
          END
          hostname.0 = j
          IF 0 < LENGTH( hostname.j ) THEN
             j = j + 1
       END
       j = j - 1
       ipnumber.j = STRIP( hostname.j )
       hostname.j = VALUE( 'HOSTNAME',, 'ENVIRONMENT' )
    END
    ELSE DO
        /* Search for a specific computer */
        hostname.0 = 1
        hostname.1 = TRANSLATE( ARG(1) )
    END
    j = 0
    DO WHILE QUEUED() > 0; PARSE PULL; END;
    DO i = 1 TO hostname.0
       IF i = hostname.0 THEN
          '@NETSTAT -n 2>&1|RXQUEUE'
       ELSE DO
          '@PING '||TRANSLATE( hostname.i )||' 1 1 2>&1|RXQUEUE'
          DO WHILE QUEUED() > 0; PARSE PULL; END;
          '@ARP '||TRANSLATE( hostname.i )||' 2>&1|RXQUEUE'
       END
       DO WHILE QUEUED() > 0
          PARSE UPPER VALUE SUBWORD( LINEIN( 'QUEUE:' ), 2 + ( i = hostname.0 ) ) WITH machex +17 ipnum .
          IF ( LENGTH( machex ) = 17 & LENGTH( ipnum ) > 7 ) | ( i = hostname.0 & LENGTH( STRIP( machex ) ) = 12 & machex <> 0 ) THEN
          DO
             pass = 0
             IF i = hostname.0 THEN
             DO
                IF DATATYPE( STRIP( machex ), 'X' ) THEN
                DO
                   hostname.i = STRIP( hostname.i )
                   ipnum = ipnumber.i
                   machex = TRANSLATE( 'ab:cd:ef:gh:ij:kl', STRIP( machex ), 'abcdefghijkl' )
                   pass = 1
                END
             END
             ELSE pass = 1
             IF pass THEN
             DO
                j = j + 1
                IF isStem THEN
                   INTERPRET stemval'.j.name = hostname.i;'||stemval'.j.macaddr = TRANSLATE( machex, "0", " " );'||stemval'.j.ipaddr = ipnum;'||stemval'.0 = j; retval = j'
                ELSE
                   retval = retval||hostname.i||' '||TRANSLATE( STRIP( machex ), "0", " " )||' '||ipnum||D2C(13)||D2C(10)
             END
          END
       END
    END
    IF 1 < hostname.0 THEN
    DO
        DO WHILE QUEUED() > 0; PARSE PULL; END;
        '@ARP -a 2>&1|RXQUEUE'
        DO WHILE QUEUED() > 0
           arp = LINEIN( 'QUEUE:' )
           IF 0 < POS( ':', arp ) & 3 < WORDS( arp ) THEN
           DO
              PARSE UPPER VALUE arp WITH iface +13 macad +17 ipadd rest
              DO i = 1 To VALUE( stemval'.0' )
                 /* Add computer to list */
                 IF TRANSLATE( macad, "0", " " ) = VALUE( stemval'.i.macaddr' ) THEN LEAVE i
              END
              IF VALUE( stemval'.0' ) < i THEN
              DO
                 IF isStem THEN
                    INTERPRET stemval'.i.name = STRIP( iface );'||stemval'.i.macaddr = TRANSLATE( macad, "0", " " );'||stemval'.i.ipaddr = STRIP( ipadd );'||stemval'.0 = i;retval = i'
                 ELSE
                    retval = retval||STRIP( iface )||' '||TRANSLATE( macad, "0", " " )||' '||ipadd||D2C(13)||D2C(10)
              END
           END
        END
    END
RETURN retval