Saturday, September 27, 2008

Upgrade individual packages for Debian-based systems

If you are using Debian-based distributions (Debian, Ubuntu, etc), you are probably familiar with the apt-get update followed by the apt-get upgrade routine. That is what I regularly use to upgrade ALL packages that have an update available.

But what if you only want to upgrade certain individual packages?

apt-get upgrade will upgrade ALL or nothing. So, that is out of the question.

What you need is apt-get install. apt-get install serves dual purposes: install and upgrade. It installs a package if it is not already installed. If it is already installed, apt-get install will upgrade the package to the latest version.

You should still run apt-get update before apt-get install. You can specify one or more package names as arguments to the apt-get install command.

For example, to upgrade these 2 packages: libfreetype6, libtiff4:
$ sudo apt-get update
$ sudo apt-get install libfreetype6 libtiff4

Sunday, September 21, 2008

How to get the process start date and time

How can we determine when a running process was started?

The venerable ps command deserves first consideration.

Most Linux command-line users are familiar with either the standard UNIX notation or the BSD notation when it comes to specifying ps options.

If ps -ef is what you use, that is the UNIX notation.

$ ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 Sep20 ? 00:00:03 init [3]

peter 1218 1 0 Sep20 ? 00:21:35 /usr/lib/iceweasel/firefox-bin -a firefox

peter 4901 1 1 16:34 ? 00:01:12 /usr/bin/emacs-snapshot-gtk


The STIME column displays the start time or date. From the above, we can tell that process 4901 (emacs) began execution at 16:34 (4:34 pm). But on what day, today?

From the ps man page: 'Only the year will be displayed if the process was not started the same year ps was invoked, or "mmmdd" if it was not started the same day, or "HH:MM" otherwise.'

So, emacs was started at 16:34 TODAY.

What is the start time for the other process, the firefox process with pid 1218?

The STIME for process 1218 reads Sep20 (which was yesterday). But what time yesterday?

The default ps -ef only tells you the start date but NOT the time if a process was NOT started on the same day.

If the BSD notation is more familiar to you, you will find that ps aux yields similar results.

$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 1576 540 ? Ss Sep20 0:03 init[3]

peter 1218 0.5 8.9 201252 45456 ? Sl Sep20 21:35 /usr/lib/iceweasel/firefox-bin -a firefox


The Start column in the above output only reveals the start date if the process is older than the current day.

There are (at least) 2 ways to determine the exact start time if the process was started before the current day.

Solution 1
Specify elapsed time in the ps output format.

$ ps -eo pid,cmd,etime
PID CMD ELAPSED
1218 /usr/lib/iceweasel/firefox-bin - 2-16:04:45


The above ps command specifies 3 fields to be included in the output: the process pid, the command, and the elapsed time, respectively.

etime is the elapsed time since the process was started, in the form dd-hh:mm:ss. dd is the number of days; hh, the number of hours; mm, the number of minutes; ss, the number of seconds.

The firefox command started execution 2 days, 16 hours, 4 minutes and 45 seconds ago. To find the exact time, you need to do some simple math.

If you prefer the BSD notation, issue this command:
$ ps axo pid,cmd,etime
PID CMD ELAPSED

1218 /usr/lib/iceweasel/firefox-bin - 2-16:04:57


Solution 2
Get the process pid and read off the timestamp in the corresponding subdirectory in /proc.

First, get the process pid using the ps command (ps -ef or ps aux)

Then, use the ls command to display the creation timestamp of the directory.
$ ls -ld /proc/1218
dr-xr-xr-x 5 peter peter 0 Sep 20 16:14 /proc/1218


You can tell from the timestamp that the process 1218 began executing on Sept 20, 16:14.

If you can think of another clever way to get the start time and date, please let us know.

Tuesday, September 2, 2008

How to find and delete all hard links to a file

Deleting a file is deceptively simple. You can simply use the rm command like this.
$ rm file1


However, if the file has one or more hard links to it, life gets more interesting. You need to seek and destroy all hard links to the file.

A hard link is essentially another name for a file. Hard links to file1 can be created as follows:
$ ln file1 file2
$ ln file1 tmp/file3


file2 and file3 become another name of file1.

How do I know if some file has a hard link to it?

Do a long listing of the file like this.
$ ls -l file1
-rw-r--r-- 3 peter peter 0 2008-09-01 16:15 file1


Note that the hard link count has the value 3 (this is the number to the left of the file owner). It means that the physical file has 3 names: file1 and two others.

If you only rm file1, the other 2 names still exist, and users can still access the physical file using these 2 names.

To find out all hard links to file1, use this command.
$ find /home -xdev -samefile file1
/home/peter/file1
/home/peter/tmp/file3
/home/peter/file2


Note that we specified /home as the search starting point. You should replace /home with the mount point for the filesystem in which your file1 was created. (This is likely to be either /home or / for files in your home directory.)

The reason for using the filesystem's mount point is that hard links are restricted to reside in the same filesystem as the physical file. This means that file2 and file3 must be in the same filesystem as file1. Therefore, to find ALL hard links to a file, you must start search at the mount point of the filesystem.

The -xdev option instructs find NOT to traverse directories in other filesystems.

To find and delete all hard links to a file:
$ find /home -xdev -samefile file1 | xargs rm


An alternative (and slightly more complicated) method is by using inodes. An inode is a data structure assigned to a physical file that contains all its meta-information except the file's name(s).

All hard links to a physical file share the same inode, and have the same inode id number. Therefore, if you know the inode number of a file, you can find all hard links to the file by searching for files with the same inode number.

To display a file's inode number, use ls -i:

$ ls -li file1
2655341 -rw-r--r-- 3 peter peter 0 2008-09-02 19:09 file1


The first column in the above listing shows the file's inode number.

Now that you know the inode number of file1, you can use the find command to search for all files that have the same inode number:

$ find /home -xdev -inum 2655341
/home/peter/file1
/home/peter/tmp/file3
/home/peter/file2


To delete all hard links to the physical file:
$ find /home -xdev -inum 2655341 | xargs rm