Friday, August 28, 2009

[Level 2] Declare and Handlers in MySQL Stored Procedure.

In MySQL stored procedure, we use use "DECLARE" statement to define some variables, like: Local Variable, Conditions and handlers and Cursors.
Something you should to take care is about the sequence of these variables declaration. The correct sequence is:
1. Variables
2. Conditions
3. Cursors
4. Handlers

IF the sequence is not correct, you will get a error message while building stored procedure.
The example for these variables declaration as below:
1. Variables:
mysql> DECLARE no int;
2. Conditions
mysql> DECLARE co CONDITION FOR SQLSTATE '23000';
3. Cursors
mysql> DECLARE cu CURSOR FOR SELECT * FROM MYSQL.USER;
4. Handlers
mysql> DECLARE CONTINUE HANDLER FOR co BEGIN END; -- the empty between BEGIN and END means to ignore the handler, do nothing.

Wish this helps.

regards,
Stanley Huang

[Level 1] Switch between user and role in OpenSolaris.

As we know, when we add a new user during OpenSolaris installation wizards, then installer will switch "root" from user to role. And we cannot login the system with role "root".
How can we switch root from user to role, after that, how can we switch back?
You can use the command below:

0. how to verify root is user or role:
[case 1: root is role]
# cat /etc/user_attr | grep ^root;
root::::type=role;auths=solaris.*,solaris.grant;profiles=All;lock_after_retries=no;clearance=admin_high;min_label=admin_low
[case 2: root is user]
# cat /etc/user_attr | grep ^root;
root::::type=normal;auths=solaris.*,solaris.grant;profiles=All;lock_after_retries=no;clearance=admin_high;min_label=admin_low

1. Change root from role to user:
# rolemod -K type=normal root;

2. Change root from user to role:
# usermod -K type=role root;

Wish this helps.

regards,
Stanley Huang

[Level 2] How Fast to Clone a Zone in OpenSolaris?

How long do I need for clone a new testing zone from a production zone?
10 mins, 20 mins or more? Such kind of answer maybe you think is.
Do not consider about the time that service down spends in your system (for some special AP, that maybe take a long time to stop), it just need few seconds to build a new testing environment.
How could it be so fast? Because OpenSolaris cloning a zone just use the new feature of ZFS clone technology.
When you create a zone and set the zonepath just under a zfs mount point,
the command zoneadm will create a ZFS for your zone.
Ex.
# zfs list rpool/zones
NAME            USED  AVAIL  REFER  MOUNTPOINT
rpool/zones   278M  32.9G    27K  /export/zones

zonecfg> set zonepath=/export/zones/zone1
zonecfg>...

# zoneadm -z zone1 install
A ZFS file system has been created for this zone.

How do we clone a zone with zone1? The step as the following
1. halt source zone
# zlogin zone1 init 5
2. export config from zone1
zonecfg -z zone1 export -f /tmp/zone2.cfg
3. modify zone2 config
# vi /tmp/zone2.cfg
4. create zone2 by import zone2 config
# zonecfg -z zone2 -f /tmp/zone2.cfg
5. clone zone
# zoneadm -z zone2 clone zone1
6. boot zones
# zoneadm -z zone1 boot
# zoneadm -z zone2 boot

Now you can check the ZFS, and you will find out, the zone2 just use few spaces, and the ZFS rpool/zones/zone2 just need few disk space for different data with zone1. And just use the same data (by reference point) with zone1 to save your disk space. That's why you can build a clone zone so fast.
# zfs list -r rpool/zones
NAME                           USED  AVAIL  REFER  MOUNTPOINT
rpool/zones                  278M  32.9G    27K  /export/zones
rpool/zones/zone1              141M  32.9G    22K  /export/zones/zone1
rpool/zones/zone1/ROOT         141M  32.9G    19K  legacy
rpool/zones/zone1/ROOT/zbe     141M  32.9G   140M  legacy
rpool/zones/zone2             498K  32.9G    22K  /export/zones/zone2
rpool/zones/zone2/ROOT        476K  32.9G    19K  legacy
rpool/zones/zone2/ROOT/zbe    457K  32.9G   140M  legacy

With this helps,

regards,
Stanley Huang

Thursday, August 27, 2009

[Level 2] MySQL Stored Procedure Characteristics

MySQL Stored Procedure has two major characters, "SQL SECURITY" and "Data Use".
"SQL SECURITY" defines what's the effect user while procedure is called, and "Data Use" indicates the procedure R/W. The detail information as the following:
1. SQL SECURITY:
  a. DEFINER-The routine will have the privileges of the user who created it.
  b. INVOKER-The routine will have the privileges of ther user who run it.
  If you want to change the character, use the command as below:
  mysql> ALTER PROCEDURE procedure_name SQL SECURITY [DEFINER/INVOKER];
2. Data Use:
  a. CONTAONS SQL-The option indicates that the routine has the SQL statement but it does not have read or write data.
  b. NO SQL-The option indicates that the routine does not have SQL statement.
  c. READS SQL DATA-The option indicates that the routine has the SQL statement with read data only.
  d. MODIFIES SQL DATA-The option indicates that the routine has the SQL statement with modify data.
  If you want to change the character, use the command as below:
  mysql> ALTER PROCEDURE procedure_name [CONTAINS SQL/NO SQL/READS SQL DATA/MODIFIES SQL DATA];

Wish this helps.

regards,
Stanley Huang

Wednesday, August 26, 2009

[Level 1] Chime, the DTrace GUI tool.

Chime is a DTrace GUI tool.
The way you can install and use as the following steps:
1. First, get the package from OpenSolaris.og, the link as below.
http://opensolaris.org/os/project/dtrace-chime/install/
Because Chime is developed by Java, you must have Java 6 since 1.4.41 environment for Chime to run.
2. Start Chime:
You have to check the account runs Chime has the privileges to run DTrace.
The Command as below.
# /opt/OSOL0chime/bin/chime
3. Choose category:
Default Chime has six categories, and choose one that you want.
4. Choose traces:
Choose the trace you want. At the same time, the right column will show the description of the trace you choose.
5. Click "Run" to execute:
And it will pop out the screen with information sheet.

If you want to make your own trace, you can click menu bar with option File -> New Trace, Following the wizard, and insert the information needed. (I recommend that you should have basic knowledge of D-script)
The specific part you should know. Because the Chime use the "sheet" to display the information, you must have one aggregation function in your D-script program, or you will not build a trace successfully.
 
Wish this helps.

regards,
Stanley Huang

