Self-Extracting Archives

D

DevynCJohnson

Guest
slide.jpg

Many Windows users are familiar with self-extracting archives. These are special archives that do not depend on any software on the current system for extraction. This allows developers to place many files into a single archive (with or without compression). The user can then obtain the single file and open it without needing to install an application to open the archive. Self-extracting archives can be used to distribute files, make an installer, or store a stand-alone executable and its libraries in on file. However, does Linux have any kind of self-extracting archive or a need for it?

Self-extracting archives are available for Linux, and Linux has a use for this feature. For instance, Python developers may use Cxfreeze to create a stand-alone executable. However, many library files are in the directory with the stand-alone executable. With the use of a self-extracting archive, the developers can distribute a single executable file that already contains all of the needed libraries. Then, users would execute the single file without needing any additional software.

As another example, assume a developer makes a single program that is composed of multiple shell scripts. With a self-extracting archive, the many scripts can appear as one, thus making the program less confusing to use.


makeself

"makeself" is a utility that creates self-extracting archives. Developers would need to obtain makeself to create the archive, but users do not need any software. The user only needs to execute the archive to run the contained program or execute the archive to cause the contained files to be extracted. For developer/packager usage, run a command in this format "makeself [options] DIR NEW-FILENAME LABEL STARTUP [args]".

  • [options] - place parameters for makeself here
  • DIR - the name and path of the directory containing the files to place in the archive
  • NEW-FILENAME - the desired name for the self-extracting archive
  • LABEL - message displayed in a terminal when the archive is decompressed
  • STARTUP - if this archive contains a program/script, specify the executable file that is to be run
  • [args] - commands to run after the extraction

For illustration, after writing a program, the developer can package it by running -

makeself --nox11 --noprogress --nowait ./ezv-fstab/ ./ezv-fstab.run "Loading ezv-fstab" ./etc-fstab

The parameters make the extraction remain quiet and independent of the user's input (after the user executes the archive). "./ezv-fstab/" indicates the folder to package is in the current directory. "./ezv-fstab.run" is the name of the archive to create. The message is in quotes, and after that, the developer specifies the executable to run when executing the archive. The path is relative to the archive. So, "./etc-fstab" is in the top-level of the archive and is the executable that will be run when the archive is executed.

Other parameters exist for makeself, but the ones used above are likely to be used by most developers. View the manpages or documentation for more info.

