#! /bin/bash
# This program is part of the Qi package manager
#
# Copyright (C) 2015, 2016 Matias A. Fonzo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
# EXIT STATUS
# 0 = Successful completion
# 1 = Minor common errors (e.g: help usage, support not available)
# 2 = Command execution error
# 3 = Integrity check error for compressed files
# 4 = File empty, not regular, or expected
# Override locale settings
export LC_ALL=C
# Functions
show_help() {
printf '%s\n' \
"Usage: qi install [options] package(s).tlz" \
"Installs .tlz packages combined with graft(1) to link." \
"" \
"Install command options:" \
" -h display this help and exit" \
" -N don't read runtime configuration file" \
" -P package installation tree" \
" -T target directory for linking" \
" -p prune conflicts" \
" -r read package from the named pipe" \
" -v graft(1) verbosity (use -V instead for more verbosity)" \
" -w warn about the files that will be linked" \
"" \
"Aliases for this command: \`add'" \
""
}
# A function to reflect the base name
_basename() { local name="${1##*/}" ; printf %s "${name%$2}"; }
# Ignore some signals during the install
isignal() {
trap "" HUP INT
eval_cmd "$@"
trap - HUP INT
}
# Directory of functions
readonly fndir="${LIBEXECDIR}/functions"
# Load (externally) internal functions
source "${fndir}"/helpers || exit 1
source "${fndir}"/readconfig || exit 1
source "${fndir}"/showvar || exit 1
# Default variable values
rcfile=rcfile
packagedir=/usr/packages
targetdir=/
prune_conflicts=no_prune_conflicts
read_pipe=noread_pipe
verbose=""
warn=nowarn
# Handle command-line options.
#
# An indexed array is created when an option is set. It helps to the
# command line in order to take precedence over the config file
while getopts ":hNprvVw P:T:" option ; do
case "$option" in
(N)
rcfile=no_rcfile
;;
(P)
packagedir="$OPTARG"
cmdLineSets+=( packagedir )
;;
(T)
targetdir="$OPTARG"
cmdLineSets+=( targetdir )
;;
(p)
prune_conflicts=prune_conflicts
;;
(r)
read_pipe=read_pipe
;;
(v)
verbose=-v
;;
(V)
verbose=-V
;;
(w)
warn=warn
;;
(h)
show_help
exit 0
;;
:)
quit 1 \
"The option '-${OPTARG}' requires an argument" \
"Usage: qi install [-hNprvVw] [-P
] [-T ] package(s).tlz"
;;
\?)
quit 1 \
"qi: install: illegal option -- '-${OPTARG}'" \
"Usage: qi install [-hNprvVw] [-P ] [-T ] package(s).tlz"
;;
esac
done
shift "$((OPTIND - 1))"
# If there are no arguments, one package is required
if (( $# == 0 )) && [[ $read_pipe != read_pipe ]] ; then
quit 4 \
"\nqi: install: You must specify at least one package." \
"Try 'qi install -h' for more information."
fi
# Sanity check: graft's availability
if ! type -P graft > /dev/null ; then
quit 1 "\"qi install\" cannot operate without graft(1). Please check your PATH."
fi
# Read configuration file
if [[ $rcfile = rcfile ]] ; then
# To mark some variables. Redefinitions of this
# variables are not allowed from the config file
readonly prune_conflicts read_pipe verbose warn
# Check existence, from where to read
if [[ -e ~/.qirc ]] ; then
configFrom="~/.qirc" # $HOME.
elif [[ -e @SYSCONFDIR@/qirc ]] ; then
configFrom="@SYSCONFDIR@/qirc" # System-wide.
fi
# Check file integrity, content
if [[ -f $configFrom && -s $configFrom ]] ; then
echo "Processing '${configFrom}' ..."
readConfig < "$configFrom"
else
warn "WARNING: ${configFrom}: File empty or not regular."
fi
fi
# Unset from memory unnecessary variables, arrays, functions
unset rcfile configFrom cmdLineSets readConfig
# Set default mask
umask 022
# Create required directories (if needed)
eval_cmd "mkdir -p "$packagedir" "$targetdir""
# Set default graft options for the user or for the super-user
graft_options="-u -l ${packagedir}/graft-log"
if (( $UID == 0 )) ; then
graft_options="-P -l ${packagedir}/graft-log"
fi
# Read package from the named pipe if -r was given (client/reader)
if [[ $read_pipe = read_pipe ]] ; then
echo "qi: install: PIPE: Waiting for server to create the pipe ..."
until [[ -p /var/tmp/qi-pipe ]] ; do
sleep 10;
done
set -- # Unset positional parameters, setting '#' to zero.
IFS="" read -r < /var/tmp/qi-pipe
set -- "$@" "$REPLY"
unset REPLY
fi
# Main loop
for package in "$@" ; do
if [[ ! -f $package ]] ; then
quit 4 "qi: install: File '${package}' not found or not regular."
fi
# Check file extension
if [[ ${package##*.} != tlz ]] ; then
quit 4 "qi: install: File '${package}' does not end in .tlz"
fi
# Check and run the warn, if -w is given
if [[ $warn = warn ]] ; then
printf '%s\n' "" "%%% Scanning package '${package}' ..."
# Show file list inside the package excluding the directories
eval_cmd "tar -tvvf "$package" | awk '!/^drwx/'"
continue;
fi
# Get the name of the package without the extension
name="$(_basename "$package" .tlz)"
# Check the integrity of the tarball
echo "==> Checking integrity of '${name}.tlz' ..."
isignal 3 "tar -tf "$package" > /dev/null"
# To install the package
echo "==> Installing package \"${name}\" in \`${packagedir}' ..."
eval_cmd "mkdir -p "${packagedir}/$name""
# Proceed to unpack the package
isignal 3 "tar xpf "$package" -C "${packagedir}/$name""
# Remove objects (files, links or directories) from the target
# directory that are in conflict with the package directory
if [[ $prune_conflicts = prune_conflicts ]] ; then
isignal "graft -p -D $verbose -t "$targetdir" "${packagedir}/$name""
fi
# Graft the package
isignal "graft -i $graft_options $verbose -t "$targetdir" "${packagedir}/$name""
# Show package information from the recipe.
#
# Get the name of the package removing the last two segments "-"
pkgname="${name%-*-*}" # Removes -version-arch+build.
# Include possible recipe names composed as "kernel3.10"
for recipe in ""${packagedir}/${name}/var/lib/qi/recipes/${pkgname}*.recipe"" ; do
if [[ -f $recipe ]] ; then
# Display information using fold(1) for fancy format
showVar description notes homepage licenses "$recipe" | fold -w 72
break;
fi
done
unset name pkgname recipe
done