Tuesday, August 25, 2009

[Level 3] Systemtap on Linux.

Today, my boss want me to find some data to compare with Solaris and Linux.
And I find a freeware(GPL) on Linux, called systemtap.
It looks like the "DTrace" in Solaris.
As the documents writes, the we have to download the kernel package then we can start to use it. The commands as the following:
# yum install systemtap kernel-devel yum-utils
# debuginfo-install kernel
 
The sample "script" as the following:
# stap -ve 'probe begin { log("hello world") exit () }'
# stap -c df -e 'probe syscall.* \
{ if (target()==pid()) log(name." ".argstr) }' 
 
Any Linux user use this before?

Wish this helps.

regards,
Stanley Huang

[Level 1] Solve MySQL case insensitive problem.

In default, MySQL is case insensitive.
ex.
mysql> select * from t where n = 'a';
+------+
| n    |
+------+
| A    |
+------+


If we want to solve this problem, we can use following ways:

1. Modify you SQL statement(temporary solution), add the key word 'binary' before your string.
ex.
mysql> select * from t where n = binary 'a';
Empty set (0.00 sec)

mysql> select * from t where n = binary 'A';
+------+
| n    |
+------+
| A    |
+------+
1 row in set (0.00 sec)

2. Modify the table schema, and let the column be case sensitive.
mysql> select * from t where n = 'a';
Empty set (0.00 sec)

mysql> select * from t where n = 'A';
+------+
| n    |
+------+
| A    |
+------+
1 row in set (0.00 sec)

3. To let the new table has case sensitive feature, modifing the database character and collation. (If you want the new table with case insensitive, you can assign the table with "not" case sensitive)
mysql> alter database test character set utf8 collate utf8_bin;
Query OK, 1 row affected (0.01 sec)
mysql> create table tt ( n varchar(32));
Query OK, 0 rows affected (0.32 sec)
mysql> select * from tt where n='A';
Empty set (0.00 sec)

mysql> select * from tt where n='a';
+------+
| n    |
+------+
| a    |
+------+
1 row in set (0.00 sec)


Wish this helps.

regards,
Stanley Huang

[Level 1] Set wifi manually.

Although, OpenSolaris has NWAM, can let user easy to setup the wifi.
But how can we do if we want to setup wifi manually?
 The steps as the following:

1. Check wireless interface is plumbed or not. if not, plumb it. 
  Ex1. Plumb all interface.
  # ifconfig -a
  Ex2. Plumb the interface name that you know.
  # ifconfig ipw0 plumb
2. Scan the ap.
  # wificonfig -i ipw0 scan

essid           bssid             type          encryption      signallevel
test-ap          12:34:56:78:90:00 access point  wep             12

3. Setting wifi profile and use WEP for authentication. In this case I set the WEP password as "1234567890" and profile name as "test-profile". After setting is done, use subcommand "showprofile" to show profiles.
  # wificonfig createprofile test-profile essid=test-ap encryption=WEP wepkey1=1234567890
  # wificonfig showprofile

[ses-ap]
        essid=test-ap
        encryption=WEP
        bssid=12:34:56:78:90:00
        wepkey1=**********

4. Connect to ap.
  # wificonfig -i ipw0 connect test-profile
  # wificonfig showstatus

        linkstatus: connected
        active profile: [test-ap]
        essid: ses-ap
        bssid: 12:34:56:78:90:00
        encryption: wep
        signal strength: strong(12)

5. Use interface ipw0 with DHCP mode.
    ifconfig -i ipw0 dhcp
    ifconfig -a

Wish this helps.
regards,

Stanley Huang

[Level 3] ZFS ARC stat script.

Sometimes, when we use OpenSolaris,

we will find out the memory usage is very high.
That's because ZFS ARC architecture will use memory as possible,
and how can we know the ZFS ARC status?
Actually we can use the command "kstat",
but it seems to hard for general end user.
And I found out a good script from World Wide Web,
Neelakanth Nadgir, who writes a script in perl for easy to check ZFS ARC.
And this script is worth for you to read.

regards,

Stanley Huang

********************************************************************************

#!/bin/perl -w
#
# Print out ZFS ARC Statistics exported via kstat(1)
# For a definition of fields, or usage, use arctstat.pl -v
#
# Author: Neelakanth Nadgir http://blogs.sun.com/realneel
# Comments/Questions/Feedback to neel_sun.com or neel_gnu.org
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License").  You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# When distributing Covered Code, include this CDDL HEADER in each
# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
# If applicable, add the following below this CDDL HEADER, with the
# fields enclosed by brackets "[]" replaced with your own identifying
# information: Portions Copyright [yyyy] [name of copyright owner]
#
# CDDL HEADER END
#
#
# Fields have a fixed width. Every interval, we fill the "v"
# hash with its corresponding value (v[field]=value) using calculate().
# @hdr is the array of fields that needs to be printed, so we
# just iterate over this array and print the values using our pretty printer.

use strict;
use POSIX qw(strftime);
use Sun::Solaris::Kstat;
use Getopt::Long;
use IO::Handle;

my %cols = (# HDR => [Size, Description]
    "Time"    =>[8, "Time"],
    "hits"    =>[4, "Arc reads per second"],
    "miss"    =>[4, "Arc misses per second"],
    "read"    =>[4, "Total Arc accesses per second"],
    "Hit%"    =>[4, "Arc Hit percentage"],
    "miss%"    =>[5, "Arc miss percentage"],
    "dhit"    =>[4, "Demand Data hits per second"],
    "dmis"    =>[4, "Demand Data misses per second"],
    "dh%"    =>[3, "Demand Data hit percentage"],
    "dm%"    =>[3, "Demand Data miss percentage"],
    "phit"    =>[4, "Prefetch hits per second"],
    "pmis"    =>[4, "Prefetch misses per second"],
    "ph%"    =>[3, "Prefetch hits percentage"],
    "pm%"    =>[3, "Prefetch miss percentage"],
    "mhit"    =>[4, "Metadata hits per second"],
    "mmis"    =>[4, "Metadata misses per second"],
    "mread"    =>[5, "Metadata accesses per second"],
    "mh%"    =>[3, "Metadata hit percentage"],
    "mm%"    =>[3, "Metadata miss percentage"],
    "arcsz"    =>[5, "Arc Size"],
    "c"     =>[4, "Arc Target Size"],
    "mfu"     =>[4, "MFU List hits per second"],
    "mru"     =>[4, "MRU List hits per second"],
    "mfug"     =>[4, "MFU Ghost List hits per second"],
    "mrug"     =>[4, "MRU Ghost List hits per second"],
    "eskip"    =>[5, "evict_skip per second"],
    "mtxmis"=>[6, "mutex_miss per second"],
    "rmis"    =>[4, "recycle_miss per second"],
    "dread"    =>[5, "Demand data accesses per second"],
    "pread"    =>[5, "Prefetch accesses per second"],
);
my %v=();
my @hdr = qw(Time read miss miss% dmis dm% pmis pm% mmis mm% arcsz c);
my @xhdr = qw(Time mfu mru mfug mrug eskip mtxmis rmis dread pread read);
my $int = 1;        # Print stats every 1 second by default
my $count = 0;        # Print stats forever
my $hdr_intr = 20;    # Print header every 20 lines of output
my $opfile = "";
my $sep = "  ";        # Default seperator is 2 spaces
my $version = "0.1";
my $cmd = "Usage: arcstat.pl [-hvx] [-f fields] [-o file] [interval [count]]\n";
my %cur;
my %d;
my $out;
my $kstat = Sun::Solaris::Kstat->new();
STDOUT->autoflush;

