Showing posts with label unix. Show all posts
Showing posts with label unix. Show all posts

Tuesday, April 23, 2013

Alvin's HISTFILE workaround

Here is the background of my story. In my site, there are 3 hosts (named host-A, host-B & host-C) running AIX 6.1. Each host allows a maximum of 2 telnet login sessions. So, I can at most login 6 telnet sessions.  My $HOME directory is mounted in host-B. Using NFS, all the 3 hosts will share the same $HOME directory. Ideally I would expect each telnet session have its own command history, but this does not happen.

Once login, the korn shell will create a command history file .sh_history in the $HOME.  Then the 6 telnet sessions will share the SAME command history file $HOME/.sh_history. This is really a nightmare.

To solve this problem, I tried to define the HISTFILE variable in the first line of my $HOME/.profile.  This HISTFILE will define an unique filename for each of the 6 telnet sessions. So, each session will have different command history filenames. However, such a HISTFILE setup does not work.

Why the HISTFILE is not functioning? Sometimes even the HISTFILE is defined in the first line of the $HOME/.profile file, it is not functioning at all. Why? It is because of the /etc/profile file. When korn shell is your login shell, once login, the korn shell will firstly execute the system file /etc/profile before executing the $HOME/.profile file. Usually, some third party software (such as file transfer or database software) will modify this /etc/profile to instruct it to run some setup scripts of the software. Commonly those setup script will use some functions. Once there is function declaration in the script, the korn shell will record the function in the command history. Thus, the default command history file $HOME/.sh_history is used. Once the default $HOME/.sh_history file is used, the name of the command history file will not be changed by the HISTFILE variable.

Actually, the command [[ set -o nolog ]] can prevent the korn shell to record the function the command history file. Usually, the nolog option will not be set in the /etc/profile. You can modify the /etc/profile to add this nolog option. However, once the host is already in production, changing the system file /etc/profile requires numerous procedures and approvals. No one will take the risk to approve this kind of system file modifications. In other words, it is very difficult to make this change in a production host. As a result, those third party software setup script and its function in the /etc/profile will force the korn shell to use the command history file $HOME/.sh_history once you login.

To be more complicate, the AIX 6.1 seems cache the command history in the memory. Therefore, when issuing the command [[ fc -l ]], sometimes the result is the command history in the cache memory but sometimes it is a mix of commands from the 6 telnet sessions due to sharing same $HOME/.sh_history file.

The korn shell in AIX 6.1 has a built-in fc command. When issuing the command [[ fc -l ]] in an interactive korn shell, this built-in fc command seems rely on the cached command history.

However, when using [[ fc -l ]] inside a script (which is run under another process), the external /usr/bin/fc or /bin/fc commands may be used (because a process should not use the korn shell process built-in commands). For the external command /usr/bin/fc, it seems that it cannot access the cached command history of the login korn shell. So, it will reply on the default command history file $HOME/.sh_history or the HISTFILE environment variable. When the HISTFILE is defined and exported to the script, it will use it, even though this HISTFILE is not functioning in the login korn shell. This further complicates the situation.

Also, when issuing [[ fc -l & ]] or [[ nohup fc -l & ]] in an interactive korn shell, a separate process is run for the command. This separate process seems behave quite similar to the situation above.

In order to solve the above problems, what we need is an unique command history file for each of the 6 telnet session. But, how to do so ? Here is my solution. I named it as Alvin's HISTFILE workaround.

This workaround is to add the following line at the beginning of the $HOME/.profile file.

if tty -s
then
     export HISTFILE=~/.sh_history.e`/bin/date +"%s"`.`/bin/hostname`.pts`/bin/tty | /bin/awk -F'/' '{print $NF}'`.r$RANDOM

     if [ -e ~/.sh_history ]
     then
          /bin/ln ~/.sh_history $HISTFILE

          /bin/rm -f ~/.sh_history

          /bin/find ~ -type f -name '.sh_history.e*r*' -mtime +15 -exec /bin/rm {} \; &

     fi
fi

Here is a detail description of how this workaround achieve my purpose.

When I telnet login the first session, this workaround is executed

The first line [[ if tty -s ]] is to ensure that this is an interactive shell. In my site, there are scheduled jobs running using root-id to [[ su - ]] to my user-id to execute some programs on behave of me. This action will call my $HOME/.profile and then run some programs in "no terminal" mode. In AIX 6.1, such a "no terminal" situation will make the [[ pts ]] command to give error messages which will spoil the scheduled jobs and also the HISTFILE variable. Anyway, the primary purpose of the workaround is for interactive korn shell, so it is better to have such a [[ if tty -s ]] checking.

