Thursday, December 17, 2015

Creating a self-extracting tar.gz

Motivation


Winzip can create self-extracting executable. Actually this is the unzip utility together with content of zip file that is being extracted when running the executable.

Recently I was working on distribution package of our software for Linux. On Windows we have a huge zip file and a small script that we run once zip is extracted. Scripts for Linux are a little bit more complicated due to necessity of granting permissions, creating user and group etc. So, I wrote script that does all necessary actions including the archive extracting. The disadvantage of this is that now the distribution consists of at least 2 files: the archive and the script.

So, I decided to check how to create self extracting archive on Linux.


Used commands

I started from the following exercise:

#!/bin/sh
echo $0
exit
foo bar


This script runs ignoring the last line "foo bar". 
Then I created tar.gz file and appended it to this script:

cat script.sh my.tar.gz >script.with.tar.sh

Although now the script contains binary content of tar.gz it runs as expected. 
But I want to create self extracting script. Therefore I need a way to separate script from its "attachment". Command "dd" helps to implement this:

dd bs=1 skip=$SCRIPT_PREFIX  if=$SELF_EXTRACTING_TAR

But how can script with attachment extract size of its scripting part? If script contains known number of lines (e.g. 3) we can do the following:

head -3 $SCRIPT | wc -c


Script can access its own name using variable $0
Taking both commands together we can write line that extracts attachment appended to script:

dd bs=1 skip=`head -3 $0 | wc -c` if=$0

Extracting tar.gz can be achieve using command 

gunzip -c  | tar -x

So, this command extracts the attached tar.gz to current directory:

dd bs=1 skip=`head -3 $0 | wc -c` if=$0 | gunzip -c | tar -x


Script

It is a good idea to create script that takes regular tar.gz and creates self-extracting archive.
The script is available here. It accepts the following arguments:

  1. mandatory path to tar.gz 
  2. optional command that is automatically executed right after the archive extracting. Typically it is script packaged into the tar. 
The name of resulting executable is as name of tar.gz with suffix ".self".



Usage Examples: 

Create self-extracted executable: 
./selftar.sh my.tar.gz

Create self-extracted executable with command executed after archive extracting: 
./selftar.sh my.tar.gz "folder/install.sh"

Both examples create executable file my.tar.gz.self that extracts files initially packaged to my.tar.gz to current directory:

./my.tar.gz.self


Usage

This script and article were inspired by my work on distribution package based on simple archive. Generally this technique is wrong by definition. Distribution package depends on the target platform and should be created utilizing the platform specific tools: .msi for MS Windows, .rpm for RedHat, .deb for Debian etc. Self-extracting executable however allows creating simple package that can be used on most Unix based platforms that is very convenient especially when the packaged application is written in cross-platform language like java.