sub detailed_usage {
    print STDERR "Arcstat version $version\n$cmd";
    print STDERR "Field definitions are as follows\n";
    foreach my $hdr (keys %cols) {
        print STDERR sprintf("%6s : %s\n", $hdr, $cols{$hdr}[1]);
    }
    print STDERR "\nNote: K=10^3 M=10^6 G=10^9 and so on\n";
    exit(1);

}

sub usage {
    print STDERR "Arcstat version $version\n$cmd";
    print STDERR "\t -x : Print extended stats\n";
    print STDERR "\t -f : Specify specific fields to print (see -v)\n";
    print STDERR "\t -o : Print stats to file\n";
    print STDERR "\t -s : Specify a seperator\n\nExamples:\n";
    print STDERR "\tarcstat -o /tmp/a.log 2 10\n";
    print STDERR "\tarcstat -s , -o /tmp/a.log 2 10\n";
    print STDERR "\tarcstat -v\n";
    print STDERR "\tarcstat -f Time,Hit%,dh%,ph%,mh%\n";
    exit(1);
}

sub init {
    my $desired_cols;
    my $xflag = '';
    my $hflag = '';
    my $vflag;
    my $res = GetOptions('x' => \$xflag,
        'o=s' => \$opfile,
        'help|h|?' => \$hflag,
        'v' => \$vflag,
        's=s' => \$sep,
        'f=s' => \$desired_cols);
    $int = $ARGV[0] || $int;
    $count = $ARGV[1] || $count;
    usage() if !$res or $hflag or ($xflag and $desired_cols);
    detailed_usage() if $vflag;
    @hdr = @xhdr if $xflag;        #reset headers to xhdr
    if ($desired_cols) {
        @hdr = split(/[ ,]+/, $desired_cols);
        # Now check if they are valid fields
        my @invalid = ();
        foreach my $ele (@hdr) {
            push(@invalid, $ele) if not exists($cols{$ele});
        }
        if (scalar @invalid > 0) {
            print STDERR "Invalid column definition! -- "
                . "@invalid\n\n";
            usage();
        }
    }
    if ($opfile) {
        open($out, ">$opfile") ||die "Cannot open $opfile for writing";
        $out->autoflush;
        select $out;
    }
}

# Capture kstat statistics. We maintain 3 hashes, prev, cur, and
# d (delta). As their names imply they maintain the previous, current,
# and delta (cur - prev) statistics.
sub snap_stats {
    my %prev = %cur;
    if ($kstat->update()) {
        printf("\n");
    }
    my $hashref_cur = $kstat->{"zfs"}{0}{"arcstats"};
    %cur = %$hashref_cur;
    foreach my $key (keys %cur) {
        next if $key =~ /class/;
        if (defined $prev{$key}) {
            $d{$key} = $cur{$key} - $prev{$key};
        } else {
            $d{$key} = $cur{$key};
        }
    }
}
# Pretty print num. Arguments are width and num
sub prettynum {
    my @suffix=(' ','K', 'M', 'G', 'T', 'P', 'E', 'Z');
    my $num = $_[1] || 0;
    my $sz = $_[0];
    my $index = 0;
    return sprintf("%s", $num) if not $num =~ /^[0-9\.]+$/;
    while ($num > 1000 and $index < 8) {
        $num = $num/1000;
        $index++;
    }
    return sprintf("%*d", $sz, $num) if ($index == 0);
    return sprintf("%*d%s", $sz - 1, $num,$suffix[$index]);
}


sub print_values {
    foreach my $col (@hdr) {
        printf("%s%s", prettynum($cols{$col}[0], $v{$col}), $sep);
    }
    printf("\n");
}


sub print_header {
    foreach my $col (@hdr) {
        printf("%*s%s", $cols{$col}[0], $col, $sep);
    }
    printf("\n");
}
sub calculate {
    %v=();
    $v{"Time"} = strftime("%H:%M:%S", localtime);
    $v{"hits"} = $d{"hits"}/$int;
    $v{"miss"} = $d{"misses"}/$int;
    $v{"read"} = $v{"hits"} + $v{"miss"};
    $v{"Hit%"} = 100*$v{"hits"}/$v{"read"} if $v{"read"} > 0;
    $v{"miss%"} = 100 - $v{"Hit%"} if $v{"read"} > 0;


    $v{"dhit"} = ($d{"demand_data_hits"} + $d{"demand_metadata_hits"})/$int;
    $v{"dmis"} = ($d{"demand_data_misses"}+$d{"demand_metadata_misses"})/$int;
    $v{"dread"} = $v{"dhit"} + $v{"dmis"};
    $v{"dh%"} = 100*$v{"dhit"}/$v{"dread"} if $v{"dread"} > 0;
    $v{"dm%"} = 100 - $v{"dh%"} if $v{"dread"} > 0;


    $v{"phit"}=($d{"prefetch_data_hits"} + $d{"prefetch_metadata_hits"})/$int;
    $v{"pmis"}=($d{"prefetch_data_misses"}
        +$d{"prefetch_metadata_misses"})/$int;
    $v{"pread"} = $v{"phit"} + $v{"pmis"};
    $v{"ph%"} = 100*$v{"phit"}/$v{"pread"} if $v{"pread"} > 0;
    $v{"pm%"} = 100 - $v{"ph%"} if $v{"pread"} > 0;


    $v{"mhit"}=($d{"prefetch_metadata_hits"}+$d{"demand_metadata_hits"})/$int;
    $v{"mmis"}=($d{"prefetch_metadata_misses"}
        +$d{"demand_metadata_misses"})/$int;
    $v{"mread"} = $v{"mhit"} + $v{"mmis"};
    $v{"mh%"} = 100*$v{"mhit"}/$v{"mread"} if $v{"mread"} > 0;
    $v{"mm%"} = 100 - $v{"mh%"} if $v{"mread"} > 0;


    $v{"arcsz"} = $cur{"size"};
    $v{"c"} = $cur{"c"};
    $v{"mfu"} = $d{"hits"}/$int;
    $v{"mru"} = $d{"mru_hits"}/$int;
    $v{"mrug"} = $d{"mru_ghost_hits"}/$int;
    $v{"mfug"} = $d{"mru_ghost_hits"}/$int;
    $v{"eskip"} = $d{"evict_skip"}/$int;
    $v{"rmiss"} = $d{"recycle_miss"}/$int;
    $v{"mtxmis"} = $d{"mutex_miss"}/$int;
}