The next line is to define the HISTFILE variable. The variable will use the epoch time, the hostname, the pts number and a random number. So, for the 6 telnet login sessions, the HISTFILE will be unique.

Then, the [[ if ]] statement is to double confirm the $HOME/.sh_history is already exist. Such file should be created by the /etc/profile once login.

Then, we use hard-link to make the two files $HOME/.sh_history and the $HISTFILE sharing the same i-node. Now, the content of this i-node file is the command history of this interactive korn shell. This i-node has 2 links : the $HOME/.sh_history and the $HISTFILE files. Now, no matter whether the built-in fc command or the external /usr/bin/fc command is used, each command will refer to the same command history content in that i-node.

The next line is to remove the filename .sh_history in the $HOME directory. Such a file removal will not affect the interactive korn shell. The shell should already get the i-node number for command history processing throughout its life. The i-node will not physically clean-up because there is still a link (the $HISTFILE file) pointing to it. As a result, both the interactive korn shell and the external /usr/bin/fc commands will function as usual.

Now, I login the second telnet session. Since the file .sh_history is already removed from the $HOME directory, the /etc/profile will create a new .sh_history file (with a new i-node number, of course). Then, this second interactive korn shell will work on this new i-node number for command history. Also, a new HISTFILE is defined for this shell. The $HISTFILE filename is different from the first telnet session. So, this new i-node and new $HISTFILE is only for this second telnet shell. Therefore, I have a completely independent command history file in the second login shell.

This process is repeated for the third, fourth, fifth and sixth interactive login korn shell. There will be six $HISTFILE in the $HOME directory, each using a different i-node.

The final [[ find ]] command is to clean-up those $HISTFILE files older than 15 days. It is assumed that you exit the login korn shell at least 15 days after login. If you do not exit the shell after 15 days, a new login process will kill your $HISTFILE and your i-node will be clean-up. Then, un-expected behavior will be resulted. Normally, you should exit the shell as soon as you no longer need it.

Alvin SIU
2013-04-23
Copyright/Licence Information:
All information and coding in this article is offered at no charge for NON-COMMERCIAL PERSONAL USE only.
This blog and the coding is copyright.
Reproduction of this blog and its coding in whole or in part in paper or digitally or in any other forms without the explicit written permission of the author is strictly prohibited.

Disclaimer:
All information in this article is distributed "as is" and is UNSUPPORTED.
NO WARRANTY of any kind is expressed or implied.
You use AT YOUR OWN RISK.
The author will not be liable for any data loss, damages, and loss of profits or any other kind of tangible or intangible loss while using or misusing wholly or partly of the information.

Thursday, August 6, 2009

Access Permission of the Underlying Directory BEFORE mount

In AIX 5.2, the du, find and tar command will sometimes fail in some directories. But, they can be run successfully in some other directories. Why this happens ? It is all because of the filesystem mounting.

It is very natural to mount numerous filesystems in AIX. Usually, a filesystem is mounted onto a directory of the same name in another filesystem. For example, under the ROOT filesystem, there are numerous other filesystems mounted onto many directories. When you ls these directories, you are actually getting the access permission of the AFTER-MOUNTED image. However, in AIX 5.2, the technical aspect of some commands such as find and tar will check the access permission of the BEFORE-MOUNTED directory. As a result, even the ls command reports a permission of 777 for the directory, the access permission of the BEFORE-MOUNTED underlying directory may have a permissoin of 700. Then, the find or tar command will certainly fail.

Since the ls command (and many other commands) will only reports the access permission of the AFTER-MONUTED image, how to know about the access permission of the before image ? The answer is to check the inode information. But, how to do so ?

First of all, you have to know the inode number. Supposed that your filesystem is mounted onto the directory /usr/your/directory. To search for the inode number of the underlying directory /usr/your/directory, issue this command:
ncheck | grep -e ':$' /usr/your/directory

The output may look like this:
: : /dev/hd1: 1996 /usr/God/directory 1997 /usr/your/directory 1998 /usr/others/directory : :

Then, use this command to check the access permission of the inode of the underlying directory:
istat 1997 /dev/hd1

You will certainly get the access perssions which is very different to that got from the ls command. This is the access permission of the underlying directory.



Friday, November 7, 2008

The Max Download Session Problem

Think about this story : there is a big data warehouse department in a company. The DW department unix machine has to download numerous files from various other departments in order to collect data to build the warehouse.

There is a situation that : for example, job script-1 will download file-A, file-B, file-C, file-D & file-E from department-1 of the company, Job script-2 will download file-F, file-G, file-H, file-I & file-J from department-2 of the company, similarly for job script-3, script-4, script-5, script-6 and so so. All jobs are inside the job database and are kick-out by the job scheduler in a monthly, weekly and daily basis respectively.

