From 7c79fc877789d5912271a4a8ed943e908676052a Mon Sep 17 00:00:00 2001 From: ILGUIZ LATYPOV Date: Mon, 30 May 2016 20:04:50 -0400 Subject: [PATCH 01/28] Emulate wget in all cases. Fixes #87. --- apt-cyg | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/apt-cyg b/apt-cyg index 84a2d5f..00044cf 100755 --- a/apt-cyg +++ b/apt-cyg @@ -124,10 +124,22 @@ function wget { command wget "$@" else warn wget is not installed, using lynx as fallback - set "${*: -1}" - lynx -source "$1" > "${1##*/}" + of= + while [[ $# -gt 1 ]] ; do + if [[ $1 == "-O" ]] ; then + shift + of="$1" + fi + shift + done + if [[ ${#of} -eq 0 ]] ; then + of="${1##*/}" + fi + echo + lynx -source "$1" \> "${of}" >&2 + lynx -source "$1" > "${of}" fi } +export -f wget function find-workspace { # default working directory and mirror @@ -424,7 +436,7 @@ function apt-searchall { for pkg in "${pks[@]}" do printf -v qs 'text=1&arch=%s&grep=%s' $arch "$pkg" - wget -O matches cygwin.com/cgi-bin2/package-grep.cgi?"$qs" + wget -O matches http://cygwin.com/cgi-bin2/package-grep.cgi?"$qs" awk ' NR == 1 {next} mc[$1]++ {next} From 718e33fc0b719929050735c031f92b9214da420b Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 3 Jun 2016 19:59:52 -0400 Subject: [PATCH 02/28] Allow running on older Bash versions now that we do not use a negative index. --- apt-cyg | 6 ------ 1 file changed, 6 deletions(-) diff --git a/apt-cyg b/apt-cyg index 00044cf..450b424 100755 --- a/apt-cyg +++ b/apt-cyg @@ -23,12 +23,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -if [ ${BASH_VERSINFO}${BASH_VERSINFO[1]} -lt 42 ] -then - echo 'Bash version 4.2+ required' - exit -fi - usage="\ NAME apt-cyg - package manager utility From 18da97935c61bb73a6a5900330c5e08a74418eb0 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 3 Jun 2016 20:36:29 -0400 Subject: [PATCH 03/28] Provide a default cache directory. Use the Unix format of the cache directory throughout the script, except when queried or set with apt-cache. --- apt-cyg | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/apt-cyg b/apt-cyg index 450b424..5b435c3 100755 --- a/apt-cyg +++ b/apt-cyg @@ -148,6 +148,12 @@ function find-workspace { print $2 } ' /etc/setup/setup.rc) + if [[ ${#cache} -eq 0 ]] ; then + mkdir -p /install + cache="/install" + else + cache=$(cygpath -ua "${cache}") + fi mirror=$(awk ' /last-mirror/ { @@ -155,6 +161,10 @@ function find-workspace { print $1 } ' /etc/setup/setup.rc) + if [[ ${#mirror} -eq 0 ]] ; then + mirror="http://mirrors.kernel.org/sourceware/cygwin/" + fi + mirrordir=$(sed ' s / %2f g s : %3a g From 5c6c7fae483605b305e65a39f1e17ad98b08e7b6 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 3 Jun 2016 20:50:27 -0400 Subject: [PATCH 04/28] Remove another dependency on Bash 4.2. --- apt-cyg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apt-cyg b/apt-cyg index 5b435c3..0ce1a49 100755 --- a/apt-cyg +++ b/apt-cyg @@ -487,7 +487,7 @@ function apt-install { mv /etc/setup/installed.db /etc/setup/installed.db-save mv /tmp/awk.$$ /etc/setup/installed.db - [ -v nodeps ] && continue + [[ -n "${nodeps+set}" ]] && continue # recursively install required packages requires=$(awk '$1=="requires", $0=$2' FS=': ' desc) @@ -514,7 +514,7 @@ function apt-install { # run all postinstall scripts - [ -v noscripts ] && continue + [[ -n "${noscripts+set}" ]] && continue find /etc/postinstall -name '*.sh' | while read script do echo Running $script From 0af2a8fe8bebfe7c29709ec17fee00bac51e73b6 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 3 Jun 2016 21:02:15 -0400 Subject: [PATCH 05/28] Allow mirror directories in the top-level Cygwin directory. --- apt-cyg | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/apt-cyg b/apt-cyg index 0ce1a49..3a065df 100755 --- a/apt-cyg +++ b/apt-cyg @@ -154,6 +154,11 @@ function find-workspace { else cache=$(cygpath -ua "${cache}") fi + if [[ "${cache%/}" == "${cache}" ]] ; then + cacheslash="${cache}/" + else + cacheslash="${cache}" + fi mirror=$(awk ' /last-mirror/ { @@ -170,8 +175,8 @@ function find-workspace { s : %3a g ' <<< "$mirror") - mkdir -p "$cache/$mirrordir/$arch" - cd "$cache/$mirrordir/$arch" + mkdir -p "$cacheslash$mirrordir/$arch" + cd "$cacheslash$mirrordir/$arch" if [ -e setup.ini ] then return 0 @@ -400,8 +405,8 @@ function download { 32) hash=md5sum ;; 128) hash=sha512sum ;; esac - mkdir -p "$cache/$mirrordir/$dn" - cd "$cache/$mirrordir/$dn" + mkdir -p "$cacheslash$mirrordir/$dn" + cd "$cacheslash$mirrordir/$dn" if ! test -e $bn || ! $hash -c <<< "$digest $bn" then wget -O $bn $mirror/$dn/$bn @@ -410,7 +415,7 @@ function download { tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz cd ~- - mv desc "$cache/$mirrordir/$dn" + mv desc "$cacheslash$mirrordir/$dn" echo $dn $bn > /tmp/dwn } @@ -470,7 +475,7 @@ function apt-install { read dn bn Date: Fri, 3 Jun 2016 21:27:20 -0400 Subject: [PATCH 06/28] Avoid depending on a feature of gzip 1.6+. --- apt-cyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-cyg b/apt-cyg index 3a065df..7404648 100755 --- a/apt-cyg +++ b/apt-cyg @@ -549,7 +549,7 @@ function apt-remove { warn Package manifest missing, cannot remove $pkg. Exiting exit 1 fi - gzip -dk setup/"$pkg".lst.gz + gzip -dc setup/"$pkg".lst.gz > setup/"$pkg".lst awk ' NR == FNR { if ($NF) ess[$NF] From cd18784af1644703705ebd1900624092319531aa Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 10 Jun 2016 23:10:17 -0400 Subject: [PATCH 07/28] Avoid exiting before uninstalling other packages. Use colours only with interactive output. --- apt-cyg | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/apt-cyg b/apt-cyg index 7404648..7a17744 100755 --- a/apt-cyg +++ b/apt-cyg @@ -129,7 +129,6 @@ function wget { if [[ ${#of} -eq 0 ]] ; then of="${1##*/}" fi - echo + lynx -source "$1" \> "${of}" >&2 lynx -source "$1" > "${of}" fi } @@ -212,7 +211,15 @@ function check-packages { } function warn { - printf '\e[1;31m%s\e[m\n' "$*" >&2 + if test -t 2 ; then + { + tput setaf 1 + echo -E "$*" + tput sgr0 + } >&2 + else + echo -E "$*" >&2 + fi } function apt-update { @@ -535,6 +542,7 @@ function apt-remove { check-packages cd /etc cygcheck awk bash bunzip2 grep gzip mv sed tar xz > setup/essential.lst + anypkgerr=0 for pkg in "${pks[@]}" do @@ -546,8 +554,9 @@ function apt-remove { if [ ! -e setup/"$pkg".lst.gz ] then - warn Package manifest missing, cannot remove $pkg. Exiting - exit 1 + warn Package manifest missing, cannot remove $pkg, skipping + anypkgerr=1 + continue fi gzip -dc setup/"$pkg".lst.gz > setup/"$pkg".lst awk ' @@ -584,11 +593,13 @@ function apt-remove { rm setup/"$pkg".lst if [ $esn = 1 ] then - warn apt-cyg cannot remove package $pkg, exiting - exit 1 + warn apt-cyg cannot remove package $pkg, skipping + anypkgerr=1 + continue fi done + return $anypkgerr } function apt-mirror { From cb1dca932c206933a267eb18e0be6f9cedd88361 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Wed, 22 Feb 2017 17:10:40 -0500 Subject: [PATCH 08/28] Allow forceful installs. --- apt-cyg | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/apt-cyg b/apt-cyg index 7a17744..40e1fa9 100755 --- a/apt-cyg +++ b/apt-cyg @@ -100,6 +100,9 @@ OPTIONS --nodeps Specify this option to skip all dependency checks. + --force + Ignore presence of the package when installing it. + --version Display version and exit. " @@ -472,8 +475,13 @@ function apt-install { if grep -q "^$pkg " /etc/setup/installed.db then - echo Package $pkg is already installed, skipping - continue + if [[ -n "${force+set}" ]] + then + echo Package $pkg found, reinstalling + else + echo Package $pkg is already installed, skipping + continue + fi fi (( sbq++ )) && echo echo Installing $pkg @@ -548,8 +556,13 @@ function apt-remove { if ! grep -q "^$pkg " setup/installed.db then - echo Package $pkg is not installed, skipping - continue + if [[ -n "${force+set}" ]] + then + echo Package $pkg not found in the list, removing from the disk + else + echo Package $pkg is not installed, skipping + continue + fi fi if [ ! -e setup/"$pkg".lst.gz ] @@ -665,6 +678,11 @@ do shift ;; + --force) + force=1 + shift + ;; + --version) printf "$version" exit From 05f75ead486e50acf32ea8a1434baf5f6146d07d Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 23 Feb 2017 13:33:09 -0500 Subject: [PATCH 09/28] Use a simpler interpreter that has a smaller number of requisite dependencies. --- apt-cyg | 359 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 195 insertions(+), 164 deletions(-) diff --git a/apt-cyg b/apt-cyg index 40e1fa9..6f03798 100755 --- a/apt-cyg +++ b/apt-cyg @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/ash # apt-cyg: install tool for Cygwin similar to debian apt-get # # The MIT License (MIT) @@ -115,29 +115,32 @@ The MIT License (MIT) Copyright (c) 2005-9 Stephen Jungels " -function wget { +export PATH=/bin:/usr/bin + +wget () { if command wget -h &>/dev/null then command wget "$@" else warn wget is not installed, using lynx as fallback of= - while [[ $# -gt 1 ]] ; do - if [[ $1 == "-O" ]] ; then + while [ $# -gt 1 ] ; do + if [ "$1" = "-O" ] ; then shift of="$1" fi shift done - if [[ ${#of} -eq 0 ]] ; then + if [ ${#of} -eq 0 ] ; then of="${1##*/}" fi lynx -source "$1" > "${of}" fi } -export -f wget +export wget + -function find-workspace { +find_workspace () { # default working directory and mirror # work wherever setup worked last, if possible @@ -150,13 +153,13 @@ function find-workspace { print $2 } ' /etc/setup/setup.rc) - if [[ ${#cache} -eq 0 ]] ; then + if [ ${#cache} -eq 0 ] ; then mkdir -p /install cache="/install" else cache=$(cygpath -ua "${cache}") fi - if [[ "${cache%/}" == "${cache}" ]] ; then + if [ "${cache%/}" = "${cache}" ] ; then cacheslash="${cache}/" else cacheslash="${cache}" @@ -168,14 +171,14 @@ function find-workspace { print $1 } ' /etc/setup/setup.rc) - if [[ ${#mirror} -eq 0 ]] ; then + if [ ${#mirror} -eq 0 ] ; then mirror="http://mirrors.kernel.org/sourceware/cygwin/" fi - mirrordir=$(sed ' + mirrordir=$(/bin/echo -E "${mirror}" | sed ' s / %2f g s : %3a g - ' <<< "$mirror") + ') mkdir -p "$cacheslash$mirrordir/$arch" cd "$cacheslash$mirrordir/$arch" @@ -183,12 +186,12 @@ function find-workspace { then return 0 else - get-setup + get_setup return 1 fi } -function get-setup { +get_setup () { touch setup.ini mv setup.ini setup.ini-save wget -N $mirror/$arch/setup.bz2 @@ -203,8 +206,8 @@ function get-setup { fi } -function check-packages { - if [[ $pks ]] +check_packages () { + if [ "$pks" ] then return 0 else @@ -213,7 +216,7 @@ function check-packages { fi } -function warn { +warn () { if test -t 2 ; then { tput setaf 1 @@ -225,17 +228,23 @@ function warn { fi } -function apt-update { - if find-workspace +error () { + echo "$*" >&2 + exit 1 +} +export error + +apt_update () { + if find_workspace then - get-setup + get_setup fi } -function apt-category { - check-packages - find-workspace - for pkg in "${pks[@]}" +apt_category () { + check_packages + find_workspace + for pkg in $pks do awk ' $1 == "@" { @@ -248,35 +257,41 @@ function apt-category { done } -function apt-list { +apt_list () { local sbq - for pkg in "${pks[@]}" + sbq=0 + for pkg in $pks do - let sbq++ && echo + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo awk 'NR>1 && $1~pkg && $0=$1' pkg="$pkg" /etc/setup/installed.db done - let sbq && return + [ $sbq -eq 0 ] || return awk 'NR>1 && $0=$1' /etc/setup/installed.db } -function apt-listall { - check-packages - find-workspace +apt_listall () { + check_packages + find_workspace local sbq - for pkg in "${pks[@]}" + sbq=0 + for pkg in $pks do - let sbq++ && echo + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo awk '$1~pkg && $0=$1' RS='\n\n@ ' FS='\n' pkg="$pkg" setup.ini done } -function apt-listfiles { - check-packages - find-workspace +apt_listfiles () { + check_packages + find_workspace local pkg sbq - for pkg in "${pks[@]}" + sbq=0 + for pkg in $pks do - (( sbq++ )) && echo + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo if [ ! -e /etc/setup/"$pkg".lst.gz ] then download "$pkg" @@ -285,10 +300,10 @@ function apt-listfiles { done } -function apt-show { - find-workspace - check-packages - for pkg in "${pks[@]}" +apt_show () { + find_workspace + check_packages + for pkg in $pks do (( notfirst++ )) && echo awk ' @@ -304,10 +319,10 @@ function apt-show { done } -function apt-depends { - find-workspace - check-packages - for pkg in "${pks[@]}" +apt_depends () { + find_workspace + check_packages + for pkg in $pks do awk ' @include "join" @@ -339,9 +354,9 @@ function apt-depends { done } -function apt-rdepends { - find-workspace - for pkg in "${pks[@]}" +apt_rdepends () { + find_workspace + for pkg in $pks do awk ' @include "join" @@ -373,24 +388,27 @@ function apt-rdepends { done } -function apt-download { - check-packages - find-workspace +apt_download () { + check_packages + find_workspace local pkg sbq - for pkg in "${pks[@]}" + sbq=0 + for pkg in $pks do - (( sbq++ )) && echo + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo download "$pkg" done } -function download { - local pkg digest digactual +download () { + local pkg digest digactual desc pkg=$1 # look for package and save desc file - awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > desc - if [ ! -s desc ] + desc="/tmp/desc$$.txt" + awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > "${desc}" + if [ ! -s "${desc}" ] then echo Unable to locate package $pkg exit 1 @@ -399,8 +417,8 @@ function download { # download and unpack the bz2 or xz file # pick the latest version, which comes first - set -- $(awk '$1 == "install:"' desc) - if (( ! $# )) + set -- $(awk '$1 == "install:"' "${desc}") + if [ $# -eq 0 ] then echo 'Could not find "install" in package description: obsolete package?' exit 1 @@ -416,43 +434,45 @@ function download { 128) hash=sha512sum ;; esac mkdir -p "$cacheslash$mirrordir/$dn" - cd "$cacheslash$mirrordir/$dn" - if ! test -e $bn || ! $hash -c <<< "$digest $bn" - then - wget -O $bn $mirror/$dn/$bn - $hash -c <<< "$digest $bn" || exit - fi + ( + cd "$cacheslash$mirrordir/$dn" + if ! test -e $bn || ! echo "$digest $bn" | $hash -c + then + wget -O $bn $mirror/$dn/$bn + echo "$digest $bn" | $hash -c || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" + fi - tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz - cd ~- - mv desc "$cacheslash$mirrordir/$dn" - echo $dn $bn > /tmp/dwn + tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz + ) + mv "${desc}" "$cacheslash$mirrordir/$dn" + _return_download_dirname="${dn}" + _return_download_basename="${bn}" } -function apt-search { - check-packages +apt_search () { + check_packages echo Searching downloaded packages... - for pkg in "${pks[@]}" + for pkg in $pks do key=$(type -P "$pkg" | sed s./..) - [[ $key ]] || key=$pkg + [ "$key" ] || key=$pkg for manifest in /etc/setup/*.lst.gz do if gzip -cd $manifest | grep -q "$key" then - package=$(sed ' + package=$(echo "${manifest}" | sed ' s,/etc/setup/,, s,.lst.gz,, - ' <<< $manifest) + ') echo $package fi done done } -function apt-searchall { +apt_searchall () { cd /tmp - for pkg in "${pks[@]}" + for pkg in $pks do printf -v qs 'text=1&arch=%s&grep=%s' $arch "$pkg" wget -O matches http://cygwin.com/cgi-bin2/package-grep.cgi?"$qs" @@ -462,101 +482,101 @@ function apt-searchall { /-debuginfo-/ {next} /^cygwin32-/ {next} {print $1} - ' FS=-[[:digit:]] matches + ' FS=-[:digit:] matches done } -function apt-install { - check-packages - find-workspace +apt_install () { + check_packages + find_workspace local pkg dn bn requires wr package sbq script - for pkg in "${pks[@]}" + sbq=0 + for pkg in $pks do - - if grep -q "^$pkg " /etc/setup/installed.db - then - if [[ -n "${force+set}" ]] + if grep -q "^$pkg " /etc/setup/installed.db then - echo Package $pkg found, reinstalling - else - echo Package $pkg is already installed, skipping - continue + if [ -n "${force+set}" ] + then + echo Package $pkg found, reinstalling + else + echo Package $pkg is already installed, skipping + continue + fi + fi + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo + echo Installing $pkg + + download $pkg + dn="${_return_download_dirname}" + bn="${_return_download_basename}" + echo Unpacking... + + ( + cd "$cacheslash$mirrordir/$dn" + tar -x -C / -f $bn + ) + # update the package database + awk ' + ins != 1 && pkg < $1 { + print pkg, bz, 0 + ins = 1 + } + 1 + END { + if (ins != 1) print pkg, bz, 0 + } + ' pkg="$pkg" bz=$bn /etc/setup/installed.db > /tmp/awk.$$ + mv /etc/setup/installed.db /etc/setup/installed.db-save + mv /tmp/awk.$$ /etc/setup/installed.db + [ -n "${nodeps+set}" ] && continue + # recursively install required packages + requires=$(awk '$1=="requires", $0=$2' FS=': ' "${cacheslash}${mirrordir}/${dn}/desc") + wr=0 + if [ "$requires" ] + then + echo Package $pkg requires the following packages, installing: + echo $requires + for package in $requires + do + if grep -q "^$package " /etc/setup/installed.db + then + echo Package $package is already installed, skipping + continue + fi + apt_cyg install --noscripts $package || (( wr++ )) + done + fi + if [ $wr -ne 0 ] + then + echo some required packages did not install, continuing fi - fi - (( sbq++ )) && echo - echo Installing $pkg - - download $pkg - read dn bn /tmp/awk.$$ - mv /etc/setup/installed.db /etc/setup/installed.db-save - mv /tmp/awk.$$ /etc/setup/installed.db - [[ -n "${nodeps+set}" ]] && continue - # recursively install required packages + # run all postinstall scripts - requires=$(awk '$1=="requires", $0=$2' FS=': ' desc) - cd ~- - wr=0 - if [[ $requires ]] - then - echo Package $pkg requires the following packages, installing: - echo $requires - for package in $requires + [ -n "${noscripts+set}" ] && continue + find /etc/postinstall -name '*.sh' | while read script do - if grep -q "^$package " /etc/setup/installed.db - then - echo Package $package is already installed, skipping - continue - fi - apt-cyg install --noscripts $package || (( wr++ )) + echo Running $script + $script + mv $script $script.done done - fi - if (( wr )) - then - echo some required packages did not install, continuing - fi - - # run all postinstall scripts - - [[ -n "${noscripts+set}" ]] && continue - find /etc/postinstall -name '*.sh' | while read script - do - echo Running $script - $script - mv $script $script.done - done - echo Package $pkg installed + echo Package $pkg installed done } -function apt-remove { - check-packages +apt_remove () { + check_packages cd /etc cygcheck awk bash bunzip2 grep gzip mv sed tar xz > setup/essential.lst anypkgerr=0 - for pkg in "${pks[@]}" + for pkg in $pks do if ! grep -q "^$pkg " setup/installed.db then - if [[ -n "${force+set}" ]] + if [ -n "${force+set}" ] then echo Package $pkg not found in the list, removing from the disk else @@ -582,7 +602,7 @@ function apt-remove { } ' FS='[/\\\\]' setup/{essential,$pkg}.lst esn=$? - if [ $esn = 0 ] + if [ $esn -eq 0 ] then echo Removing $pkg if [ -e preremove/"$pkg".sh ] @@ -604,9 +624,9 @@ function apt-remove { echo Package $pkg removed fi rm setup/"$pkg".lst - if [ $esn = 1 ] + if [ $esn -eq 1 ] then - warn apt-cyg cannot remove package $pkg, skipping + warn apt_cyg cannot remove package $pkg, skipping anypkgerr=1 continue fi @@ -615,7 +635,7 @@ function apt-remove { return $anypkgerr } -function apt-mirror { +apt_mirror () { if [ "$pks" ] then awk -i inplace ' @@ -636,7 +656,7 @@ function apt-mirror { fi } -function apt-cache { +apt_cache () { if [ "$pks" ] then vas=$(cygpath -aw "$pks") @@ -660,7 +680,11 @@ function apt-cache { if [ -p /dev/stdin ] then - mapfile -t pks + while read -r p + do + read -r p + pks="$pks $p" + done fi # process options @@ -695,9 +719,9 @@ do list | cache | remove | depends | listall | download | listfiles |\ show | mirror | search | install | category | rdepends | searchall ) - if [[ $command ]] + if [ "$command" ] then - pks+=("$1") + pks="$pks $1" else command=$1 fi @@ -705,7 +729,7 @@ do ;; *) - pks+=("$1") + pks="$pks $1" shift ;; @@ -714,10 +738,17 @@ done set -a -if type -t apt-$command | grep -q function +if type apt_$command | grep -q function then - readonly arch=${HOSTTYPE/i6/x} - apt-$command + # arch=${HOSTTYPE/i6/x} + # arch=$(file /bin/cat | /bin/sed -e 's/.*\(x86[^,]*\),.*/\1/' -e 's/-/_/g') + if [ "${PROCESSOR_ARCHITECTURE}" = x86 -a ! "${PROCESSOR_ARCHITEW6432+set}" ] + then + arch="x86" + else + arch="x86_64" + fi + apt_$command else - printf "$usage" + error "$usage" fi From f8e3eb8327bd82bdba67ea877cf2a1875ae7db39 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 00:23:41 -0500 Subject: [PATCH 10/28] Speed up unpacking by avoiding lookups the (0) user ID of files in tar balls. Skip downloading, checksumming whenever possible. Enable an experimental 4-stage upgrade that uses a secondary root to separate the long installation process from swapping with subdirectories in the original root. This may still stall in installing to the secondary root as this still uses an in-place upgrade. --- apt-cyg | 415 +++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 308 insertions(+), 107 deletions(-) diff --git a/apt-cyg b/apt-cyg index 6f03798..d89a759 100755 --- a/apt-cyg +++ b/apt-cyg @@ -23,7 +23,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -usage="\ +usage=' NAME apt-cyg - package manager utility @@ -44,6 +44,23 @@ OPERATIONS remove Remove package(s) from the system. + upgradesetup + Prepare for an upgrade by copying required files to another root such as /fw, + c:\cygwin64\bin\ash.exe /bin/apt-cyg upgradesetup /fw + + upgradeinstall + Download and install all packages to another root such as /fw. + This needs to run from that root, e.g. as follows, + c:\cygwin64\fw\bin\ash.exe /bin/apt-cyg upgradeinstall + + upgradecopy + Replace directories of the actual root with those from the upgraded root, + c:\cygwin64\fw\bin\ash.exe /bin/apt-cyg upgradecopy + + upgradeclean + Remove the secondary root, + c:\cygwin64\bin\ash.exe /bin/apt-cyg upgradeclean + update Download a fresh copy of the master package list (setup.ini) from the server defined in setup.rc. @@ -100,29 +117,25 @@ OPTIONS --nodeps Specify this option to skip all dependency checks. - --force - Ignore presence of the package when installing it. - --version Display version and exit. -" +' -version="\ +version=' apt-cyg version 1 The MIT License (MIT) Copyright (c) 2005-9 Stephen Jungels -" +' export PATH=/bin:/usr/bin -wget () { - if command wget -h &>/dev/null +getfile () { + if wget -h > /dev/null 2>&1 then - command wget "$@" + wget --no-verbose "$@" else - warn wget is not installed, using lynx as fallback of= while [ $# -gt 1 ] ; do if [ "$1" = "-O" ] ; then @@ -134,10 +147,11 @@ wget () { if [ ${#of} -eq 0 ] ; then of="${1##*/}" fi + warn "lynx -source \"$1\"" lynx -source "$1" > "${of}" fi } -export wget +export getfile find_workspace () { @@ -180,8 +194,8 @@ find_workspace () { s : %3a g ') - mkdir -p "$cacheslash$mirrordir/$arch" - cd "$cacheslash$mirrordir/$arch" + mkdir -p "${cacheslash}${mirrordir}/${arch}" + cd "${cacheslash}${mirrordir}/${arch}" if [ -e setup.ini ] then return 0 @@ -194,14 +208,14 @@ find_workspace () { get_setup () { touch setup.ini mv setup.ini setup.ini-save - wget -N $mirror/$arch/setup.bz2 + getfile -N "${mirror}/${arch}/setup.bz2" if [ -e setup.bz2 ] then bunzip2 setup.bz2 mv setup setup.ini - echo Updated setup.ini + echo "Updated setup.ini" else - echo Error updating setup.ini, reverting + echo "Error updating setup.ini, reverting" || return 1 mv setup.ini-save setup.ini fi } @@ -220,20 +234,24 @@ warn () { if test -t 2 ; then { tput setaf 1 - echo -E "$*" + /bin/echo -E "$*" tput sgr0 } >&2 else - echo -E "$*" >&2 + /bin/echo -E "$*" >&2 fi } error () { - echo "$*" >&2 - exit 1 + warn "Error: $*" + return 1 } export error +qecho () { + [ "${quiet}" = "1" ] || /bin/echo -E "$@" +} + apt_update () { if find_workspace then @@ -264,10 +282,10 @@ apt_list () { do sbq=$((sbq + 1)) [ $sbq -eq 1 ] || echo - awk 'NR>1 && $1~pkg && $0=$1' pkg="$pkg" /etc/setup/installed.db + awk 'NR>1 && !a[$1]++ && $1~pkg && $0=$1' pkg="$pkg" /etc/setup/installed.db done [ $sbq -eq 0 ] || return - awk 'NR>1 && $0=$1' /etc/setup/installed.db + awk 'NR>1 && !a[$1]++ && $0=$1' /etc/setup/installed.db } apt_listall () { @@ -303,9 +321,12 @@ apt_listfiles () { apt_show () { find_workspace check_packages + local sbq + sbq=0 for pkg in $pks do - (( notfirst++ )) && echo + sbq=$((sbq + 1)) + [ $sbq -eq 1 ] || echo awk ' $1 == query { print @@ -402,7 +423,7 @@ apt_download () { } download () { - local pkg digest digactual desc + local pkg digest hflags desc pkg=$1 # look for package and save desc file @@ -410,8 +431,8 @@ download () { awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > "${desc}" if [ ! -s "${desc}" ] then - echo Unable to locate package $pkg - exit 1 + warn "Unable to locate package $pkg" + return 1 fi # download and unpack the bz2 or xz file @@ -420,12 +441,14 @@ download () { set -- $(awk '$1 == "install:"' "${desc}") if [ $# -eq 0 ] then - echo 'Could not find "install" in package description: obsolete package?' - exit 1 + error 'Could not find "install" in package description: obsolete package?' || return 1 fi dn=$(dirname $2) bn=$(basename $2) + _return_download_dirname="${dn}" + _return_download_basename="${bn}" + [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || return 0 # check the md5 digest=$4 @@ -433,25 +456,27 @@ download () { 32) hash=md5sum ;; 128) hash=sha512sum ;; esac - mkdir -p "$cacheslash$mirrordir/$dn" + hflags="" + [ "${quiet}" != "1" ] || hflags="${hflags} --quiet" + mkdir -p "${cacheslash}${mirrordir}/${dn}" ( - cd "$cacheslash$mirrordir/$dn" - if ! test -e $bn || ! echo "$digest $bn" | $hash -c + cd "${cacheslash}${mirrordir}/${dn}" + if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} then - wget -O $bn $mirror/$dn/$bn - echo "$digest $bn" | $hash -c || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" + getfile -O "${bn}" "${mirror}/${dn}/${bn}" + echo "$digest $bn" | "${hash}" --check ${hflags} || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 + else + qecho "Reusing existing file ${cacheslash}${mirrordir}/${dn}/${bn}" fi - tar tf $bn | gzip > /etc/setup/"$pkg".lst.gz + tar --numeric-owner -tf "${bn}" | gzip > /etc/setup/"$pkg".lst.gz ) - mv "${desc}" "$cacheslash$mirrordir/$dn" - _return_download_dirname="${dn}" - _return_download_basename="${bn}" + mv "${desc}" "${cacheslash}${mirrordir}/${dn}/desc" } apt_search () { check_packages - echo Searching downloaded packages... + echo "Searching downloaded packages..." for pkg in $pks do key=$(type -P "$pkg" | sed s./..) @@ -464,28 +489,31 @@ apt_search () { s,/etc/setup/,, s,.lst.gz,, ') - echo $package + echo "$package" fi done done } apt_searchall () { - cd /tmp for pkg in $pks do printf -v qs 'text=1&arch=%s&grep=%s' $arch "$pkg" - wget -O matches http://cygwin.com/cgi-bin2/package-grep.cgi?"$qs" + getfile -O "/tmp/matches$$.txt" "http://cygwin.com/cgi-bin2/package-grep.cgi?$qs" awk ' NR == 1 {next} mc[$1]++ {next} /-debuginfo-/ {next} /^cygwin32-/ {next} {print $1} - ' FS=-[:digit:] matches + ' 'FS=-[:digit:]' "/tmp/matches$$.txt" + rm -f "/tmp/matches$$.txt" done } +indent=0 +ind="" + apt_install () { check_packages find_workspace @@ -495,103 +523,117 @@ apt_install () { do if grep -q "^$pkg " /etc/setup/installed.db then - if [ -n "${force+set}" ] + if [ "${force}" = "1" ] then - echo Package $pkg found, reinstalling + qecho "Package $pkg found, reinstalling" else - echo Package $pkg is already installed, skipping + qecho "Package $pkg is already installed, skipping" continue fi fi sbq=$((sbq + 1)) - [ $sbq -eq 1 ] || echo - echo Installing $pkg + [ $sbq -eq 1 ] || qecho + + if [ ${indent} -eq 0 ] + then + ind="" + else + ind=$(/bin/printf "%${indent}s" "") + fi + /bin/echo -n "${ind}Checking $pkg" - download $pkg + download "$pkg" || continue dn="${_return_download_dirname}" bn="${_return_download_basename}" - echo Unpacking... - - ( + [ -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || ( + /bin/echo -n ", unpacking" cd "$cacheslash$mirrordir/$dn" - tar -x -C / -f $bn - ) + tar --numeric-owner -x -C / -f $bn || error "Unpacking failed" || exit 1 + ) || continue + touch "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" # update the package database + # > Running setup does NOT attempt to re-install the packages identified by "0". + # https://cygwin.com/ml/cygwin/2016-09/msg00244.html awk ' - ins != 1 && pkg < $1 { + NR == 1 { + print + next + } + a[$1]++ { + next + } + ins != 1 && pkg <= $1 { print pkg, bz, 0 ins = 1 } + pkg == $1 { + next + } 1 END { if (ins != 1) print pkg, bz, 0 } - ' pkg="$pkg" bz=$bn /etc/setup/installed.db > /tmp/awk.$$ + ' pkg="$pkg" bz="$bn" /etc/setup/installed.db > /tmp/awk.$$ mv /etc/setup/installed.db /etc/setup/installed.db-save mv /tmp/awk.$$ /etc/setup/installed.db - [ -n "${nodeps+set}" ] && continue + [ "${nodeps}" != "1" ] || continue # recursively install required packages requires=$(awk '$1=="requires", $0=$2' FS=': ' "${cacheslash}${mirrordir}/${dn}/desc") wr=0 if [ "$requires" ] then - echo Package $pkg requires the following packages, installing: - echo $requires - for package in $requires - do - if grep -q "^$package " /etc/setup/installed.db - then - echo Package $package is already installed, skipping - continue - fi - apt_cyg install --noscripts $package || (( wr++ )) - done + echo + qecho "${ind}Package $pkg requires $requires" + indent=$((indent+1)) + ( noscripts=1 ; unset force; pks=$requires ; apt_install ) || wr=1 + indent=$((indent-1)) + else + echo fi if [ $wr -ne 0 ] then - echo some required packages did not install, continuing + warn "${ind}some required packages did not install, continuing" fi # run all postinstall scripts - [ -n "${noscripts+set}" ] && continue - find /etc/postinstall -name '*.sh' | while read script + [ "${noscripts}" != "1" ] || continue + find /etc/postinstall -name '*.sh' | while read -r script do - echo Running $script - $script - mv $script $script.done + qecho "${ind}Running $script" + "$script" + mv "$script" "$script.done" done - echo Package $pkg installed + qecho "${ind}Package $pkg installed" done } apt_remove () { check_packages - cd /etc - cygcheck awk bash bunzip2 grep gzip mv sed tar xz > setup/essential.lst + cygcheck awk bash bunzip2 grep gzip mv sed tar xz > /etc/setup/essential.lst anypkgerr=0 for pkg in $pks do - if ! grep -q "^$pkg " setup/installed.db + if ! grep -q "^$pkg " /etc/setup/installed.db then - if [ -n "${force+set}" ] + if [ "${force}" = "1" ] then - echo Package $pkg not found in the list, removing from the disk + qecho "Package $pkg not found in the list, removing from the disk" else - echo Package $pkg is not installed, skipping + qecho "Package $pkg is not installed, skipping" continue fi fi - if [ ! -e setup/"$pkg".lst.gz ] + if [ ! -e /etc/setup/"$pkg".lst.gz ] then - warn Package manifest missing, cannot remove $pkg, skipping + warn "Package manifest missing, cannot remove $pkg, skipping" anypkgerr=1 continue fi - gzip -dc setup/"$pkg".lst.gz > setup/"$pkg".lst + gzip -dc /etc/setup/"$pkg".lst.gz > /etc/setup/"$pkg".lst awk ' NR == FNR { if ($NF) ess[$NF] @@ -600,33 +642,29 @@ apt_remove () { $NF in ess { exit 1 } - ' FS='[/\\\\]' setup/{essential,$pkg}.lst + ' FS='[/\\\\]' /etc/setup/essential.lst /etc/setup/"$pkg".lst esn=$? if [ $esn -eq 0 ] then - echo Removing $pkg - if [ -e preremove/"$pkg".sh ] + echo "Removing $pkg" + if [ -e /etc/preremove/"$pkg".sh ] then - preremove/"$pkg".sh - rm preremove/"$pkg".sh + /etc/preremove/"$pkg".sh + rm /etc/preremove/"$pkg".sh fi - mapfile dt < setup/"$pkg".lst - for each in ${dt[*]} + while read -r each do - [ -f /$each ] && rm /$each - done - for each in ${dt[*]} - do - [ -d /$each ] && rmdir --i /$each - done - rm -f setup/"$pkg".lst.gz postinstall/"$pkg".sh.done - awk -i inplace '$1 != ENVIRON["pkg"]' setup/installed.db - echo Package $pkg removed + [ ! -f "/$each" ] || rm "/$each" + [ ! -d "/$each" ] || rmdir --i "/$each" + done < /etc/setup/"$pkg".lst + rm -f /etc/setup/"$pkg".lst.gz /etc/postinstall/"$pkg".sh.done + awk -i inplace '$1 != ENVIRON["pkg"]' /etc/setup/installed.db + qecho "Package $pkg removed" fi - rm setup/"$pkg".lst + rm /etc/setup/"$pkg".lst if [ $esn -eq 1 ] then - warn apt_cyg cannot remove package $pkg, skipping + warn "apt-cyg cannot remove package $pkg, skipping" anypkgerr=1 continue fi @@ -656,6 +694,167 @@ apt_mirror () { fi } +# TODO: Run upgrade from the actual root. Include prepupgrade into it as well. +# Use the other root as a prefix in all functions. + +apt_upgradesetup() { + local preproot + preproot=/fw + if [ "$pks" ] + then + preproot="$pks" + fi + if [ "${preproot}" = "/" ] + then + error "prepupgrade needs a separate root" || return 1 + fi + if [ -d "${preproot}" ] + then + echo "Skipping the setup of a secondary root in ${preproot} as it already exists" + return + fi + local preprootnative + preprootnative=$(cygpath -wa "${preproot}") + qecho "Copying system directories to the prepared root in ${preprootnative}..." + mkdir -p "${preproot}" "${preproot}/dev" "${preproot}/proc" + mkdir -p -m a=rxwt "${preproot}/tmp" + ln -sf /proc/self/fd/0 "${preproot}/dev/stdin" + ln -sf /proc/self/fd/1 "${preproot}/dev/stdout" + ln -sf /proc/self/fd/2 "${preproot}/dev/stderr" + ln -sf /proc/self/fd "${preproot}/dev/fd" + + # mkdir -p "${preproot}/bin" "${preproot}/usr" "${preproot}/etc" \ + # "${preproot}/sbin" "${preproot}/lib" "${preproot}/var" \ + # "${preproot}/tmp" "${preproot}/proc" "${preproot}/dev" + ## cp -av /bin/cygwin1.dll /bin/ash.exe /bin/grep.exe /bin/awk.exe /bin/cygpath.exe /bin/apt-cyg "${preproot}/bin/" + cp -dr /bin /usr /etc /sbin /lib /var "${preproot%/}/" || : + mv "${preproot%/}/etc/fstab" "${preproot%/}/etc/fstab.prep" || error "Moving ${preproot%/}/etc/fstab" || return 1 + umount "${preproot%/}/usr/bin" || : + umount "${preproot%/}/usr/lib" || : + rm -rf "${preproot%/}/usr/bin" "${preproot%/}/usr/lib" + mount "${preprootnative}\\bin" "${preproot%/}/usr/bin" || error "Mounting ${preproot%/}/usr/bin" || return 1 + mount "${preprootnative}\\lib" "${preproot%/}/usr/lib" || error "Mounting ${preproot%/}/usr/lib" || return 1 + + qecho "Resetting permissions to the prepared root in ${preprootnative}..." + local winsys + winsys=$(cygpath -S) + "${winsys}/icacls.exe" "${preprootnative}" /reset /t /c /l > /dev/null + cygpath -aw / > "${preproot}/origroot" +} + +apt_upgradeinstall() { + if [ -s /origroot ] + then + origroot=$(cat /origroot) + fi + if [ ! "$origroot" ] + then + error "Could not find a reference to the actual root that needs creating with apt-cyg prepupgrade" || return 1 + fi + preproot="/" + preprootnative=$(cygpath -wa "${preproot}") + + # umount "${preproot%/}/usr/bin" || : # Operation not permitted + # umount "${preproot%/}/usr/lib" || : # Operation not permitted + ## /bin/rm -rf "${preproot%/}/usr/bin" "${preproot%/}/usr/lib" + # /bin/mount "${preprootnative}\\bin" "${preproot%/}/usr/bin" || : # Couldn't determine mount type [..] not permitted + # /bin/mount "${preprootnative}\\lib" "${preproot%/}/usr/lib" || : # Couldn't determine mount type [..] not permitted + if [ ! "$pks" ] + then + pks=$(awk 'NR>1 && !a[$1]++ && $0=$1' /etc/setup/installed.db) + fi + force=1 quiet=1 apt_install +} + +apt_upgradecopy() { + if [ -s /origroot ] + then + origroot=$(cat /origroot) + fi + if [ ! "$origroot" ] + then + error "Could not find a reference to the actual root that needs creating with apt-cyg prepupgrade" || return 1 + fi + local winsys + winsys=$(cygpath -S) + local cygprocs pid + pid=$$ + "${winsys}/tasklist" /nh /m cygwin1.dll > "/tmp/cygprocs${pid}.txt" + cygprocs=$(sed -e '/^INFO:/d' -e 's/\r//g' -e 's/ \+/ /g' -e 's/ \+$//g' -e '/^$/d' -e "/ash.exe ${pid} cygwin1.dll/d" \ + "/tmp/cygprocs${pid}.txt" \ + | while read -r proc cpid mod ; do \ + ticpid=$("${winsys}/tasklist" /nh /fi "pid eq ${cpid}" | sed -e '/^INFO:/d' -e 's/\r//g' -e 's/ \+/ /g' -e 's/ \+$//g' -e '/^$/d') ; \ + if [ "${ticpid}" ] ; then \ + echo "${proc} ${cpid}" ; \ + fi ; \ + done) + rm -f "/tmp/cygprocs${pid}.txt" + if [ "$cygprocs" ] + then + ps -eW + error "Some Cygwin processes are still running (own PID ${pid}): +$cygprocs" || return 1 + fi + /bin/echo -E "Moving the original bin, usr, etc, sbin, lib, var away to *.bak in ${origroot} ..." + rm -rf "${origroot}/bin.bak" "${origroot}/usr.bak" "${origroot}/etc.bak" \ + "${origroot}/sbin.bak" "${origroot}/lib.bak" "${origroot}/var.bak" + mv "${origroot}/bin" "${origroot}/bin.bak" || error "Moving ${origroot}/bin" || return 1 + mv "${origroot}/usr" "${origroot}/usr.bak" || error "Moving ${origroot}/usr" || return 1 + mv "${origroot}/sbin" "${origroot}/sbin.bak" || error "Moving ${origroot}/sbin" || return 1 + mv "${origroot}/lib" "${origroot}/lib.bak" || error "Moving ${origroot}/lib" || return 1 + mv "${origroot}/var" "${origroot}/var.bak" || error "Moving ${origroot}/var" || return 1 + mv "${origroot}/etc" "${origroot}/etc.bak" || error "Moving ${origroot}/etc" || return 1 + + preproot="/" + preprootnative=$(cygpath -wa "${preproot}") + # umount "${preproot%/}/usr/bin" || : + # umount "${preproot%/}/usr/lib" || : + ## rm -rf "${preproot%/}/usr/bin" "${preproot%/}/usr/lib" + ## mount "${preprootnative}\\bin" "${preproot%/}/usr/bin" + ## mount "${preprootnative}\\lib" "${preproot%/}/usr/lib" + + /bin/echo -E "Copying upgraded files from ${preprootnative}/{bin,usr,etc,sbin,lib,var} to ${origroot}/ ..." + cp -dr "${preproot%/}/bin" "${origroot}/" || error "Copying ${preproot%/}/bin" || return 1 + mkdir -p "${origroot}/usr" + local d n + for d in "${preproot%/}/usr/"* + do + n="${d##*/}" + case "${n}" in + (\*|bin|lib) + ;; + (*) + cp -dr "${d}" "${origroot}/usr/" || error "Copying ${d}" || return 1 + ;; + esac + done + cp -dr "${preproot%/}/etc" "${origroot}/" || error "Copying ${preproot%/}/etc" || return 1 + mv "${origroot}/etc/fstab.prep" "${origroot}/etc/fstab" || : + cp -dr "${preproot%/}/sbin" "${origroot}/" || error "Copying ${preproot%/}/sbin" || return 1 + cp -dr "${preproot%/}/lib" "${origroot}/" || error "Copying ${preproot%/}/lib" || return 1 + cp -dr "${preproot%/}/var" "${origroot}/" || error "Copying ${preproot%/}/var" || return 1 +} + +apt_upgradeclean() { + local preproot + preproot=/fw + if [ "$pks" ] + then + preproot="$pks" + fi + preproot=$(cygpath -ua "${preproot}") + if [ "${preproot}" = "/" -o ! "${preproot#/cygdrive/}" = "${preproot}" ] + then + error "Expecting another root such as /fw and not ${preproot} in this commitupgrade call" || return 1 + fi + + /bin/echo -E "Cleaning up the secondary root ${preproot} ..." + rm -rf "${preproot}" + echo "Cleaning up files stashed by the upgrade in /bin.bak, /usr.bak, /etc.bak ...." + rm -rf /bin.bak /usr.bak /etc.bak /sbin.bak /lib.bak /var.bak +} + + apt_cache () { if [ "$pks" ] then @@ -718,10 +917,11 @@ do ;; list | cache | remove | depends | listall | download | listfiles |\ - show | mirror | search | install | category | rdepends | searchall ) + show | mirror | search | install | category | rdepends | searchall |\ + upgradesetup | upgradeinstall | upgradecopy | upgradeclean) if [ "$command" ] then - pks="$pks $1" + pks="${pks}${pks:+ }$1" else command=$1 fi @@ -729,7 +929,7 @@ do ;; *) - pks="$pks $1" + pks="${pks}${pks:+ }$1" shift ;; @@ -748,7 +948,8 @@ then else arch="x86_64" fi - apt_$command + "apt_${command}" else - error "$usage" + /bin/echo -E "$usage" + exit 1 fi From da4f4285efc435bd76e87ab9315e825a6e25fe4d Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 10:00:08 -0500 Subject: [PATCH 11/28] Create a home directory as a work-around for Lynx. --- apt-cyg | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/apt-cyg b/apt-cyg index d89a759..b04ce63 100755 --- a/apt-cyg +++ b/apt-cyg @@ -147,7 +147,13 @@ getfile () { if [ ${#of} -eq 0 ] ; then of="${1##*/}" fi - warn "lynx -source \"$1\"" + qecho "lynx -source \"$1\"" + # Lynx fails when it cannot access the home directory for user + # configuration. Creating the home directory works this around. + if [ ! -d "${HOME}" ] + then + mkdir -p "${HOME}" + fi lynx -source "$1" > "${of}" fi } From 946f763b6f884a5b1d258c03600c5d954c6160d0 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 10:07:55 -0500 Subject: [PATCH 12/28] Quiet down hash failure messages as the error code already reports the failure. --- apt-cyg | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apt-cyg b/apt-cyg index b04ce63..efb7a17 100755 --- a/apt-cyg +++ b/apt-cyg @@ -467,10 +467,11 @@ download () { mkdir -p "${cacheslash}${mirrordir}/${dn}" ( cd "${cacheslash}${mirrordir}/${dn}" - if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} + if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null then getfile -O "${bn}" "${mirror}/${dn}/${bn}" - echo "$digest $bn" | "${hash}" --check ${hflags} || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 + echo "$digest $bn" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null \ + || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 else qecho "Reusing existing file ${cacheslash}${mirrordir}/${dn}/${bn}" fi From 5bc704a7c3940f310adf233c9fe0a6ce38f4a441 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 12:14:35 -0500 Subject: [PATCH 13/28] Avoid using sed in a critical function of upgrades when the requisite DLLs on which sed depends may be broken. --- apt-cyg | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/apt-cyg b/apt-cyg index efb7a17..3dd0064 100755 --- a/apt-cyg +++ b/apt-cyg @@ -131,6 +131,22 @@ Copyright (c) 2005-9 Stephen Jungels export PATH=/bin:/usr/bin +repl() { + local n m + n="$1" + while : + do + m="${n%%$2*}" + if [ "${m}" = "${n}" ] + then + _return_repl="${n}" + return + else + n="${m}$3${n#*$2}" + fi + done +} + getfile () { if wget -h > /dev/null 2>&1 then @@ -195,10 +211,9 @@ find_workspace () { mirror="http://mirrors.kernel.org/sourceware/cygwin/" fi - mirrordir=$(/bin/echo -E "${mirror}" | sed ' - s / %2f g - s : %3a g - ') + repl "${mirror}" "/" "%2f" + repl "${_return_repl}" ":" "%3a" + mirrordir="${_return_repl}" mkdir -p "${cacheslash}${mirrordir}/${arch}" cd "${cacheslash}${mirrordir}/${arch}" From 309aab07b83c9de1c2ad49e66d338b69236466d0 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 12:28:29 -0500 Subject: [PATCH 14/28] Show the location of the updated package list. --- apt-cyg | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/apt-cyg b/apt-cyg index 3dd0064..79c2ae7 100755 --- a/apt-cyg +++ b/apt-cyg @@ -227,17 +227,18 @@ find_workspace () { } get_setup () { - touch setup.ini - mv setup.ini setup.ini-save + if [ -f setup.ini ] + then + mv setup.ini setup.ini-save + fi getfile -N "${mirror}/${arch}/setup.bz2" - if [ -e setup.bz2 ] + if [ -e setup.bz2 ] && bunzip2 setup.bz2 then - bunzip2 setup.bz2 - mv setup setup.ini - echo "Updated setup.ini" + mv setup setup.ini || return 1 + /bin/echo -E "Updated setup.ini in $(cygpath -aw .)" else - echo "Error updating setup.ini, reverting" || return 1 - mv setup.ini-save setup.ini + /bin/echo -E "Error updating setup.ini in $(cygpath -aw . ), reverting" || return 1 + mv setup.ini-save setup.ini || : fi } From 7f54872404a0d467140102ca6897ce06ca85b646 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 12:46:39 -0500 Subject: [PATCH 15/28] Avoid doubling the trailing slash in the mirror when fetching its list of packages and packages themselves. --- apt-cyg | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/apt-cyg b/apt-cyg index 79c2ae7..5fe6132 100755 --- a/apt-cyg +++ b/apt-cyg @@ -217,13 +217,8 @@ find_workspace () { mkdir -p "${cacheslash}${mirrordir}/${arch}" cd "${cacheslash}${mirrordir}/${arch}" - if [ -e setup.ini ] - then - return 0 - else - get_setup - return 1 - fi + [ ! -e setup.ini ] || [ "$1" = "--update" ] || return 0 + get_setup } get_setup () { @@ -231,7 +226,7 @@ get_setup () { then mv setup.ini setup.ini-save fi - getfile -N "${mirror}/${arch}/setup.bz2" + getfile -N "${mirror%/}/${arch}/setup.bz2" if [ -e setup.bz2 ] && bunzip2 setup.bz2 then mv setup setup.ini || return 1 @@ -247,7 +242,7 @@ check_packages () { then return 0 else - echo No packages found. + echo "No packages found." return 1 fi } @@ -275,10 +270,7 @@ qecho () { } apt_update () { - if find_workspace - then - get_setup - fi + find_workspace --update } apt_category () { @@ -485,7 +477,7 @@ download () { cd "${cacheslash}${mirrordir}/${dn}" if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null then - getfile -O "${bn}" "${mirror}/${dn}/${bn}" + getfile -O "${bn}" "${mirror%/}/${dn}/${bn}" echo "$digest $bn" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null \ || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 else @@ -706,7 +698,7 @@ apt_mirror () { print "\t" pks } ' pks="$pks" /etc/setup/setup.rc - echo Mirror set to "$pks". + echo "Mirror set to \"$pks\"." else awk ' /last-mirror/ { From dcd4fa0f87a66bc050f901af36cbb7ff76267f08 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 12:51:53 -0500 Subject: [PATCH 16/28] Report download and save errors, then bail out. --- apt-cyg | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apt-cyg b/apt-cyg index 5fe6132..ef91d6c 100755 --- a/apt-cyg +++ b/apt-cyg @@ -150,7 +150,10 @@ repl() { getfile () { if wget -h > /dev/null 2>&1 then - wget --no-verbose "$@" + if ! wget --no-verbose "$@" + then + error "Downloading \"$1\" to \"${of}\"" + fi else of= while [ $# -gt 1 ] ; do @@ -170,7 +173,10 @@ getfile () { then mkdir -p "${HOME}" fi - lynx -source "$1" > "${of}" + if ! lynx -source "$1" > "${of}" + then + error "Downloading \"$1\" to \"${of}\"" + fi fi } export getfile From f9cdac20b9636b8c3502e18bd6e7dc0159669b0b Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 12:58:06 -0500 Subject: [PATCH 17/28] Report on file saving errors that appear flagged by a shell redirect in a message but not in an error code. --- apt-cyg | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apt-cyg b/apt-cyg index ef91d6c..f63c141 100755 --- a/apt-cyg +++ b/apt-cyg @@ -173,6 +173,7 @@ getfile () { then mkdir -p "${HOME}" fi + touch "${of}" || error "Touching \"${of}\"" if ! lynx -source "$1" > "${of}" then error "Downloading \"$1\" to \"${of}\"" @@ -491,7 +492,7 @@ download () { fi tar --numeric-owner -tf "${bn}" | gzip > /etc/setup/"$pkg".lst.gz - ) + ) || return 1 mv "${desc}" "${cacheslash}${mirrordir}/${dn}/desc" } From 9ac6d59f0ce71a59b6e0018f2c61d7d03c16a1db Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 13:14:18 -0500 Subject: [PATCH 18/28] Follow the change of the error function that no longer stops the shell level. Add a temporary trace message. --- apt-cyg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apt-cyg b/apt-cyg index f63c141..c36052b 100755 --- a/apt-cyg +++ b/apt-cyg @@ -152,7 +152,7 @@ getfile () { then if ! wget --no-verbose "$@" then - error "Downloading \"$1\" to \"${of}\"" + error "Downloading \"$1\" to \"${of}\"" || return 1 fi else of= @@ -173,10 +173,10 @@ getfile () { then mkdir -p "${HOME}" fi - touch "${of}" || error "Touching \"${of}\"" - if ! lynx -source "$1" > "${of}" + echo "Downloading \"$1\" ..." + if ! { lynx -source "$1" > "${of}" ; } then - error "Downloading \"$1\" to \"${of}\"" + error "Downloading \"$1\" to \"${of}\"" || return 1 fi fi } @@ -265,6 +265,7 @@ warn () { /bin/echo -E "$*" >&2 fi } +export warn error () { warn "Error: $*" From 8c8ac564f028383ac69e7adc55d6b5147e937562 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 13:25:47 -0500 Subject: [PATCH 19/28] Allow forcing package installation past the check in the list but not past checksumming. --- apt-cyg | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apt-cyg b/apt-cyg index c36052b..8fc6229 100755 --- a/apt-cyg +++ b/apt-cyg @@ -470,7 +470,7 @@ download () { bn=$(basename $2) _return_download_dirname="${dn}" _return_download_basename="${bn}" - [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || return 0 + [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" != "1" ] || return 0 # check the md5 digest=$4 @@ -546,7 +546,7 @@ apt_install () { do if grep -q "^$pkg " /etc/setup/installed.db then - if [ "${force}" = "1" ] + if [ "${force}" = "1" -o "${force_package_check}" = "1" ] then qecho "Package $pkg found, reinstalling" else @@ -568,7 +568,7 @@ apt_install () { download "$pkg" || continue dn="${_return_download_dirname}" bn="${_return_download_basename}" - [ -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || ( + [ -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" != "1" ] || ( /bin/echo -n ", unpacking" cd "$cacheslash$mirrordir/$dn" tar --numeric-owner -x -C / -f $bn || error "Unpacking failed" || exit 1 @@ -608,7 +608,7 @@ apt_install () { echo qecho "${ind}Package $pkg requires $requires" indent=$((indent+1)) - ( noscripts=1 ; unset force; pks=$requires ; apt_install ) || wr=1 + ( noscripts=1 ; unset force_package_check; pks=$requires ; apt_install ) || wr=1 indent=$((indent-1)) else echo @@ -786,7 +786,7 @@ apt_upgradeinstall() { then pks=$(awk 'NR>1 && !a[$1]++ && $0=$1' /etc/setup/installed.db) fi - force=1 quiet=1 apt_install + force_package_check=1 quiet=1 apt_install } apt_upgradecopy() { From 0867cb1ac7d8f260cb42bc2670d71e5b0ee3a1b8 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 13:32:39 -0500 Subject: [PATCH 20/28] Allow forcing package installation past the check in the list but not past checksumming. --- apt-cyg | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apt-cyg b/apt-cyg index 8fc6229..0d23395 100755 --- a/apt-cyg +++ b/apt-cyg @@ -470,7 +470,7 @@ download () { bn=$(basename $2) _return_download_dirname="${dn}" _return_download_basename="${bn}" - [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" != "1" ] || return 0 + [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" = "1" ] || return 0 # check the md5 digest=$4 @@ -568,11 +568,12 @@ apt_install () { download "$pkg" || continue dn="${_return_download_dirname}" bn="${_return_download_basename}" - [ -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" != "1" ] || ( - /bin/echo -n ", unpacking" + [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" = "1" ] || continue + /bin/echo -n ", unpacking" + ( cd "$cacheslash$mirrordir/$dn" tar --numeric-owner -x -C / -f $bn || error "Unpacking failed" || exit 1 - ) || continue + ) touch "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" # update the package database # > Running setup does NOT attempt to re-install the packages identified by "0". From d1aef1064bcc203c767b6947ac4c9b5ba1545dab Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 23:23:58 -0500 Subject: [PATCH 21/28] Unpack into the secondary root during upgrades. Complete upgrades with the postinstall scripts. --- apt-cyg | 280 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 167 insertions(+), 113 deletions(-) diff --git a/apt-cyg b/apt-cyg index 0d23395..2cebbb0 100755 --- a/apt-cyg +++ b/apt-cyg @@ -51,15 +51,15 @@ OPERATIONS upgradeinstall Download and install all packages to another root such as /fw. This needs to run from that root, e.g. as follows, - c:\cygwin64\fw\bin\ash.exe /bin/apt-cyg upgradeinstall + c:\cygwin64\bin\ash.exe /bin/apt-cyg upgradeinstall /fw upgradecopy Replace directories of the actual root with those from the upgraded root, c:\cygwin64\fw\bin\ash.exe /bin/apt-cyg upgradecopy - upgradeclean - Remove the secondary root, - c:\cygwin64\bin\ash.exe /bin/apt-cyg upgradeclean + upgradecomplete + Run post-install scripts and remove the secondary root, + c:\cygwin64\bin\ash.exe /bin/apt-cyg upgradecomplete update Download a fresh copy of the master package list (setup.ini) from the @@ -184,9 +184,9 @@ export getfile find_workspace () { - # default working directory and mirror - - # work wherever setup worked last, if possible + local setup + setup="${prefix}/etc/setup/setup.rc" + [ -f "${setup}" ] || error "No setup in $(cygpath -aw ${setup})" || return 1 cache=$(awk ' BEGIN { RS = "\n\\<" @@ -195,7 +195,7 @@ find_workspace () { $1 == "last-cache" { print $2 } - ' /etc/setup/setup.rc) + ' "${setup}") if [ ${#cache} -eq 0 ] ; then mkdir -p /install cache="/install" @@ -213,7 +213,7 @@ find_workspace () { getline print $1 } - ' /etc/setup/setup.rc) + ' "${setup}") if [ ${#mirror} -eq 0 ] ; then mirror="http://mirrors.kernel.org/sourceware/cygwin/" fi @@ -282,8 +282,8 @@ apt_update () { } apt_category () { - check_packages - find_workspace + check_packages || return 1 + find_workspace || return 1 for pkg in $pks do awk ' @@ -311,8 +311,8 @@ apt_list () { } apt_listall () { - check_packages - find_workspace + check_packages || return 1 + find_workspace || return 1 local sbq sbq=0 for pkg in $pks @@ -324,8 +324,8 @@ apt_listall () { } apt_listfiles () { - check_packages - find_workspace + check_packages || return 1 + find_workspace || return 1 local pkg sbq sbq=0 for pkg in $pks @@ -341,8 +341,8 @@ apt_listfiles () { } apt_show () { - find_workspace - check_packages + find_workspace || return 1 + check_packages || return 1 local sbq sbq=0 for pkg in $pks @@ -363,8 +363,8 @@ apt_show () { } apt_depends () { - find_workspace - check_packages + find_workspace || return 1 + check_packages || return 1 for pkg in $pks do awk ' @@ -398,7 +398,7 @@ apt_depends () { } apt_rdepends () { - find_workspace + find_workspace || return 1 for pkg in $pks do awk ' @@ -432,8 +432,8 @@ apt_rdepends () { } apt_download () { - check_packages - find_workspace + check_packages || return 1 + find_workspace || return 1 local pkg sbq sbq=0 for pkg in $pks @@ -445,12 +445,17 @@ apt_download () { } download () { - local pkg digest hflags desc - pkg=$1 + local clean pkg digest hflags desc + if [ "$1" = "--clean" ] + then + clean=1 + shift + fi + pkg="$1" # look for package and save desc file desc="/tmp/desc$$.txt" - awk '$1 == pc' RS='\n\n@ ' FS='\n' pc=$pkg setup.ini > "${desc}" + awk '$1 == pc' RS='\n\n@ ' FS='\n' pc="${pkg}" setup.ini > "${desc}" if [ ! -s "${desc}" ] then warn "Unable to locate package $pkg" @@ -470,6 +475,11 @@ download () { bn=$(basename $2) _return_download_dirname="${dn}" _return_download_basename="${bn}" + if [ "${clean}" = "1" ] + then + rm -rf "${cacheslash}${mirrordir}/${dn}" + return 0 + fi [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" = "1" ] || return 0 # check the md5 @@ -486,19 +496,20 @@ download () { if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null then getfile -O "${bn}" "${mirror%/}/${dn}/${bn}" + rm -f "${bn}.unpacked" echo "$digest $bn" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null \ || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 else qecho "Reusing existing file ${cacheslash}${mirrordir}/${dn}/${bn}" fi - tar --numeric-owner -tf "${bn}" | gzip > /etc/setup/"$pkg".lst.gz + tar --numeric-owner -tf "${bn}" | gzip > "${prefix}/etc/setup/${pkg}.lst.gz" ) || return 1 mv "${desc}" "${cacheslash}${mirrordir}/${dn}/desc" } apt_search () { - check_packages + check_packages || return 1 echo "Searching downloaded packages..." for pkg in $pks do @@ -536,20 +547,47 @@ apt_searchall () { indent=0 ind="" +force_package_check=1 + +read_upgraded() { + if [ -f "${prefix}/etc/setup/upgraded.txt" ] + then + read -r _return_upgraded_pks < "${prefix}/etc/setup/upgraded.txt" + else + _return_upgraded_pks="" + fi +} + +check_upgraded() { + read_upgraded + local p + for p in ${_return_upgraded_pks} + do + if [ "${p}" = "$1" ] + then + return 0 + fi + done + return 1 +} + +add_upgraded() { + read_upgraded + /bin/echo -E "${_return_upgraded_pks}${_return_upgraded_pks:+ }$1" > "${prefix}/etc/setup/upgraded.txt" +} apt_install () { - check_packages - find_workspace + check_packages || return 1 + find_workspace || return 1 local pkg dn bn requires wr package sbq script sbq=0 for pkg in $pks do - if grep -q "^$pkg " /etc/setup/installed.db + ! check_upgraded "${pkg}" || continue + if grep -q "^$pkg " "${prefix}/etc/setup/installed.db" then - if [ "${force}" = "1" -o "${force_package_check}" = "1" ] + if [ "${force}" != "1" -a "${force_package_check}" != "1" -a "${upgrade}" = "1" ] then - qecho "Package $pkg found, reinstalling" - else qecho "Package $pkg is already installed, skipping" continue fi @@ -563,16 +601,17 @@ apt_install () { else ind=$(/bin/printf "%${indent}s" "") fi - /bin/echo -n "${ind}Checking $pkg" + /bin/echo -n "${ind}Checking $pkg ..." download "$pkg" || continue dn="${_return_download_dirname}" bn="${_return_download_basename}" - [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" = "1" ] || continue - /bin/echo -n ", unpacking" + [ ! -f "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" ] || [ "${force}" = "1" ] || { echo; continue; } + /bin/echo -n " unpacking ..." ( - cd "$cacheslash$mirrordir/$dn" - tar --numeric-owner -x -C / -f $bn || error "Unpacking failed" || exit 1 + cd "${cacheslash}${mirrordir}/${dn}" + tar --numeric-owner -x -C "${prefix}/" -f "${bn}" \ + || error "Unpacking $(cygpath -aw ${cacheslash}${mirrordir}/${dn}/${bn}) in ${prefix}/" || return 1 ) touch "${cacheslash}${mirrordir}/${dn}/${bn}.unpacked" # update the package database @@ -597,10 +636,11 @@ apt_install () { END { if (ins != 1) print pkg, bz, 0 } - ' pkg="$pkg" bz="$bn" /etc/setup/installed.db > /tmp/awk.$$ - mv /etc/setup/installed.db /etc/setup/installed.db-save - mv /tmp/awk.$$ /etc/setup/installed.db - [ "${nodeps}" != "1" ] || continue + ' pkg="$pkg" bz="$bn" "${prefix}/etc/setup/installed.db" > "/tmp/awk.$$" || { echo; continue; } + mv "${prefix}/etc/setup/installed.db" "${prefix}/etc/setup/installed.db-save" || { echo; continue; } + mv "/tmp/awk.$$" "${prefix}/etc/setup/installed.db" || { echo; continue; } + add_upgraded "${pkg}" + [ "${nodeps}" != "1" ] || { echo; continue; } # recursively install required packages requires=$(awk '$1=="requires", $0=$2' FS=': ' "${cacheslash}${mirrordir}/${dn}/desc") wr=0 @@ -609,7 +649,7 @@ apt_install () { echo qecho "${ind}Package $pkg requires $requires" indent=$((indent+1)) - ( noscripts=1 ; unset force_package_check; pks=$requires ; apt_install ) || wr=1 + ( noscripts=1 ; unset force_package_check; pks="${requires}" ; prefix="${prefix}" ; apt_install ) || wr=1 indent=$((indent-1)) else echo @@ -620,9 +660,8 @@ apt_install () { fi # run all postinstall scripts - [ "${noscripts}" != "1" ] || continue - find /etc/postinstall -name '*.sh' | while read -r script + find "${prefix}/etc/postinstall" -name "*.sh" | while read -r script do qecho "${ind}Running $script" "$script" @@ -634,64 +673,63 @@ apt_install () { } apt_remove () { - check_packages + check_packages || return 1 + find_workspace || return 1 cygcheck awk bash bunzip2 grep gzip mv sed tar xz > /etc/setup/essential.lst anypkgerr=0 for pkg in $pks do - if ! grep -q "^$pkg " /etc/setup/installed.db - then - if [ "${force}" = "1" ] + download --clean "$pkg" || : + if ! grep -q "^$pkg " /etc/setup/installed.db then - qecho "Package $pkg not found in the list, removing from the disk" - else - qecho "Package $pkg is not installed, skipping" - continue + if [ "${force}" = "1" ] + then + qecho "Package $pkg not found in the list, removing from the disk" + else + qecho "Package $pkg is not installed, skipping" + continue + fi fi - fi - if [ ! -e /etc/setup/"$pkg".lst.gz ] - then - warn "Package manifest missing, cannot remove $pkg, skipping" - anypkgerr=1 - continue - fi - gzip -dc /etc/setup/"$pkg".lst.gz > /etc/setup/"$pkg".lst - awk ' - NR == FNR { - if ($NF) ess[$NF] - next - } - $NF in ess { - exit 1 - } - ' FS='[/\\\\]' /etc/setup/essential.lst /etc/setup/"$pkg".lst - esn=$? - if [ $esn -eq 0 ] - then - echo "Removing $pkg" - if [ -e /etc/preremove/"$pkg".sh ] + if [ ! -e /etc/setup/"$pkg".lst.gz ] then - /etc/preremove/"$pkg".sh - rm /etc/preremove/"$pkg".sh + warn "Package manifest missing, cannot remove $pkg, skipping" + anypkgerr=1 + continue + fi + gzip -dc /etc/setup/"$pkg".lst.gz > /etc/setup/"$pkg".lst + if awk ' + NR == FNR { + if ($NF) ess[$NF] + next + } + $NF in ess { + exit 1 + } + ' FS='[/\\\\]' /etc/setup/essential.lst /etc/setup/"$pkg".lst + then + echo "Removing $pkg" + if [ -e /etc/preremove/"$pkg".sh ] + then + /etc/preremove/"$pkg".sh + rm /etc/preremove/"$pkg".sh + fi + while read -r each + do + [ ! -f "/$each" ] || rm "/$each" + [ ! -d "/$each" ] || rmdir --i "/$each" + done < /etc/setup/"$pkg".lst + rm -f /etc/setup/"$pkg".lst.gz /etc/postinstall/"$pkg".sh.done + awk -i inplace '$1 != ENVIRON["pkg"]' /etc/setup/installed.db + rm /etc/setup/"$pkg".lst + qecho "Package $pkg removed" + else + rm /etc/setup/"$pkg".lst + warn "apt-cyg cannot remove package $pkg, skipping" + anypkgerr=1 + continue fi - while read -r each - do - [ ! -f "/$each" ] || rm "/$each" - [ ! -d "/$each" ] || rmdir --i "/$each" - done < /etc/setup/"$pkg".lst - rm -f /etc/setup/"$pkg".lst.gz /etc/postinstall/"$pkg".sh.done - awk -i inplace '$1 != ENVIRON["pkg"]' /etc/setup/installed.db - qecho "Package $pkg removed" - fi - rm /etc/setup/"$pkg".lst - if [ $esn -eq 1 ] - then - warn "apt-cyg cannot remove package $pkg, skipping" - anypkgerr=1 - continue - fi done return $anypkgerr @@ -742,10 +780,10 @@ apt_upgradesetup() { qecho "Copying system directories to the prepared root in ${preprootnative}..." mkdir -p "${preproot}" "${preproot}/dev" "${preproot}/proc" mkdir -p -m a=rxwt "${preproot}/tmp" - ln -sf /proc/self/fd/0 "${preproot}/dev/stdin" - ln -sf /proc/self/fd/1 "${preproot}/dev/stdout" - ln -sf /proc/self/fd/2 "${preproot}/dev/stderr" - ln -sf /proc/self/fd "${preproot}/dev/fd" + ln -sf /proc/self/fd/0 "${preproot}/dev/stdin" || : + ln -sf /proc/self/fd/1 "${preproot}/dev/stdout" || : + ln -sf /proc/self/fd/2 "${preproot}/dev/stderr" || : + ln -sf /proc/self/fd "${preproot}/dev/fd" || : # mkdir -p "${preproot}/bin" "${preproot}/usr" "${preproot}/etc" \ # "${preproot}/sbin" "${preproot}/lib" "${preproot}/var" \ @@ -767,27 +805,32 @@ apt_upgradesetup() { } apt_upgradeinstall() { - if [ -s /origroot ] + local preproot preprootnative + preproot=/fw + if [ "$pks" ] then - origroot=$(cat /origroot) + preproot="$pks" fi - if [ ! "$origroot" ] + if [ "${preproot}" = "/" ] then - error "Could not find a reference to the actual root that needs creating with apt-cyg prepupgrade" || return 1 + error "prepupgrade needs a separate root" || return 1 fi - preproot="/" preprootnative=$(cygpath -wa "${preproot}") - # umount "${preproot%/}/usr/bin" || : # Operation not permitted - # umount "${preproot%/}/usr/lib" || : # Operation not permitted - ## /bin/rm -rf "${preproot%/}/usr/bin" "${preproot%/}/usr/lib" - # /bin/mount "${preprootnative}\\bin" "${preproot%/}/usr/bin" || : # Couldn't determine mount type [..] not permitted - # /bin/mount "${preprootnative}\\lib" "${preproot%/}/usr/lib" || : # Couldn't determine mount type [..] not permitted + umount "${preproot%/}/usr/bin" || : # Operation not permitted + umount "${preproot%/}/usr/lib" || : # Operation not permitted + # /bin/rm -rf "${preproot%/}/usr/bin" "${preproot%/}/usr/lib" + /bin/mount "${preprootnative}\\bin" "${preproot%/}/usr/bin" || : # Couldn't determine mount type [..] not permitted + /bin/mount "${preprootnative}\\lib" "${preproot%/}/usr/lib" || : # Couldn't determine mount type [..] not permitted if [ ! "$pks" ] then - pks=$(awk 'NR>1 && !a[$1]++ && $0=$1' /etc/setup/installed.db) + pks=$(awk 'NR>1 && !a[$1]++ && $0=$1' "${preproot%/}/etc/setup/installed.db") fi - force_package_check=1 quiet=1 apt_install + prefix="${preproot%/}" noscripts=1 force=1 quiet=1 apt_install + qecho "Resetting permissions to the prepared root in ${preprootnative}..." + local winsys + winsys=$(cygpath -S) + "${winsys}/icacls.exe" "${preprootnative}" /reset /t /c /l > /dev/null } apt_upgradecopy() { @@ -819,6 +862,7 @@ apt_upgradecopy() { error "Some Cygwin processes are still running (own PID ${pid}): $cygprocs" || return 1 fi + /bin/echo -E "Moving the original bin, usr, etc, sbin, lib, var away to *.bak in ${origroot} ..." rm -rf "${origroot}/bin.bak" "${origroot}/usr.bak" "${origroot}/etc.bak" \ "${origroot}/sbin.bak" "${origroot}/lib.bak" "${origroot}/var.bak" @@ -859,7 +903,7 @@ $cygprocs" || return 1 cp -dr "${preproot%/}/var" "${origroot}/" || error "Copying ${preproot%/}/var" || return 1 } -apt_upgradeclean() { +apt_upgradecomplete() { local preproot preproot=/fw if [ "$pks" ] @@ -872,8 +916,17 @@ apt_upgradeclean() { error "Expecting another root such as /fw and not ${preproot} in this commitupgrade call" || return 1 fi + /bin/echo -E "Running postinstall scripts in $(cygpath -aw /etc/postinstall) ..." + find "/etc/postinstall" -name "*.sh" | while read -r script + do + qecho "Running $script" + "$script" + mv "$script" "$script.done" + done + /bin/echo -E "Cleaning up the secondary root ${preproot} ..." rm -rf "${preproot}" + echo "Cleaning up files stashed by the upgrade in /bin.bak, /usr.bak, /etc.bak ...." rm -rf /bin.bak /usr.bak /etc.bak /sbin.bak /lib.bak /var.bak } @@ -890,7 +943,7 @@ apt_cache () { print "\t" vas } ' vas="${vas//\\/\\\\}" /etc/setup/setup.rc - echo Cache set to "$vas". + /bin/echo -E "Cache set to \"${vas}\"." else awk ' /last-cache/ { @@ -906,7 +959,7 @@ then while read -r p do read -r p - pks="$pks $p" + pks="${pks}${pks:+ }${p}" done fi @@ -942,7 +995,7 @@ do list | cache | remove | depends | listall | download | listfiles |\ show | mirror | search | install | category | rdepends | searchall |\ - upgradesetup | upgradeinstall | upgradecopy | upgradeclean) + upgradesetup | upgradeinstall | upgradecopy | upgradecomplete) if [ "$command" ] then pks="${pks}${pks:+ }$1" @@ -972,6 +1025,7 @@ then else arch="x86_64" fi + rm -f "/etc/setup/upgraded.txt" "apt_${command}" else /bin/echo -E "$usage" From f7faf0d19c3a277fba699607f2188f2c8ac14db0 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 2 Mar 2017 23:36:41 -0500 Subject: [PATCH 22/28] Use a specified secondary root in upgradeinstall. --- apt-cyg | 1 + 1 file changed, 1 insertion(+) diff --git a/apt-cyg b/apt-cyg index 2cebbb0..7758aec 100755 --- a/apt-cyg +++ b/apt-cyg @@ -810,6 +810,7 @@ apt_upgradeinstall() { if [ "$pks" ] then preproot="$pks" + pks="" fi if [ "${preproot}" = "/" ] then From 2b933e70f8b0666410201c5198e4d0015bb20351 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Mon, 6 Mar 2017 10:37:00 -0500 Subject: [PATCH 23/28] Avoid relying on a feature of a bash builtin. --- apt-cyg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apt-cyg b/apt-cyg index 7758aec..f5ab4c1 100755 --- a/apt-cyg +++ b/apt-cyg @@ -532,7 +532,7 @@ apt_search () { apt_searchall () { for pkg in $pks do - printf -v qs 'text=1&arch=%s&grep=%s' $arch "$pkg" + qs="text=1&arch=${arch}&grep=${pkg}" getfile -O "/tmp/matches$$.txt" "http://cygwin.com/cgi-bin2/package-grep.cgi?$qs" awk ' NR == 1 {next} From b42c2b6b58b7aaadee53ad7a2843ca6b76b487c6 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Mon, 6 Mar 2017 11:13:11 -0500 Subject: [PATCH 24/28] Explain the expected way to run upgradecopy. Clarify other messages. --- apt-cyg | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/apt-cyg b/apt-cyg index f5ab4c1..0a20a78 100755 --- a/apt-cyg +++ b/apt-cyg @@ -756,9 +756,6 @@ apt_mirror () { fi } -# TODO: Run upgrade from the actual root. Include prepupgrade into it as well. -# Use the other root as a prefix in all functions. - apt_upgradesetup() { local preproot preproot=/fw @@ -768,7 +765,7 @@ apt_upgradesetup() { fi if [ "${preproot}" = "/" ] then - error "prepupgrade needs a separate root" || return 1 + error "upgradesetup needs a separate root" || return 1 fi if [ -d "${preproot}" ] then @@ -814,7 +811,7 @@ apt_upgradeinstall() { fi if [ "${preproot}" = "/" ] then - error "prepupgrade needs a separate root" || return 1 + error "upgradeinstall needs a separate root" || return 1 fi preprootnative=$(cygpath -wa "${preproot}") @@ -841,7 +838,12 @@ apt_upgradecopy() { fi if [ ! "$origroot" ] then - error "Could not find a reference to the actual root that needs creating with apt-cyg prepupgrade" || return 1 + error "Could not find the primary root reference created with apt-cyg upgradesetup. +The upgradecopy command needs running from Command Prompt using the shell copied to +a secondary root, e.g. + + c:\cygwin64\fw\bin\ash.exe /bin/apt-cyg upgradecopy +" || return 1 fi local winsys winsys=$(cygpath -S) @@ -928,7 +930,7 @@ apt_upgradecomplete() { /bin/echo -E "Cleaning up the secondary root ${preproot} ..." rm -rf "${preproot}" - echo "Cleaning up files stashed by the upgrade in /bin.bak, /usr.bak, /etc.bak ...." + echo "Cleaning up files stashed by the upgrade in /{bin,usr,etc,sbin,lib,var}.bak ..." rm -rf /bin.bak /usr.bak /etc.bak /sbin.bak /lib.bak /var.bak } From 2cd417660bdbec151b01d2ca45e0e522f8e60774 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Thu, 18 May 2017 16:02:37 -0400 Subject: [PATCH 25/28] Obtain the package list from a trusted location regardless of the mirror. --- apt-cyg | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/apt-cyg b/apt-cyg index 0a20a78..a3298e0 100755 --- a/apt-cyg +++ b/apt-cyg @@ -130,6 +130,7 @@ Copyright (c) 2005-9 Stephen Jungels ' export PATH=/bin:/usr/bin +mirrorsource="http://mirrors.kernel.org/sourceware/cygwin/" repl() { local n m @@ -215,7 +216,7 @@ find_workspace () { } ' "${setup}") if [ ${#mirror} -eq 0 ] ; then - mirror="http://mirrors.kernel.org/sourceware/cygwin/" + mirror="${mirrorsource}" fi repl "${mirror}" "/" "%2f" @@ -229,18 +230,19 @@ find_workspace () { } get_setup () { - if [ -f setup.ini ] - then - mv setup.ini setup.ini-save - fi - getfile -N "${mirror%/}/${arch}/setup.bz2" - if [ -e setup.bz2 ] && bunzip2 setup.bz2 + u="${mirrorsource%/}/${arch}/setup.xz" + d="$(cygpath -aw .)" + getfile -N "${u}" + if [ -e setup.xz ] && unxz setup.xz then + if [ -f setup.ini ] + then + mv setup.ini setup.ini-save + fi mv setup setup.ini || return 1 - /bin/echo -E "Updated setup.ini in $(cygpath -aw .)" + /bin/echo -E "Updated setup.ini from ${u} in ${d}" else - /bin/echo -E "Error updating setup.ini in $(cygpath -aw . ), reverting" || return 1 - mv setup.ini-save setup.ini || : + /bin/echo -E "Error updating setup.ini from ${u} in ${d}" || return 1 fi } From 70074897eb503736da86c8255b3f03405c3a3b65 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Fri, 2 Jun 2017 14:19:59 -0400 Subject: [PATCH 26/28] Use curl in addition to wget and lynx. Exit early when downloading fails. --- apt-cyg | 41 ++++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 15 deletions(-) diff --git a/apt-cyg b/apt-cyg index a3298e0..82adb96 100755 --- a/apt-cyg +++ b/apt-cyg @@ -149,11 +149,11 @@ repl() { } getfile () { - if wget -h > /dev/null 2>&1 + if wget --version > /dev/null 2>&1 then if ! wget --no-verbose "$@" then - error "Downloading \"$1\" to \"${of}\"" || return 1 + error "wget --no-verbose $*" || return 1 fi else of= @@ -167,17 +167,28 @@ getfile () { if [ ${#of} -eq 0 ] ; then of="${1##*/}" fi - qecho "lynx -source \"$1\"" - # Lynx fails when it cannot access the home directory for user - # configuration. Creating the home directory works this around. - if [ ! -d "${HOME}" ] + if curl --version > /dev/null 2>&1 then - mkdir -p "${HOME}" - fi - echo "Downloading \"$1\" ..." - if ! { lynx -source "$1" > "${of}" ; } - then - error "Downloading \"$1\" to \"${of}\"" || return 1 + if ! curl -s -o "${of}" "$1" + then + error "curl -s -o \"${of}\" \"$1\"" || return 1 + fi + else + if type lynx > /dev/null 2>&1 + then + # Lynx fails when it cannot access the home directory for user + # configuration. Creating the home directory works this around. + if [ ! -d "${HOME}" ] + then + mkdir -p "${HOME}" + fi + if ! { lynx -source "$1" > "${of}" ; } + then + error "lynx -source \"$1\" > \"${of}\"" || return 1 + fi + else + error "No wget, lynx or curl found" || return 1 + fi fi fi } @@ -232,7 +243,7 @@ find_workspace () { get_setup () { u="${mirrorsource%/}/${arch}/setup.xz" d="$(cygpath -aw .)" - getfile -N "${u}" + getfile -N "${u}" || return 1 if [ -e setup.xz ] && unxz setup.xz then if [ -f setup.ini ] @@ -497,7 +508,7 @@ download () { cd "${cacheslash}${mirrordir}/${dn}" if ! test -e "${bn}" || ! echo "${digest} ${bn}" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null then - getfile -O "${bn}" "${mirror%/}/${dn}/${bn}" + getfile -O "${bn}" "${mirror%/}/${dn}/${bn}" || return 1 rm -f "${bn}.unpacked" echo "$digest $bn" | "${hash}" --check ${hflags} > /dev/null 2> /dev/null \ || error "Hash ${hash} of ${cacheslash}${mirrordir}/${dn}/${bn} did not result in ${digest}" || return 1 @@ -535,7 +546,7 @@ apt_searchall () { for pkg in $pks do qs="text=1&arch=${arch}&grep=${pkg}" - getfile -O "/tmp/matches$$.txt" "http://cygwin.com/cgi-bin2/package-grep.cgi?$qs" + getfile -O "/tmp/matches$$.txt" "http://cygwin.com/cgi-bin2/package-grep.cgi?$qs" || return 1 awk ' NR == 1 {next} mc[$1]++ {next} From 1b15b06233adc791adc9e91a8cd06f90115b9ac0 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Tue, 20 Jun 2017 20:52:41 -0400 Subject: [PATCH 27/28] Avoid a Bash-only built-in option. --- apt-cyg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apt-cyg b/apt-cyg index 82adb96..fd0b32f 100755 --- a/apt-cyg +++ b/apt-cyg @@ -526,8 +526,8 @@ apt_search () { echo "Searching downloaded packages..." for pkg in $pks do - key=$(type -P "$pkg" | sed s./..) - [ "$key" ] || key=$pkg + key="bin/${pkg##*/}" + [ -x "/usr/$key" ] || key="${pkg}" for manifest in /etc/setup/*.lst.gz do if gzip -cd $manifest | grep -q "$key" From 2700f5578d75436cb90f1f50cb78c816541ebf20 Mon Sep 17 00:00:00 2001 From: Ilguiz Latypov Date: Tue, 31 Oct 2017 16:33:44 -0400 Subject: [PATCH 28/28] Avoid failing on an unimportant error. --- apt-cyg | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/apt-cyg b/apt-cyg index fd0b32f..a88f99d 100755 --- a/apt-cyg +++ b/apt-cyg @@ -882,12 +882,12 @@ $cygprocs" || return 1 /bin/echo -E "Moving the original bin, usr, etc, sbin, lib, var away to *.bak in ${origroot} ..." rm -rf "${origroot}/bin.bak" "${origroot}/usr.bak" "${origroot}/etc.bak" \ "${origroot}/sbin.bak" "${origroot}/lib.bak" "${origroot}/var.bak" - mv "${origroot}/bin" "${origroot}/bin.bak" || error "Moving ${origroot}/bin" || return 1 - mv "${origroot}/usr" "${origroot}/usr.bak" || error "Moving ${origroot}/usr" || return 1 - mv "${origroot}/sbin" "${origroot}/sbin.bak" || error "Moving ${origroot}/sbin" || return 1 - mv "${origroot}/lib" "${origroot}/lib.bak" || error "Moving ${origroot}/lib" || return 1 - mv "${origroot}/var" "${origroot}/var.bak" || error "Moving ${origroot}/var" || return 1 - mv "${origroot}/etc" "${origroot}/etc.bak" || error "Moving ${origroot}/etc" || return 1 + mv "${origroot}/bin" "${origroot}/bin.bak" || : + mv "${origroot}/usr" "${origroot}/usr.bak" || : + mv "${origroot}/sbin" "${origroot}/sbin.bak" || : + mv "${origroot}/lib" "${origroot}/lib.bak" || : + mv "${origroot}/var" "${origroot}/var.bak" || : + mv "${origroot}/etc" "${origroot}/etc.bak" || : preproot="/" preprootnative=$(cygpath -wa "${preproot}") @@ -980,6 +980,9 @@ then fi # process options +nodeps= +noscripts= +force= until [ $# = 0 ] do case "$1" in