sub main {
    my $i = 0;
    my $count_flag = 0;


    init();
    if ($count > 0) { $count_flag = 1; }
    while (1) {
        print_header() if ($i == 0);
        snap_stats();
        calculate();
        print_values();
        last if ($count_flag == 1 && $count-- <= 1);
        $i = ($i == $hdr_intr) ? 0 : $i+1;
        sleep($int);
    }
    close($out) if defined $out;
}
&main;  

Monday, August 24, 2009

[Level 1] Install MySQL in OpenSolaris

The Step as the following:

1. Use Package Mangement to download MySQL 5.1 (SUNWmysql51)
2. Start MySQL server
# /etc/init.d/mysql start
3. set root password
# mysqladmin -u'root' password 'new_password'
4. Login MySQL by mysql client with root account.
# mysql -u'root' -p'new_password'

regards,

Stanley Huang

[Level 3] Script for Solaris Zone FSS.

The following script that I found in the world wide web.
It is a good utility that you can adjust cpu priority with FSS for your zone.

with this helps,

regards,

Stanley Huang

#!/usr/bin/ksh
#
# zonefss - zone FSS administration. Solaris 10.
# FSS : Fair Share Scheduler
#
# 05-Apr-2005, ver 0.50 (first release)
#
# USAGE: zonefss -l | -z zone shares
# eg,
# zonefss -l # list FSS share values for all zones
# zonefss -z global 10 # set the global zone shares to 10
#
# Standard Disclaimer: This is freeware, use at your own risk.
#
# 05-Apr-2005 Brendan Gregg Created this.
#


### Process Arguments
PATH=/usr/bin:/usr/sbin
list=0
set=0
if [[ "$1" == "-l" ]]; then
shift; list=1
fi
if [[ "$1" == "-z" ]]; then
shift; set=1
zone=$1; shift
shares=$1; shift
fi




### List FSS shares
if (( list )); then
printf "%4s %-16s %s\n" "ID" "NAME" "SHARES"
for zone in `zoneadm list`
do
prctl -n zone.cpu-shares -i zone $zone | awk '
$1 ~ /^zone:/ {
zone = $3;
id = substr($2,0,(length($2)-1));
}
$1 ~ /^privileged$/ { printf("%4s %-16s %d\n",id,zone,$2); }
'
done
exit
fi


### Set FSS shares
if (( set )); then
prctl -n zone.cpu-shares -v $shares -r -i zone $zone
exit
fi


### Print usage
echo >&2 "USAGE: zonefss -l | -z zone shares
eg,
zonefss -l # list FSS share values for all zones
zonefss -z global 10 # set the global zone shares to 10"

Sunday, August 23, 2009

[Level 3] Open HA Cluster Whitepaper

I got the information from Nicholas Solter's blog.
Nicholas is one of the authors writing OpenSolaris Bible.
If you are the one who interests Open HA Cluster and OpenSolaris,
I recommend you to read the
Open HA Cluster Whitepaper.

regards,
Stanley Huang

OpenSolaris on SLX

Today, I find out a website which use vedio to present about the SUN technology.
Of course, included OpenSolaris.
After viewing some vedio, that impress me. I recommend you to watch it when you have free time.
The website as the following:
https://slx.sun.com/channel/1179273732

regards,

Stanley Huang

Friday, August 21, 2009

[Level 1] How to set ip forwarding in OpenSolaris

It's easy to set ip forwarding in OpenSolaris.
The command the following:
# routeadm -u -e ipv4-forwarding
To check the config again:
# routeadm

Thursday, August 20, 2009

How often does other user group hold the meeting?

We hold the meeting for 3-4 times in past few years, and I wonder how often does other user group hold the meeting. Then I find out one of these user group has almost 30 times, the number is six times of ours.
They hold the meeting every month, that surprises me. Maybe we can let the meeting more often as possible. But one thing before that, we should study OpenSolaris more, and we could share more information to those who interested it.

Wednesday, August 19, 2009

[Level 2] ZFS and DTrace in Mac.

My friend who use Mac OS X, and told me that the Mac OS X support ZFS and DTrace. It surprises me! ZFS and DTrace is the new feature of Solaris 10, of course, OpenSolaris also has these two features, too. So I try the ZFS and DTrace on Mac immediately.
After test, I have the two following conclusions.
1. Mac support ZFS but for read only, so Mac cannot modify ZFS. That's so pity. The primary reason that I love ZFS just because I can have snapshot, clone. Readonly, is not the impression that I know about ZFS.
2. In OpenSolaris, it has over 60K probes(use command to check how many probes your system has, "/usr/sbin/dtrace -l | wc -l"), so I can detect the system behavior. But when I use the command, I found out the Mac OS only have just over 20K probes, just the 1/3 of OpenSolaris. And I try the D-script, it does work. That's a good gift that all Mac fans should to cherish. Really, because DTrace can be used for online debug, performance and you do not need to modify the source ( Sometimes, even we don't have!! ).
The following sample code is the D-script that exists in OpenSolaris, and to let Mac can run it, I modify the probe name from "open64" to "open" in the script. That you can try it on your Mac. Please save the source code on /tmp/opensnoop and use the following command to detect what processes are opening the file.

# /tmp/opensnoop


********************************************************************************************************


