#! /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