To obtain "makeself", search your repositories/package-manager, go to (http://megastep.org/makeself/), or run "wget http://megastep.org/makeself/makeself-2.1.5.run". To install makeself by obtaining it using the former method, run the following code -

Code:
wget http://megastep.org/makeself/makeself-2.1.5.run
chmod 755 makeself-2.1.5.run
./makeself-2.1.5.run
cd makeself-2.1.5
cp *.sh /usr/bin

Two examples of multi-file programs that use makeself to become a single executable files include Color-kit ( http://dcjtech.info/topic/color-kit/ ) and EZV-fstab ( http://dcjtech.info/topic/ezv-fstab-easy-viewing-etcfstab/ ).



shar

"shar" is a shell script archive. This archive is only used for file storage and distribution. To use shar, type "shar ./* > ../FILE.shar" to archive all files in the current directory and save the shar-file in the directory above. Various parameters can be applied to shar to change the results of the created archive.

Various parameters can be applied when creating or extracting the archive. For instance, "-x" can be used during creation to inform the archive that when it extracts its contents existing files should be overwritten. Then, when a user obtains the shar archive and extracts it, any files with the same name as the archive's contents will be overwritten. This is useful for applying patches.

Shar archives can be used to "install" local programs or files. A developer could make a game that users can install locally in their Home folder. Then, updates and patches can be applied by extracting the newer shar into the game's directory. This is an example of a use for the "-x" parameter.

When creating a shar archive, the "-s" parameter can be used to specify the creator of the archive. For example, "shar -x -s [email protected] *.pdf > manual.shar" will create an archive that contains metadata specifying the person (or company) that packaged the archive. By default, when not explicitly using this option, the current system value will be used (USER@HOSTNAME).

The "-L" parameter allows users to specify the size at which the archive will split. For instance, "shar -L 5000000 *.LARGE-FILES > large.shar" will create an archive. Once the archive reaches five megabytes (5MB), then another archive will be made. Each created archive will be no larger than the specified value. When declaring the max archive size, type the value as bytes.

The "-l" (lowercase "L") parameter is the same as "-L". However, files will not be split. Thus, if the user specifies that the max size is 2MB (-l 2000000), then some archives may still exceed that limit. To explain, if an archive is 1.5MB and then the next file to add to the archive is 1MB, shar will not split the 1MB file, but will add the whole file to the archive. As a result, the archive is now 2.5MB.

Various parameters are also available to compress the archive. Without compression, the shar is a plain-text file containing the files (that are archived) and code (that provides the self-extracting features). With compression, the archive's code is still readable, but the files appear as random sequences of characters. Shar archives can be emailed to users as plain text. Copy the contents of a shar file into the body of an email. Then, the recipient can copy the email's body and paste the contents into a plain-text file.

To extract the files, execute the shar file. Users may need to give it executable permissions by running "chmod +x ./FILE.shar". Alternately, type "sh FILE.shar" to extract the shar archive without giving the file executable permissions.

There is an "unshar" command, although it seems useless to have a program that uncompresses a "self-extracting archive".

shar is a common GNU utility that can usually be obtained from the system's standard software-sources/repositories.



Security

Remember that self-extracting archives are executables that require executable permissions. Only execute a self-extracting archive from a trusted source. Otherwise, the system could suffer from malware, data-loss, and other security threats.


Sample shar contents
Code:
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.14).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh01090
# Made on 2014-09-22 20:53 EDT by <collier@Nacho-Linux>.
# Source directory was '/media/collier/PROGRAMMING/lib/gui-programs/__pycache__/build/ezv-fstab'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode  name
# ------ ---------- ------------------------------------------
#  17160 -rw-r--r-- _bz2.cpython-34m-x86_64-linux-gnu.so





>(((CODE REMOVED HERE)))





#  24960 -rw-r--r-- termios.cpython-34m-x86_64-linux-gnu.so
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
  echo 'Note: not verifying md5sums.  Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false

for dir in $PATH
do
  if test -f $dir/gettext \
  && ($dir/gettext --version >/dev/null 2>&1)
  then
  case `$dir/gettext --version 2>&1 | sed 1q` in
  *GNU*) gettext_dir=$dir
  set_echo=true
  break ;;
  esac
  fi
done

if ${set_echo}
then
  set_echo=false
  for dir in $PATH
  do
  if test -f $dir/shar \
  && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
  locale_dir=`$dir/shar --print-text-domain-dir`
  set_echo=true
  break
  fi
  done

  if ${set_echo}
  then
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
  fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
  then shar_n= shar_c='
'
  else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901

if  touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
  test ! -f ${st1} && test -f ${f}; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'

elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
  test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'

elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
  test ! -f ${st3} && test -f ${f}; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'

else
  shar_touch=:
  echo
  ${echo} 'WARNING: not restoring timestamps.  Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
  echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
  exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
  exit 1
fi
# ============= _bz2.cpython-34m-x86_64-linux-gnu.so ==============
if test -n "${keep_file}" && test -f '_bz2.cpython-34m-x86_64-linux-gnu.so'
then
${echo} "x - SKIPPING _bz2.cpython-34m-x86_64-linux-gnu.so (file already exists)"

else
${echo} "x - extracting _bz2.cpython-34m-x86_64-linux-gnu.so (text)"
  sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 _bz2.cpython-34m-x86_64-linux-gnu.so