#!/usr/bin/sh
#
# opensnoop - snoop file opens as they occur.
# Written using DTrace (Solaris 10 3/05).
#
# $Id: opensnoop 3 2007-08-01 10:50:08Z brendan $
#
# USAGE: opensnoop [-a|-A|-ceghsvxZ] [-f pathname] [-n name] [-p PID]
#
# opensnoop # default output
#
# -a # print most data
# -A # dump all data, space delimited
# -c # print cwd of process
# -e # print errno value
# -g # print command arguments
# -s # print start time, us
# -v # print start time, string
# -x # only print failed opens
# -Z # print zonename
# -f pathname # file pathname to snoop
# -n name # command name to snoop
# -p PID # process ID to snoop
# eg,
# opensnoop -v # human readable timestamps
# opensnoop -e # see error codes
# opensnoop -f /etc/passwd # snoop this file only
#
# FIELDS:
# ZONE Zone name
# UID User ID
# PID Process ID
# PPID Parent Process ID
# FD file descriptor (-1 for error)
# ERR errno value (see /usr/include/sys/errno.h)
# CWD print current working directory of process
# PATH pathname for file open
# COMM command name for the process
# ARGS argument listing for the process
# TIME timestamp for the open event, us
# STRTIME timestamp for the open event, string
#
# SEE ALSO: truss, BSM auditing.
#
# COPYRIGHT: Copyright (c) 2006 Brendan Gregg.
#
# CDDL HEADER START
#
# The contents of this file are subject to the terms of the
# Common Development and Distribution License, Version 1.0 only
# (the "License"). You may not use this file except in compliance
# with the License.
#
# You can obtain a copy of the license at Docs/cddl1.txt
# or http://www.opensolaris.org/os/licensing.
# See the License for the specific language governing permissions
# and limitations under the License.
#
# CDDL HEADER END
#
# Author: Brendan Gregg [Sydney, Australia]
#
# 09-May-2004 Brendan Gregg Created this.
# 21-Jan-2005 " " Wrapped in sh to provide options.
# 08-May-2005 " " Rewritten for performance.
# 14-May-2005 " " Added errno.
# 28-Jun-2005 " " Added cwd, zonename.
# 17-Sep-2005 " " Increased switchrate, fixed page fault bug.
# 16-Jan-2006 " " Added -n, -p.
# 16-Jan-2006 " " Last update.
#




##############################
# --- Process Arguments ---
#


### Default variables
opt_dump=0; opt_file=0; opt_time=0; opt_timestr=0; opt_args=0
opt_zone=0; opt_cwd=0; opt_failonly=0; opt_err=0; filter=0; pathname=.
opt_name=0; opt_pid=0; pname=.; pid=0


### Process options
while getopts aAcef:ghn:p:svxZ name
do
case $name in
a) opt_time=1; opt_timestr=1; opt_args=1; opt_err=1 ;;
A) opt_dump=1 ;;
c) opt_cwd=1 ;;
e) opt_err=1 ;;
g) opt_args=1 ;;
f) opt_file=1; pathname=$OPTARG ;;
n) opt_name=1; pname=$OPTARG ;;
p) opt_pid=1; pid=$OPTARG ;;
s) opt_time=1 ;;
v) opt_timestr=1 ;;
x) opt_failonly=1 ;;
Z) opt_zone=1 ;;
h|?) cat <<-END >&2
USAGE: opensnoop [-a|-A|-ceghsvxZ] [-f pathname]
[-n name] [-p PID]
opensnoop # default output
-a # print most data
-A # dump all data, space delimited
-c # print cwd of process
-e # print errno value
-g # print command arguments
-s # print start time, us
-v # print start time, string
-x # only print failed opens
-Z # print zonename
-f pathname # pathname name to snoop
-n name # process name to snoop
-p PID # process ID to snoop
eg,
opensnoop -v # human readable timestamps
opensnoop -e # see error codes
opensnoop -f /etc/motd # snoop this file only
END
exit 1
esac
done


### Option logic
if [ $opt_dump -eq 1 ]; then
opt_zone=0; opt_cwd=0; opt_time=0; opt_timestr=0; opt_args=2
fi
if [ $opt_name -eq 1 -o $opt_pid -eq 1 ]; then
filter=1
fi




#################################
# --- Main Program, DTrace ---
#
/usr/sbin/dtrace -n '
/*
* Command line arguments
*/
inline int OPT_dump = '$opt_dump';
inline int OPT_file = '$opt_file';
inline int OPT_args = '$opt_args';
inline int OPT_cwd = '$opt_cwd';
inline int OPT_err = '$opt_err';
inline int OPT_zone = '$opt_zone';
inline int OPT_time = '$opt_time';
inline int OPT_timestr = '$opt_timestr';
inline int OPT_failonly = '$opt_failonly';
inline int OPT_pid = '$opt_pid';
inline int OPT_name = '$opt_name';
inline int FILTER = '$filter';
inline int PID = '$pid';
inline string PATHNAME = "'$pathname'";
inline string NAME = "'$pname'";


#pragma D option quiet
#pragma D option switchrate=10hz


/*
* Print header
*/
dtrace:::BEGIN
{
/*
* ternary operators are used to improve performance.
* OPT_args is unusual in that it can have one of three values.
*/


/* print optional headers */
OPT_time ? printf("%-14s ", "TIME") : 1;
OPT_timestr ? printf("%-20s ", "STRTIME") : 1;
OPT_zone ? printf("%-10s ", "ZONE") : 1;


/* print dump headers */
OPT_dump ? printf("%s %s %s %s %s %s %s %s %s %s %s", "ZONE",
"TIME", "UID", "PID", "PPID", "COMM", "FD", "ERR", "CWD",
"PATH", "ARGS") : printf("%5s %6s ","UID","PID");


/* print main headers */
OPT_args == 0 ? printf("%-12s ", "COMM") : 1;
OPT_dump == 0 ? printf("%3s ", "FD") : 1;
OPT_err ? printf("%3s ", "ERR") : 1;
OPT_cwd ? printf("%-20s ", "CWD") : 1;
OPT_dump == 0 ? printf("%-20s ", "PATH") : 1;
OPT_args == 1 ? printf("%s", "ARGS") : 1;
printf("\n");
}


/*
* Print open event
*/
syscall::open:entry, syscall::open:entry
{
/* save pathname */
self->pathp = arg0;


/* default is to trace unless filtering */
self->ok = FILTER ? 0 : 1;


/* check each filter */
(OPT_name == 1 && NAME == execname) ? self->ok = 1 : 1;
(OPT_pid == 1 && PID == pid) ? self->ok = 1 : 1;
/* OPT_file is checked on return to ensure pathp is mapped */
}