How to do the download ? Actually, the script will call a third party file transfer software.

For this situation, there are many outstanding questions :

Due to license issue, the third party file transfer software only allows a max download session of 4. If there are 6 scripts kick-out by the job scheduler, what will happen ? Can the third party file transfer software put the requests queuing ? Or, will it just turn down the all upcoming requests ?

How about, for example, job script-1 & job script-2 are monthly jobs, script-3 & script-4 are weekly jobs and script-5 & script-6 are daily jobs. The files in monthly job scripts (e.g. script-1 and script-2) are very large. They take a long time for transfer. The files in daily job scripts (e.g. script-5 and script-6) are relatively smaller, just a few hours or minutes are required. But, the daily job scripts have a batch running window of approx 24 hour only. They must finish the file downloading within one day. On the next day, there is a new daily batch. Can the third party file transfer software prioritize the transfer requests ? What happen when all the 4 downloading sessions are occupied by the files of the monthly job scripts ? Can the third party file transfer software let the daily job scripts to jump queue to do the downloading once a monthly file finishes its downloading ? If the transfer software only serves the request in a first-come-first-serve basis and the monthly job scripts appear first, all the monthly file transfer will be answered first. Then, the daily job scripts may face starvation.

What happen when the third party software is hang up ? Will the job scripts get notified ? Or, will the job script simply wait infinitely ? Will the human being production system support get alerted ?

When that third party file transfer software is down, what happens to all the downloading job scripts ? Can all the job scripts automatically switch to use another file transfer software ?

If the DW department wants to upgrade the third party file transfer software or to replace it by another software, will the job script affected ?

To tackle all these questions, one solution is to build a centralized file transfer request manager as an agent or a middle-man between the job scripts and the third party file transfer software.

First of all, the DW job scripts should not call the third party file transfer software directly. Instead, they will submit the file transfer requests to the file transfer request manager and then go sleeping. For example, job script-1 will submit the request of file-A, file-B, file-C, file-D & file-E to the manager and then go sleeping for 2 days. After 2 days, if all the 5 files are not received, the job script-1 should raise a non-zero return-code to the job scheduler to signal the production system support personnel, similarly for script-2. For script-3 and script-4, since they are weekly jobs, sleeping hour is only 1 day. For daily job script-5 & script-6, they can only sleep for a few hours. Each job script can control its own sleeping hours, depending on the average file transfer time of the job script.

On receiving the file transfer requests, the manager can then call the third party file transfer software to perform the actual file downloading.

Normally, the request is done in a first-come-file-serve basis. However, the manager can also allow daily jobs to jump queue. Daily jobs should have a higher priority always.

Also, the manager can control over the max file transfer session. If there are already 4 files performing transfer, the manager simply put all upcoming request queuing. Also, the manager can further control that each job can only occupy at most 2 file transfer sessions in order to avoid one single job to use up all the 4 sessions.

The manager should totally take care about the third party file transfer software. If the third party software is down, the manager should alert the human being production system support (i.e. PSS). After investigation, if the bug cannot be fixed shortly, this PSS can instruct the manger to switch to use another file transfer software. This is transparent to the DW job scripts.

For the handshaking between the manager and the job scripts, the manager to send signal to the job script to report whether the file transfer is successful or fail. When receiving a successful signal, the DW job script can do some post processing.

For example, when all the file-A, file-B, file-C, file-D & file-E are downloaded successfully, the manger can alert the job script-1. Another method is to let the job script-1 to count whether all the 5 files are downloaded, the manager does not perform the counting. When all the 5 files are downloaded successfully, job script-1 should wake up from sleeping (job script-1 sleeps at most 2 days). Then, job script-1 should give a zero return-code to the job scheduler to indicate job successfully complete so that the scheduler can kick-out job(s) in the downstream.

When there is a software upgrade, only the manger is affected. The DW job scripts are totally transparent.

Furthermore, the manager can be enhanced to classify and distribute requests to different multiple queues. The requests of some VIP DW job scripts can go to high priority queues which is always served first. Those requests from some can-be-wait job scripts should go to lower priority queues. Also, maybe different queues are using different third party file transfer software. Maybe some queues are using software for secured channel to provide higher security level with maybe slower performance.

By the way, although this article is talking about file downloading, everything can also be applied to uploading as well. In other words, this situation and the file request manager can actually handle both file downloading / receiving / pulling as well as file uploading / sending / pushing. There can be out-queues and in-queues in the manger.


Monday, October 27, 2008

The date command in unix

In unix, the date command is to show the current date and time.

If you are the root, you can use the date command to set the system date (i.e. the current date as reported by the unix machine). Since the majority of the users are not root, for most of the time this command is used for display.

Without any parameter, just type the date command will display the current date and/or time in the default format.