M?T5,1@(!`0````````````,`/@`!````@!,```````!``````````(@\````
M`````````$``.``'`$``&@`9``$````%````````````````````````````
M````````1"P```````!$+```````````(````````0````8```"@+0``````
M`*`M(```````H"T@``````#0#0```````-@-```````````@```````"````
M!@```+@M````````N"T@``````"X+2```````.`!````````X`$````````(
M``````````0````$````R`$```````#(`0```````,@!````````)```````
M```D``````````0`````````4.5T9`0```!P*0```````'`I````````<"D`
M``````!T`````````'0`````````!`````````!1Y71D!@``````````````
M```````````````````````````````````````````0`````````%+E=&0$
M````H"T```````"@+2```````*`M(```````8`(```````!@`@````````$`





>(((CODE REMOVED HERE)))





M`P````````````````````````"<.P```````.@````````````````````!
/````````````````````
`
end
SHAR_EOF
  (set 20 14 04 11 10 15 15 '_bz2.cpython-34m-x86_64-linux-gnu.so'
  eval "${shar_touch}") && \
  chmod 0644 '_bz2.cpython-34m-x86_64-linux-gnu.so'
if test $? -ne 0
then ${echo} "restore of _bz2.cpython-34m-x86_64-linux-gnu.so failed"
fi
  if ${md5check}
  then (
  ${MD5SUM} -c >/dev/null 2>&1 || ${echo} '_bz2.cpython-34m-x86_64-linux-gnu.so': 'MD5 check failed'
  ) << \SHAR_EOF
0dc545d20fd965bcc8c7744fab556bb4  _bz2.cpython-34m-x86_64-linux-gnu.so
SHAR_EOF

else
test `LC_ALL=C wc -c < '_bz2.cpython-34m-x86_64-linux-gnu.so'` -ne 17160 && \
  ${echo} "restoration warning:  size of '_bz2.cpython-34m-x86_64-linux-gnu.so' is not 17160"
  fi
fi
# ============= _codecs_cn.cpython-34m-x86_64-linux-gnu.so ==============
if test -n "${keep_file}" && test -f '_codecs_cn.cpython-34m-x86_64-linux-gnu.so'
then
${echo} "x - SKIPPING _codecs_cn.cpython-34m-x86_64-linux-gnu.so (file already exists)"

else
${echo} "x - extracting _codecs_cn.cpython-34m-x86_64-linux-gnu.so (text)"
  sed 's/^X//' << 'SHAR_EOF' | uudecode &&
begin 600 _codecs_cn.cpython-34m-x86_64-linux-gnu.so
M?T5,1@(!`0````````````,`/@`!````H"X```````!``````````'!"`@``
M`````````$``.``'`$``&P`:``$````%````````````````````````````





>(((CODE REMOVED HERE)))





M```````````````!`````P`````````````````````````46@```````.@`
>```````````````````!````````````````````
`
end
SHAR_EOF
  (set 20 14 04 11 10 15 15 'termios.cpython-34m-x86_64-linux-gnu.so'
  eval "${shar_touch}") && \
  chmod 0644 'termios.cpython-34m-x86_64-linux-gnu.so'
if test $? -ne 0
then ${echo} "restore of termios.cpython-34m-x86_64-linux-gnu.so failed"
fi
  if ${md5check}
  then (
  ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'termios.cpython-34m-x86_64-linux-gnu.so': 'MD5 check failed'
  ) << \SHAR_EOF
f3b873a5ae869e89ed0c26a1875d5caa  termios.cpython-34m-x86_64-linux-gnu.so
SHAR_EOF

else
test `LC_ALL=C wc -c < 'termios.cpython-34m-x86_64-linux-gnu.so'` -ne 24960 && \
  ${echo} "restoration warning:  size of 'termios.cpython-34m-x86_64-linux-gnu.so' is not 24960"
  fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
  exit 1
fi
exit 0
 
Last edited:



Members online


Top