syscall::open:return, syscall::open:return
/self->ok && (! OPT_failonly || (int)arg0 < 0) && ((OPT_file == 0) || (OPT_file == 1 && PATHNAME == copyinstr(self->pathp)))/
{
/* print optional fields */
OPT_time ? printf("%-14d ", timestamp/1000) : 1;
OPT_timestr ? printf("%-20Y ", walltimestamp) : 1;
OPT_zone ? printf("%-10s ", zonename) : 1;


/* print dump fields */
OPT_dump ? printf("%s %d %d %d %d %s %d %d %s %s %S", zonename,
timestamp/1000, uid, pid, ppid, execname, (int)arg0, errno,
cwd, copyinstr(self->pathp), curpsinfo->pr_psargs) :
printf("%5d %6d ", uid, pid);


/* print main fields */
OPT_args == 0 ? printf("%-12s ", execname) : 1;
OPT_dump == 0 ? printf("%3d ", (int)arg0) : 1;
OPT_err ? printf("%3d ", errno) : 1;
OPT_cwd ? printf("%-20s ", cwd) : 1;
OPT_dump == 0 ? printf("%-20s ", copyinstr(self->pathp)) : 1;
OPT_args == 1 ? printf("%S", curpsinfo->pr_psargs) : 1;
printf("\n");


/* cleanup */
self->pathp = 0;
self->ok = 0;
}


/*
* Cleanup
*/
syscall::open:return, syscall::open:return
/self->ok/
{
self->pathp = 0;
self->ok = 0;
}
'

Tuesday, August 18, 2009

[Level 1] Create OpenSolaris zone

Today I try to install zone in OpenSolaris.
I find out the default value of global attribute "brand" is ipkg.
Then I modify this attribute with value "native" ( Solaris 10 default attribute value ).
After I execute the command "zoneadm -z myzone install",
it will be failed with the following message:

[root@Stanley-NB]:/shell/SolarisCommands/zones# zoneadm -z myzone install
sh: line 1: /usr/lib/lu/lucreatezone: not found

What's the command "lucreatezone"?
It's the Solaris 10 command for create a new zone with live upgrade.

[Level 3] One shell a day, keep commands away~

The following the script is my template to create a new shell script.

with this helps,


regards,


Staley Huang


#!/usr/bin/bash
#/usr/bin/bash -xvu
# -x: print command and arguments after interpreted
# -v: print command and arguments before interpreted
# -f: no file globbing
# -u: treat unbound variable as error
# ex.
# a=1
# b=$a
# c=$d ( Error: unbound variable / parameter not set ... )
#
##Bash Note:
# while $1=null
# if [ -f $1] => true
# if [ -d $1] => true
# if [ -f "$1" ] => false
# if [ -d "$1" ] => false
#
################################################################
#
# Customize the setting following the key search
# [##**--]
#
# psedu code:
#
#
################################################################
#
# This template file is for ceating bash script program
# All copyright reserved by Stanley Huang
#
# __ script name ___________: [##**--(/shell/_shell_template.sh)] ## Do not remove '()' ##-- $sShellScriptName, absolution path
# __ purpose _______________: bash script template
# __ current version _______: [##**--(0.9.13 beta)] ## Do not remove '()' ##-- $sVersion, and below...
# __ base shell_temp Ver. __: 0.9.13 beta
# __ author ________________: Stanley Huang
# __ create date ___________: [##**--2006/12/12 10:45]
# __ included shell lib ____: /shell/inc/ : getLastField.sh, getInstanceDir.sh, [##**--]
# __ included perl lib _____: /shell/perlFuncs/ : [##**--] #-- $sIncShell
# __ included ucb lib ______: /usr/ucb/ : expr, [##**--] #-- $sPerlFuncs
# __ notes _________________: on this architecure, only have to modify the funcion 'runProc()' and the code with [##**--]
# __ modification history __:
# Version , Datetime , Author , Purpose
# -------------------------------------------------------------------
# v0.9 beta , 2006/12/12 10:45, Stanley Huang, Init
# v0.9.1 beta, 2006/12/14 23:30, Stanley Huang, Modify for $sPidFile with Instance Directory
# v0.9.2 beta, 2006/12/15 00:15, Stanley Huang, Modify for add check incShell & perlFuncs
# v0.9.3 beta, 2006/12/15 11:15, Stanley Huang, Modify for changing argument action with 'getopts'
# v0.9.4 beta, 2006/12/15 14:15, Stanley Huang, fix the bug for setCmdArgv
# v0.9.5 beta, 2006/12/16 00:30, Stanley Huang, Modify for $sLogFileName and kill PidFile while exit program normally
# v0.9.6 beta, 2006/12/17 23:30, Stanley Huang, Modify for shell_template layout
# v0.9.7 beta, 2006/12/20 22:45, Stanley Huang, add logSyslog function
# v0.9.8 beta, 2007/01/16 01:30, Stanley Huang, Modify for sShellScriptName and sVersion
# v0.9.9 beta, 2007/05/16 21:55, Stanley Huang, Add function pressEnterKey2Cont()
# v0.9.10 beta, 2007/07/17 07:05, Stanley Huang, Add function firstNonEmpty()
# v0.9.11 beta, 2007/07/17 07:05, Stanley Huang, Add function pressAnyKey2Cont()
# v0.9.12 beta, 2008/11/10 23:05, Stanley Huang, Add function pak2c(), modify function setCmdArgv(), for add case ':)' for without argument error
# v0.9.13 beta, 2009/07/23 10:22, Stanley Huang, Modify function firstNonEmpty() to verify more then 2 args and dynamic setting default value by getting environment variable "default_value"


#---------------- Trap -----------------
trap delPidFileAndExit 2
trap exitProg 0
#trap "echo 'hello'" 2


#---------------- Func -----------------


# firstNonEmpty $v1 $v2
_firstNonEmpty() {
sDefault="default value"
sReturn=$1
sNextValue=$2
sNextValue=${sNextValue:=$sDefault}
echo ${sReturn:=$sNextValue}
}


