#! /bin/bash # encoding: utf-8 # vim: se ts=2 sw=2 et: # menageatator: Remove unneeded linux kernel from debuntu systems # http://schplurtz.free.fr/wiki/schplurtziel/menageatator # # Copyright Schplurtz Le Déboulonné, 2016, 2017, 2019 # # Schplurtz le Déboulonné # # FRENCH | ENGLISH # ------------------------------------+-------------------------------------- # Ce logiciel est un programme | This software is a computer program # informatique servant à supprimer | whose purpose is to automatically # automatiquement les noyaux non | remove unused kernels from ubuntu # utilisés des systèmes ubuntu ou | or Debian GNU/Linux systems. # debian GNU/linux. | # | # Ce logiciel est régi par la licence | This software is governed by the # CeCILL soumise au droit français et | CeCILL license under French law and # respectant les principes de | abiding by the rules of # diffusion des logiciels libres. | distribution of free software. You # Vous pouvez utiliser, modifier | can use, modify and/ or # et/ou redistribuer ce programme | redistribute the software under the # sous les conditions de la licence | terms of the CeCILL license as # CeCILL telle que diffusée par le | circulated by CEA, CNRS and INRIA # CEA, le CNRS et l'INRIA sur le site | at the following URL # "http://www.cecill.info/". | "http://www.cecill.info/". # | # En contrepartie de l'accessibilité | As a counterpart to the access to # au code source et des droits de | the source code and rights to # copie, de modification et de | copy, modify and redistribute # redistribution accordés par cette | granted by the license, users are # licence, il n'est offert aux | provided only with a limited # utilisateurs qu'une garantie | warranty and the software's # limitée. Pour les mêmes raisons, | author, the holder of the economic # seule une responsabilité restreinte | rights, and the successive # pèse sur l'auteur du programme, le | licensors have only limited # titulaire des droits patrimoniaux | liability. # et les concédants successifs. | # | # A cet égard l'attention de | In this respect, the user's # l'utilisateur est attirée sur les | attention is drawn to the risks # risques associés au chargement, à | associated with loading, using, # l'utilisation, à la modification | modifying and/or developing or # et/ou au développement et à la | reproducing the software by the # reproduction du logiciel par | user in light of its specific # l'utilisateur étant donné sa | status of free software, that may # spécificité de logiciel libre, qui | mean that it is complicated to # peut le rendre complexe à manipuler | manipulate, and that also # et qui le réserve donc à des | therefore means that it is # développeurs et des professionnels | reserved for developers and # avertis possédant des | experienced professionals having # connaissances informatiques | in-depth computer knowledge. Users # approfondies. Les utilisateurs | are therefore encouraged to load # sont donc invités à charger et | and test the software's suitability # tester l'adéquation du logiciel à | as regards their requirements in # leurs besoins dans des conditions | conditions enabling the security of # permettant d'assurer la sécurité de | their systems and/or data to be # leurs systèmes et ou de leurs | ensured and, more generally, to # données et, plus généralement, à | use and operate it in the same # l'utiliser et l'exploiter dans les | conditions as regards security. # mêmes conditions de sécurité. | # | # Le fait que vous puissiez accéder à | The fact that you are presently # cet en-tête signifie que vous avez | reading this means that you have # pris connaissance de la licence | had knowledge of the CeCILL license # CeCILL, et que vous en avez accepté | and that you accept its terms. # les termes. | # Yeah I know. Could use ruby/perl/ocam/lua/python/whatever and less pipes. # Could use array, associative arrays etc... Just prefering simplicity, # clarity and possibility to run with dumb^Wsimple shells. # # Whatever happens : # keep the current kernel # keep the most recent kernel correctly installed # keep all kernels that are on hold # if current = most recent, keep the next most recent kernel # # remove anything else. IFS="$(printf ' \t') " # /sbin and /usr/sbin are usually not in cron PATH. add them # if they're not present as dpkg will need commands there. case "$PATH" in (*:/usr/sbin|/usr/sbin:*|*:/usr/sbin:*) : ;; (*) PATH="${PATH}:/usr/sbin" ;; esac case "$PATH" in (*:/sbin|/sbin:*|*:/sbin:*) : ;; (*) PATH="${PATH}:/sbin" ;; esac set -e # Stop on any error. version() { sed -e "s/${1}-//" # remove prefix } no_suffix() { sed -e 's/-[a-zA-Z_]*$//' # remove suffix. (-generic, -lowlatency etc...) } reject() { grep -v "$@" } dpkg_query() { # dpkg sorts alphabetically. to avoid problematic order, explicitly sort # on version number. # before sorting | After sorting # ii linux-image-3.13.0-100-generic | ii linux-image-3.13.0-95-generic # ii linux-image-3.13.0-101-generic | ii linux-image-3.13.0-98-generic # ii linux-image-3.13.0-95-generic | ii linux-image-3.13.0-100-generic # ii linux-image-3.13.0-98-generic | ii linux-image-3.13.0-101-generic # old dpkg-query (from ubuntu 12.04 lucid for example) don't support # ${db:Status-Abbrev}. We have to use ${Status} that's a real pain. # We have to convert things like "deinstall ok config-files" to # "rc " # examples : # install ok installed linux-image-3.2.0-23-generic # unknown ok not-installed linux-image-3.2.0-23-generic # deinstall ok config-files linux-image-3.2.0-23-generic # hold ok installed linux-image-3.2.0-23-generic # The sed script does this : # 1) rewrite deinstall to removed # 2) replace the first 3 word by their initials in changing order # fe "unknown ok not-installed" becomes "uno" (2 and 3 are swapped) # 3) in 3rd column, replace "o" by " " # Also we are not interested in uninstalled kernels, so we filter # out the kernels that dpkg has never touched : /^un / dpkg-query -W -f '${Status} ${package}\n' "$@" 2>/dev/null | sed -e 's/^deinstall/removed/ s/^\(.\)[^ ]* *\(.\)[^ ]* *\(.\)[^ ]* */\1\3\2 / s/^\(..\)o/\1 / ' | reject '^un ' | sort -k 2,2V # always return list sorted by version number } _apt_get() { # args >&2 apt-get "$@" apt-get "$@" } ARGV=( "$@" ) # keep command line args for final apt-get command... linux_vers_tpl='[0-9]*.[0-9]*.[0-9]*-[0-9]*' linux_images_tpl="linux-image-${linux_vers_tpl}" linux_images_extra_tpl="linux-image-extra-${linux_vers_tpl}" linux_headers_tpl="linux-headers-${linux_vers_tpl}" linux_modules_tpl="linux-modules-${linux_vers_tpl}" # list of all linux-image packages dpkg is aware of linux_img=$( dpkg_query "$linux_images_tpl" ) # Get the list of packages NOT to remove : # onhold, current, latest, almost_latest onhold= current= latest= almost_latest= current=$( # This one is easy. uname -r | # get current version no_suffix # just the version, not the kind ) onhold=$( echo "$linux_img" | # list linux images grep ^h | # keep only those on hold awk '{ print $2 }' | # keep package name only version linux-image | # just need the version part of the name no_suffix # just the version, not the kind ) latest=$( echo "$linux_img" | # list linux images grep ^.i | # only consider correctly installed packages tail -1 | # keep last one awk '{ print $2 }' | # keep package name only version linux-image | # just need the version part of the name no_suffix # just the version, not the kind ) if test "$latest" = "$current" then almost_latest=$( echo "$linux_img" | # list linux images grep ^.i | # only consider correctly installed packages tail -2 | # keep last two head -1 | # keep first one (that is the 2nd most recent) awk '{ print $2 }' | # keep package name only version linux-image | # just need the version part of the name no_suffix # just the version, not the kind ) fi # build list and (grep -e args) of kernels to keep set -- for version in $onhold $current $latest $almost_latest do set -- ${1+"$@"} -e "$version" done #OFF#green="$*" #OFF## 32 vert; 33 brown #OFF#set -- -e '/^h/s/.*/&/' $( #OFF# printf '%s\n' $green | #OFF# awk ' #OFF# /^-e$/ { print; next } #OFF# { print "/" $1 "/s/.*/&/" } #OFF# ' #OFF# ) #OFF# #OFF#set -x #OFF# dpkg_query \ #OFF# "$linux_images_tpl" \ #OFF# "$linux_images_extra_tpl" \ #OFF# "$linux_headers_tpl" | # list linux images, images-extra, headers #OFF# sed "$@" #OFF# #OFF#exit # build list of kernels to remove set -- $( dpkg_query \ "$linux_images_tpl" \ "$linux_images_extra_tpl" \ "$linux_headers_tpl" \ "$linux_modules_tpl" | # list linux images, images-extra, headers, modules reject '^h' | # filter out packages on hold reject "$@" | # filter out those we keep awk '{ print $2 }' # just keep name ) # If there are kernels to remove, remove them { test $# -gt 0 && _apt_get "${ARGV[@]}" purge "$@" ; } || : # Given this list of kernel, # ii linux-image-3.13.0-93-generic # ii linux-image-3.13.0-95-generic # ii linux-image-3.13.0-96-generic # ii linux-image-3.13.0-98-generic # ii linux-image-3.13.0-100-generic # ii linux-image-3.13.0-101-generic # ii linux-image-3.13.0-103-generic # # and if we are running 3.13.0-95, this script # performs these removal : # apt-get purge linux-image-3.13.0-93-generic linux-image-3.13.0-96-generic linux-image-3.13.0-98-generic linux-image-3.13.0-100-generic linux-image-3.13.0-101-generic