But, you can set the display format as you like.

Usually, I will create file with a filename having the current date-time. Then I will use this date command. Here it is:

touch my_file.d`date +"%Y%m%d%H%M%S"`

Assuming now is 2008-12-31 23:58:59, this will create a file my_file.d20081231235859


Thursday, October 23, 2008

What is a line ?

When a human being reads a text file in computer, the file is well formatted line by line. When the file is a COBOL program in mainframe MVS, the program is displayed in a well formatted 80-column line by line. When the file is a C program in unix, it is also formatted well line by line, similarly for many DOS files.

Human beings see the text file as a line-by-line file. How does the computer see this file ?

Actually, the computer does NOT see the file in a human being line-by-line concept.

In fact, the file is stored as a STREAM of bytes, i.e. a byte following a byte continuously until the end of the file. Then, some special handling (e.g. using line delimiter or else) is done to identify which portion is line-1 and which portion is line-2 in that long stream of bytes.

For example, when you see this 2-line file (named C:\example.txt) in DOS:

This is first line.
This is second line.

This file has 2 lines. The first line [ This is first line. ] has 19 characters from T to the last period. Similarly, the second line [ This is second line. ] has 20 characters. One can count a total of 39 characters.

However, when you use the DOS command [ dir ] to examine the file size:

C:\> dir example.txt
2006-03-20  13:39                41 example.txt
1 File(s)             41 bytes
This [ dir ] command reports a file size of 41 byte, not 39 byte. Why there are 2 more bytes ?

Actually, how the file is stored in DOS ? Using the [ debug ] program, the following will be seen:

C:\> debug example.txt
-d
0B1A:0100  54 68 69 73 20 69 73 20-66 69 72 73 74 20 6C 69   This is first li
0B1A:0110  6E 65 2E 0D 0A 54 68 69-73 20 69 73 20 73 65 63   ne...This is sec
0B1A:0120  6F 6E 64 20 6C 69 6E 65-2E 6B 6A 6B 6A 65 72 6A   ond line.kjkjerj
0B1A:0130  20 64 67 6B 3B 6C 64 73-20 6C 6B 6A 66 67 6C 73    dgk;lds lkjfgls
0B1A:0140  20 64 68 6A 73 64 6B 68-6A 6B 73 68 20 73 20 68    dhjsdkhjksh s h
0B1A:0150  6B 73 20 68 20 73 68 20-73 20 68 20 64 73 68 20   ks h sh s h dsh
0B1A:0160  66 64 73 20 68 20 73 66-64 68 20 6B 20 73 68 20   fds h sfdh k sh
0B1A:0170  6B 68 6A 6B 73 68 6B 20-73 68 20 73 66 64 68 20   khjkshk sh sfdh
-q

As one can see, the file is stored as a STREAM of characters in the harddisk. After the string [ This is first line. ], one can find 2 characters [ 0D 0A ]. Then, the second line follows.

This [ 0D 0A ] characters are termed line delimiter. This 39-byte information plus 2-byte line delimiter results in a 41-byte file.

Also, this line delimiter [ 0D 0A ] tells the software editor to display the file into 2 lines.

According to ASCII encoding sequence, [ 0D ] is the decimal value 13. This [ 0D ] is called [ carriage return ], with an abbreviation [ CR ]. Similarly, [ 0A ] is decimal 10, called [ line feed ], abbreviated as [ LF ]. Together, [ 0D 0A ] are represented by CRLF.

In the world of unix, the line delimiter is [ 0A ] for most of the common settings.

As a result, when using FTP to transfer files between DOS and unix, it is better to use the [ ascii ] option to turn on the line delimiter conversion between [ 0D 0A ] and [ 0A ]. If someone forget to do so, after uploading a DOS file into unix, there will be a ^M character at the end of each line (when the file is opened by vi editor). This ^M is actually the [ 0D ] character which is NOT treated as line delimiter and is considered as normal character to be displayed.

Similar mistake can occur for downloading unix file into DOS. Without using the [ ascii ] option, there is no line delimiter conversion. The received file in DOS will be delimited by [ 0A ] only, not the common DOS line delimiter [ 0D 0A ]. So far, the Notepad application CANNOT recognize this [ 0A ] as line delimiter. You will see all the line mess together into one very long line. Another application, Wordpad, is more intelligent. It knows that [ 0A ] is also a line delimiter. It can open the file normally for human being to read.

In the mainframe MVS world, if the dataset file is a QSAM, there is no need to have line delimiter. The dataset organization has already tell the exact number of characters for each line.


Duplicate Open Current Folder in a New Window

Sometimes after I opened a folder in Win7, I would like to duplicate open the same folder again in another explorer window. Then, I can ope...