# firstNonEmpty "$v1" "$v2" "$v3" "$v4"
firstNonEmpty() {
sDefault=$default_value
while [ -z "$1" ] && [ $# -gt 0 ]
do
shift
done
if [ -z "$1" ]
then
[ ! -z "$sDefault" ] && echo $sDefault
else
echo "$1"
fi
}


# get data from shell, dependy on $lCmd
getDataFromShell() {
sVarName=$1
sVarValue=grep "^#@ $1=" $lCmd | head -1 | cut -d= -f2
}




# press enter key to continue
pressEnterKey2Cont() {
read -p "Press enter key to continue" sPressEnterKeyToContinue
}


# press any key to continue
pressAnyKey2Cont() {
read -p "Press enter key to continue" -n 1 sPressAnyKeyToContinue
echo ""
}
pak2c() {
read -p "Press enter key to continue" -n 1 x
echo ""
}


# set $sNow
setNow() {
sTimeMode=$1
local sFormat=""
case $sTimeMode in
1)
sFormat="+%Y/%m/%d %H:%M:%S"
;;
2)
sFormat="+%Y%m%d"
;;
3)
sFormat="+%Y%m%d%H%M%S"
;;
*)
sFormat="+%Y%m%d%H%M%S"
;;
esac
sNow=`date "$sFormat"`
}


# log into syslog
logSyslog() {
local sMesg=$1
local sPri=$2
local sTag=$3


if [ -z "$sMesg" ]
then
echo "Error log syslog without messsage!"
return
fi


if [ -z "$sPri" ]
then
sPri="user.err"
fi


if [ -z "$sTag" ]
then
sTag="ShellProgram"
fi


logger -p $sPri -t $sTag "Log from $sProgName : $sMesg"
}


# dependency with $bRunWithDot
exitProg() {
#echo $bIsRunWithDot
if [ $bIsRunWithDot -eq 1 ]
then
trap 2 # cancel trap 2
kill $$
else
exit 0
fi
}


# dependency with $bSetVarExplict, bSetDebug
setEnv() {
if [ $bSetVarExplict -eq 1 ]
then
set -u
export PS4='[${LINENO}]+ '
fi


export PS3='Select the item: ' # ref: showMenuSelect(){}


if [ $bSetDebug -eq 1 ]
then
set -x
fi
}


showMenu() {
declare sTitle=$1
declare sMenuList=$2
declare -i i=0
read -p "Press enter to continue..." x
clear
echo "Please select the no. of the item, or Ctrl+D to quit..."
echo $sTitle
for sMenuItem in $sMenuList
do
i=$i+1
echo "$i) $sMenuItem"
done
}


# no dependency
showMenuSelect() { # PS3
$sQuestion=$1
$sItemList=$2
$sDisplay=$3
$sEnding=$4


$sItemList="exit menu $sItemList"


echo "Please select the no. of the item, or Ctrl+D to quit..."
echo $sQuestion
select item in $sItemList
do
echo "$sDisplay : $item"
case $item in
exit)
break
;;
menu)
showMenu $sQuestion $sItemList
;;
template)
echo "template"
showMenu $sQuestion $sItemList
;;
*)
echo "you don't select any option try again..."
;;
esac
done
echo $sEnding
}


# dependency with $sProgName, $sVersion
getShellVersion() {
echo "The current version of the program ($sProgName) is: $sVersion"
}


# dependency with arguments($sOrigCmd), $sIncDir, $sProgName
setProgCmdName() {
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
##if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
sSuffix="dot"
sProgName=$sShellScriptName
sCmd=`$sIncDir/getLastField.sh "$sProgName" "/"`
else
sSuffix="nom"
sProgName=$0
sCmd=`$sIncDir/getLastField.sh "$sProgName" "/"`
fi
}


# check Singleton
# only exist pidfile & process, return 0
# else return 1
#
# dependency with $sInstanceDir, $sCmd, $sSuffix, bSingleton, sPidFile, $sInstancePid
checkSingleton() {
#echo $sInstanceDir
#echo $sCmd
#echo $sSuffix
#exitProg
sPidFile=$sInstanceDir/$sCmd.$sSuffix
if [ $bSingleton -eq 1 ]
then
if [ -f "$sPidFile" ]
then
sInstancePid=`cat $sPidFile`
#if [ `ps -p $sInstancePid | grep -v PID | grep -c $sCmd` -eq 1 ]
if [ `ps -ef | grep $sInstancePid | grep -c $sCmd` -eq 1 ]
then
return 0
else
return 1
fi
else
return 1
fi
else
return 1
fi
}


# usage:
# showUsage [bNeedToShowDot(0/1)] [Original Command]
#
# dependency with arguments(0/1, $sOrigCmd), $bRunWithDot
showUsage() {
local lDot=""
local lCmd=""


if [ $1 -eq 1 ] || [ $2 == "." ]
then
lDot="."
fi


if [ $2 == "." ]
then
lCmd=$3
else
lCmd=$2
fi




#if [ $bShowDot -eq 1 ]
#then
# lDot="."
# #lCmd=$1
##else
# #lCmd=$0
#fi


##**--
## option => ":dhvl:", $sGetOpts
#echo $sGetOpts
echo "Usage:"
echo " $lDot $lCmd -dhv -l [ Output Log Filename ]"
echo "ex."
echo " $lDot $lCmd -v"


if [ $bDetail -eq 1 ]
then
#echo "The option description:"
#echo "-d: debug mode"
#echo "-h: help manual"
#echo "-v: display script version"
#echo "-l: setting log file name"
cat <&2 # PS. cat <<-EOF, the sign of eof is "EOF or EOF"
The option description:
-d: debug mode
-h: help manual
-v: display script version
-l: setting log file name
EOF
fi
}

# dependency with $sIncShell, $sIncDir
checkIncShell() {

local sLackOfShellNo=0

for sIncShellItem in $sIncShell
do
if [ ! -f "$sIncDir/$sIncShellItem" ]
then
echo "Lack Shell Library ($sIncDir/$sIncShellItem) !!!"
let "sLackOfShellNo=$sLackOfShellNo+1"
fi
done

if [ $sLackOfShellNo -gt 0 ]
then
echo "Total Shell Library Lacks: $sLackOfShellNo ."
echo "Exit program."
exitProg
fi
}

# dependency with $sPerlFuncs, $sPerlFuncsDir
checkPerlFuncs() {

local sLackOfPerlNo=0

for sPerlFuncsItem in $sPerlFuncs
do
if [ ! -f "$sPerlFuncsDir/$sPerlFuncsItem" ]
then
echo "Lack Perl Library ($sPerlFuncsDir/$sPerlFuncsItem) !!!"
let "sLackOfPerlNo=$sLackOfPerlNo+1"
fi
done

if [ $sLackOfPerlNo -gt 0 ]
then
echo "Total Perl Library Lacks: $sLackOfPerlNo ."
echo "Exit program."
exitProg # if use . , exit will cause the terminal closed.
fi
}

# dependency with $sRunWithDot
checkShellBase() {
local sReturn=""

if [ $bRunWithDot -eq 1 ]
then
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
## if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
bIsRunWithDot=1
sReturn=1
else
bIsRunWithDot=0
echo "have to run this program with '.'"
showUsage 1 $sOrigCmd
sReturn=0
fi
else
if [ $0 == "/usr/bin/bash" ] || [ $0 == "bash" ]
## if [ $0 == $SHELL ] || [ $0 == "bash" ]
then
bIsRunWithDot=1
else
bIsRunWithDot=0
fi
sReturn=1
fi

return $sReturn
}

# dependeny with showUsage(), exitProg()
checkCmdArgv() {
# [##**--]
if [ -z "$sLogFileName" ]
then
echo "Error without assign the logfile (-l)"
showUsage
exitProg
elif [ ! -f "$sLogFileName" ]
then
touch $sLogFileName
fi
}

# dependency with $sRunWithDot, showUsage(), exitProg(), checkCmdArgv()
setCmdArgv() {
# [##**--]
local lOptionsCount=0
sGetOpts=":dhvl:"
while getopts $sGetOpts OPTION
# PS. ':'d => not display error message while the option is out of range...
do
case $OPTION in
d)
set -x
;;
h)
bDetail=1
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
v)
getShellVersion
exitProg # if use . , exit will cause the terminal closed.
;;
l)
if [ `/usr/ucb/expr substr $OPTARG 1 1` == "/" ]
then
declare sLogFileName=$OPTARG
else
declare sLogFileName=`pwd`/$OPTARG
fi
;;
\?)
echo "No such option ($OPTARG)..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
:)
echo ":)The option ($OPTARG) without assigning value..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
*)
### never reach here ###
echo "*)The option ($OPTARG) without assigning value..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
;;
esac
done

let "lOptionsCount=$OPTIND-1"
if [ $lOptionsCount -eq 0 ]
then
echo "Please use this command with arguments..."
showUsage 0 $sOrigCmd
exitProg # if use . , exit will cause the terminal closed.
fi

checkCmdArgv
}

delPidFileAndExit() {
if [ -f "$sPidFile" ]
then
rm $sPidFile
fi
exitProg
}

# dependency with $sPidFile, $sWorkingDir, delPidFileAndExit()
runProc() {
if [ $bSingleton -eq 1 ]
then
echo "sPidFile="$sPidFile
echo $$ > $sPidFile
fi

##-------------------------------------------------------------------------------------------------

# [##**--]
declare -i count=0
while true
do
count=$count+1
if [ $count -gt 5 ]
then
break # exit while loop
fi
setNow 1
echo "[$$] $sNow" >> $sLogFileName
logSyslog "[$$] $sNow" "user.err" "ShellProgram"
sleep 3
done

##-------------------------------------------------------------------------------------------------

delPidFileAndExit
}


##[##**--], verify for global setting variables
#declareSysVariables() {

# init variables
# do not set the variable with readonly, cannot revoke the attribute back
# sh not support declare, so cannot run sh /shell/_shell_template.sh
#

declare -i bSetVarExplict=1
declare -i bSetDebug=0

declare sShellScriptName="/shell/_shell_template.sh" # absoluted path # [##**--]
#declare sShellScriptName=`grep "^#" $0 | grep "__ script name __" | cut -d'(' -f2 | cut -d')' -f1`
#if [ -z "$sShellScriptName" ]
#then
# sShellScriptName=`grep "^#" $1 | grep "__ script name __" | cut -d'(' -f2 | cut -d')' -f1`
#fi

declare sVersion=`grep "^#" $sShellScriptName | grep "__ current version __" | cut -d'(' -f2 | cut -d')' -f1`
#if [ -z "$sVersion" ]
#then
# sVersion=`grep "^#" $1 | grep "__ current version __" | cut -d'(' -f2 | cut -d')' -f1`
#fi

declare -i bRunWithDot=1 ##**--
declare -i bSingleton=1
declare sIncDir=/shell/inc
declare sPerlFuncsDir=/shell/perlFuncs
declare sWorkingDir=`pwd`
declare sIncShell="getLastField.sh getInstanceDir.sh"
declare sPerlFuncs=""
declare sOrigCmd="$0 $@"
declare sPara=$@
declare -i bDetail=0
declare sNow=""

# pre-define variables for checkSingleton()
declare sPidFile=""

# pre-define variables for setProgCmdName()
declare sSuffix=""
declare sProgName=""
declare sCmd=""


# pre-define variables for checkShellBase()
declare -i bIsRunWithDot=0

setProgCmdName $sOrigCmd # dependency with $sIncDir, $sSuffix, $sProgName, $sCmd
declare sInstanceDir=`$sIncDir/getInstanceDir.sh $sProgName`

declare sLogFileName=$sInstanceDir/$sCmd.log

#}

## [ declare ]
## declare option:
## -a: array
## -f: function
## -F: display function name but not the definition
## -i: integer
## -r: readonly
## -x: export
## ex.
## declare -ir nVar=123 # set variable as integer and readonly
## declare -x sVar="abc" # export to global environment
## declare -p nVar # display var attributes

####################################################################
#
# Add Extra Variables Below
#
####################################################################

#declareCustVariables() {
# [##**--]
#echo ""
#}

####################################################################
#
# Add Extra Functions Below
#
####################################################################

#---------------- Env ------------------

# init Environment
export LC_ALL=C

#---------------- Main -----------------


# declare system variables
#declareSysVariables

# declare cutomize variables
#declareCustVariables

# dependency with $bSetVarExplict, bSetDebug
setEnv

# no dependency
setCmdArgv $sPara

# dependency with $sIncShell, $sIncDir
checkIncShell
# dependency with $sPerlFuncs, $sPerlFuncsDir
checkPerlFuncs

# dependency with $sRunWithDot
checkShellBase
sReturn=$?

if [ $sReturn == '1' ]
then
# dependency with $sInstanceDir, $sCmd, $sSuffix, bSingleton, sPidFile, $sInstancePid
checkSingleton
sReturn=$?

if [ $sReturn == '1' ]
then
# dependency with $sPidFile, $sWorkingDir
#runProc $sPara
runProc
else
echo "Limited process with singleton, please check the instance pid file & process"
echo "instance pid file ($sPidFile), process ($sInstancePid)"
exitProg # if use . , exit will cause the terminal closed.
fi
fi


exitProg
exitProg
#--------------------------------------------------------------------
## Data for shell, begin with #@.
#@ username=root
#@ password=root123