Compare commits
24 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
482a2825c4 |
||
|
|
6095bc576b | ||
|
|
0eb1bed0a5 | ||
|
|
7d63bffff9 | ||
|
|
06113ecc4c | ||
|
|
beb5f2b8a8 | ||
|
|
50760fed68 | ||
|
|
6f82f6bf08 | ||
|
|
410b6c7592 | ||
|
|
a94c545ae2 | ||
|
|
014744456d | ||
|
|
fbdec79a3e | ||
|
|
197adec183 | ||
|
|
758f62e580 | ||
|
|
5318daa5c6 | ||
|
|
893f94f428 | ||
|
|
a73ecd5815 | ||
|
|
aa9b1b454f | ||
|
|
3d050aaf49 | ||
|
|
8656bfd565 | ||
|
|
d696710922 | ||
|
|
68f872a10e | ||
|
|
9f3764d8d2 | ||
|
|
2f6207731e |
6 changed files with 120 additions and 494 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# set -x
|
||||
|
||||
if [[ "$(uname -m)" == arm* || "$(uname -m)" == aarch64 ]]
|
||||
if [[ "$(uname -m)" == arm* || "$(uname -m)" == aarch64 || "$(uname -m)" == riscv64 ]]
|
||||
then
|
||||
COMMAND="$1"
|
||||
KERNEL_VERSION="$2"
|
||||
|
|
|
|||
82
grubby-bls
82
grubby-bls
|
|
@ -92,7 +92,7 @@ get_bls_values() {
|
|||
bls="${bls%.conf}"
|
||||
bls="${bls##*/}"
|
||||
echo "${bls}"
|
||||
done | /usr/libexec/grubby/rpm-sort -c rpmnvrcmp 2>/dev/null | tac)) || :
|
||||
done | sort -Vr 2>/dev/null)) || :
|
||||
|
||||
for bls in "${files[@]}" ; do
|
||||
blspath="${blsdir}/${bls}.conf"
|
||||
|
|
@ -356,22 +356,26 @@ get_custom_bls_filename() {
|
|||
prefix="${bls_target%%${arch}}"
|
||||
prefix="${prefix%.*}"
|
||||
|
||||
last=($(for bls in ${prefix}.*~custom*.conf ; do
|
||||
if ! [[ -e "${bls}" ]] ; then
|
||||
continue
|
||||
fi
|
||||
bls="${bls##${prefix}.}"
|
||||
bls="${bls%%~custom*}"
|
||||
echo "${bls}"
|
||||
done | tail -n1)) || :
|
||||
first_gap=$(
|
||||
first=0
|
||||
for bls_entry in $(ls "${prefix}".*~custom*.conf 2>/dev/null | sort -V); do
|
||||
if [[ -e ${bls_entry} ]]; then
|
||||
bls_entry="${bls_entry##"${prefix}".}"
|
||||
bls_entry="${bls_entry%%~custom*}"
|
||||
if [[ "${bls_entry}" = "${first}" ]]; then
|
||||
first=$((first+1))
|
||||
else
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "${first}") || :
|
||||
|
||||
if [[ -z $last ]]; then
|
||||
last="0"
|
||||
else
|
||||
last=$((last+1))
|
||||
if [[ -z "$first_gap" ]]; then
|
||||
first_gap="0"
|
||||
fi
|
||||
|
||||
echo "${bls_target}" | sed -e "s!${prefix}!${prefix}.${last}~custom!"
|
||||
echo "${bls_target}" | sed -e "s!${prefix}!${prefix}.${first_gap}~custom!"
|
||||
}
|
||||
|
||||
add_bls_fragment() {
|
||||
|
|
@ -500,7 +504,7 @@ update_bls_fragment() {
|
|||
if [[ -n $old_args ]]; then
|
||||
opts="$(update_args "${old_args}" "${remove_args}" "${add_args}")"
|
||||
opts="$(echo "$opts" | sed -e 's/\//\\\//g')"
|
||||
sed -i -e "s/^GRUB_CMDLINE_LINUX.*/GRUB_CMDLINE_LINUX=\\\"${opts}\\\"/" "${grub_etc_default}"
|
||||
sed -i -e "s/^GRUB_CMDLINE_LINUX=.*/GRUB_CMDLINE_LINUX=\\\"${opts}\\\"/" "${grub_etc_default}"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -563,7 +567,7 @@ set_default_bls() {
|
|||
echo "default=${default}" >> "${zipl_config}"
|
||||
fi
|
||||
fi
|
||||
|
||||
update_grubcfg
|
||||
print_info "The default is ${bls_file[$index]} with index $index and kernel $(get_prefix)${bls_linux[$index]}"
|
||||
}
|
||||
|
||||
|
|
@ -595,33 +599,29 @@ remove_var_prefix() {
|
|||
|
||||
update_grubcfg()
|
||||
{
|
||||
# Older ppc64le OPAL firmware (petitboot version < 1.8.0) don't have BLS support
|
||||
# so grub2-mkconfig has to be run to generate a config with menuentry commands.
|
||||
if [ "${arch}" = "ppc64le" ] && [ -d /sys/firmware/opal ]; then
|
||||
# Turn on RUN_MKCONFIG on different archs/scenarios
|
||||
if [[ "${arch}" = 's390' ]] || [[ "${arch}" = 's390x' ]]; then
|
||||
# On s390/s390x systems, run mkconfig/zipl
|
||||
RUN_MKCONFIG="true"
|
||||
petitboot_path="/sys/firmware/devicetree/base/ibm,firmware-versions/petitboot"
|
||||
|
||||
if test -e ${petitboot_path}; then
|
||||
read -r -d '' petitboot_version < ${petitboot_path}
|
||||
petitboot_version="$(echo ${petitboot_version//v})"
|
||||
|
||||
if test -n ${petitboot_version}; then
|
||||
major_version="$(echo ${petitboot_version} | cut -d . -f1)"
|
||||
minor_version="$(echo ${petitboot_version} | cut -d . -f2)"
|
||||
|
||||
re='^[0-9]+$'
|
||||
if [[ $major_version =~ $re ]] && [[ $minor_version =~ $re ]] &&
|
||||
([[ ${major_version} -gt 1 ]] ||
|
||||
[[ ${major_version} -eq 1 &&
|
||||
${minor_version} -ge 8 ]]); then
|
||||
RUN_MKCONFIG="false"
|
||||
fi
|
||||
fi
|
||||
elif [[ "${arch}" = "ppc64le" ]] && [[ -d /sys/firmware/opal ]]; then
|
||||
# Older ppc64le OPAL firmware don't have BLS support so grub2-mkconfig has to be run
|
||||
# to generate a config with menuentry commands.
|
||||
RUN_MKCONFIG="true"
|
||||
elif [[ -e /sys/hypervisor/type ]] && grep -q "^xen$" /sys/hypervisor/type; then
|
||||
if [ ! -e /sys/hypervisor/guest_type ] || ! grep -q "^HVM$" /sys/hypervisor/guest_type; then
|
||||
# PV and PVH Xen DomU guests boot with pygrub that doesn't have BLS support,
|
||||
# also Xen Dom0 use the menuentries from 20_linux_xen and not the ones from
|
||||
# 10_linux. So grub2-mkconfig has to run for both Xen Dom0 and DomU.
|
||||
RUN_MKCONFIG=true
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $RUN_MKCONFIG = "true" ]]; then
|
||||
grub2-mkconfig --no-grubenv-update -o "${grub_config}" >& /dev/null
|
||||
if [[ $bootloader = "zipl" ]]; then
|
||||
zipl
|
||||
else
|
||||
grub2-mkconfig --no-grubenv-update -o "${grub_config}" &> /dev/null
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -630,7 +630,7 @@ print_usage()
|
|||
cat <<EOF
|
||||
Usage: grubby [OPTION...]
|
||||
--add-kernel=kernel-path add an entry for the specified kernel
|
||||
--args=args default arguments for the new kernel or new arguments for kernel being updated)
|
||||
--args=args default arguments for the new kernel or new arguments for kernel being updated
|
||||
--bad-image-okay don't sanity check images in boot entries (for testing only)
|
||||
-c, --config-file=path path to grub config file to update ("-" for stdin)
|
||||
--copy-default use the default boot entry as a template for the new entry being added; if the default is not a linux image, or if the kernel referenced by the default image does not exist, the
|
||||
|
|
@ -833,7 +833,9 @@ if [[ -n $kernel ]]; then
|
|||
opts="${opts} ${args}"
|
||||
fi
|
||||
else
|
||||
opts="${args}"
|
||||
opts="${opts} ${args}"
|
||||
remove_args="$kernelopts"
|
||||
update_args "${opts}" "${remove_args}" ""
|
||||
fi
|
||||
|
||||
add_bls_fragment "${kernel}" "${title}" "${opts}" "${initrd}" \
|
||||
|
|
|
|||
85
grubby.spec
85
grubby.spec
|
|
@ -3,16 +3,16 @@
|
|||
|
||||
Name: grubby
|
||||
Version: 8.40
|
||||
Release: 66%{?dist}
|
||||
Release: 86%{?dist}
|
||||
Summary: Command line tool for updating bootloader configs
|
||||
License: GPLv2+
|
||||
License: GPL-2.0-or-later
|
||||
Source1: grubby-bls
|
||||
Source2: rpm-sort.c
|
||||
# Source2: rpm-sort.c
|
||||
Source3: COPYING
|
||||
Source4: installkernel-bls
|
||||
Source5: 95-kernel-hooks.install
|
||||
Source6: 10-devicetree.install
|
||||
Source7: grubby.8
|
||||
Source8: kernel.sysconfig
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: glib2-devel
|
||||
|
|
@ -22,7 +22,7 @@ BuildRequires: pkgconfig
|
|||
BuildRequires: popt-devel
|
||||
BuildRequires: rpm-devel
|
||||
BuildRequires: sed
|
||||
%ifarch aarch64 x86_64 %{power64}
|
||||
%ifarch aarch64 x86_64 %{power64} riscv64
|
||||
BuildRequires: grub2-tools-minimal
|
||||
Requires: grub2-tools-minimal
|
||||
Requires: grub2-tools
|
||||
|
|
@ -49,16 +49,10 @@ cp %{SOURCE3} . || true
|
|||
|
||||
%build
|
||||
%set_build_flags
|
||||
gcc ${CPPFLAGS} ${CFLAGS} ${LDFLAGS} -std=gnu99 -DVERSION='"8.4.0"' \
|
||||
-o rpm-sort %{SOURCE2} -lrpmio
|
||||
|
||||
%install
|
||||
mkdir -p %{buildroot}%{_libexecdir}/grubby/
|
||||
install -D -m 0755 rpm-sort %{buildroot}%{_libexecdir}/grubby
|
||||
|
||||
mkdir -p %{buildroot}%{_sbindir}/
|
||||
install -T -m 0755 %{SOURCE1} %{buildroot}%{_sbindir}/grubby
|
||||
install -T -m 0755 %{SOURCE4} %{buildroot}%{_sbindir}/installkernel
|
||||
|
||||
install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE5}
|
||||
install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE6}
|
||||
|
|
@ -66,6 +60,9 @@ install -D -m 0755 -t %{buildroot}%{_prefix}/lib/kernel/install.d/ %{SOURCE6}
|
|||
mkdir -p %{buildroot}%{_mandir}/man8
|
||||
install -m 0644 %{SOURCE7} %{buildroot}%{_mandir}/man8/
|
||||
|
||||
mkdir -p %{buildroot}%{_sysconfdir}/sysconfig
|
||||
install -m 0644 %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/kernel
|
||||
|
||||
%post
|
||||
if [ "$1" = 2 ]; then
|
||||
arch=$(uname -m)
|
||||
|
|
@ -75,15 +72,75 @@ fi
|
|||
|
||||
%files
|
||||
%license COPYING
|
||||
%dir %{_libexecdir}/grubby
|
||||
%attr(0755,root,root) %{_libexecdir}/grubby/rpm-sort
|
||||
%attr(0755,root,root) %{_sbindir}/grubby
|
||||
%attr(0755,root,root) %{_sbindir}/installkernel
|
||||
%attr(0755,root,root) %{_prefix}/lib/kernel/install.d/10-devicetree.install
|
||||
%attr(0755,root,root) %{_prefix}/lib/kernel/install.d/95-kernel-hooks.install
|
||||
%{_mandir}/man8/grubby.8*
|
||||
%config(noreplace) %{_sysconfdir}/sysconfig/kernel
|
||||
|
||||
%changelog
|
||||
* Wed Dec 10 2025 Simon de Vlieger <cmdr@supakeen.com> - 8.40-86
|
||||
- Own `/etc/sysconfig/kernel` which is used for `grubby` configuration
|
||||
|
||||
* Wed Jul 30 2025 Leo Sandoval <lsandova@redhat.com> - 8.40-85
|
||||
- Update cfg when setting a default kernel
|
||||
|
||||
* Thu Jul 24 2025 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-84
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild
|
||||
|
||||
* Thu Mar 20 2025 Leo Sandoval <lsandova@redhat.com> - 8.40-83
|
||||
- grubby-bls: in s390* systems, run zipl on grub cfg update event
|
||||
Fixes previous commit and formats better the conditions that trigger grub cfg updates
|
||||
|
||||
* Fri Jan 17 2025 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-82
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild
|
||||
|
||||
* Mon Jan 06 2025 Nicolas Frayer <nfrayer@redhat.com> - 8.40-81
|
||||
- Fixups to custom kernel targets
|
||||
|
||||
* Fri Dec 06 2024 Leo Sandoval <lsandova@redhat.com> - 8.40-80
|
||||
- grubby-bls: on PPC systems, remove petiboot's version checks
|
||||
|
||||
* Fri Dec 06 2024 Leo Sandoval <lsandova@redhat.com> - 8.40-79
|
||||
- grubby-bls: in s390* systems, run zipl on grub cfg update event
|
||||
|
||||
* Mon Dec 02 2024 David Abdurachmanov <davidlt@rivosinc.com> - 8.40-78
|
||||
- Add riscv64 support
|
||||
|
||||
* Mon Nov 25 2024 Leo Sandoval <lsandova@redhat.com> - 8.40-77
|
||||
- On grub cfg updates, run grub2-mkconfig for Xen systems
|
||||
|
||||
* Thu Jul 18 2024 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-76
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild
|
||||
|
||||
* Wed Jan 24 2024 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-75
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Sat Jan 20 2024 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-74
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
|
||||
|
||||
* Wed Jan 10 2024 Marta Lewandowska <mlewando@redhat.com> - 8.40-73
|
||||
- Do not overwrite all vars that start with GRUB_CMDLINE_LINUX
|
||||
|
||||
* Mon Sep 11 2023 Zbigniew Jedrzejewski-Szmek <zbyszek@in.waw.pl> - 8.40-72
|
||||
- Drop installkernel so that it can be provided by systemd
|
||||
|
||||
* Thu Jul 20 2023 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-71
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
|
||||
|
||||
* Tue Feb 21 2023 Marta Lewandowska <mlewando@redhat.com> - 8.40-70
|
||||
- remove root= when not copying default
|
||||
|
||||
* Thu Jan 19 2023 Fedora Release Engineering <releng@fedoraproject.org> - 8.40-69
|
||||
- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
|
||||
|
||||
* Tue Nov 01 2022 Robbie Harwood <rharwood@redhat.com> - 8.40-68
|
||||
- Drop custom rpm-sort
|
||||
- See-also: https://github.com/rpm-software-management/rpm/pull/2249
|
||||
|
||||
* Tue Oct 04 2022 Robbie Harwood <rharwood@redhat.com> - 8.40-67
|
||||
- Apply Marta's copy-default args fix
|
||||
|
||||
* Mon Aug 22 2022 Robbie Harwood <rharwood@redhat.com> - 8.40-66
|
||||
- Give up and just pull the config from BLS
|
||||
- Suggested-by: Bojan Smojver <bojan@rexursive.com>
|
||||
|
|
|
|||
|
|
@ -1,83 +0,0 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# /sbin/installkernel
|
||||
#
|
||||
# Copyright 2007-2008 Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# 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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Author(s): tyson@rwii.com
|
||||
#
|
||||
|
||||
usage() {
|
||||
echo "Usage: `basename $0` <kernel_version> <bootimage> <mapfile>" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cfgLoader=
|
||||
|
||||
if [ -z "$INSTALL_PATH" -o "$INSTALL_PATH" == "/boot" ]; then
|
||||
INSTALL_PATH=/boot
|
||||
cfgLoader=1
|
||||
fi
|
||||
|
||||
LINK_PATH=/boot
|
||||
RELATIVE_PATH=`echo "$INSTALL_PATH/" | sed "s|^$LINK_PATH/||"`
|
||||
KERNEL_VERSION=$1
|
||||
BOOTIMAGE=$2
|
||||
MAPFILE=$3
|
||||
ARCH=$(uname -m)
|
||||
if [ $ARCH = 'ppc64' -o $ARCH = 'ppc' ]; then
|
||||
KERNEL_NAME=vmlinux
|
||||
else
|
||||
KERNEL_NAME=vmlinuz
|
||||
fi
|
||||
|
||||
if [ -z "$KERNEL_VERSION" -o -z "$BOOTIMAGE" -o -z "$MAPFILE" ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ -f $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION ]; then
|
||||
mv $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION \
|
||||
$INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION.old;
|
||||
fi
|
||||
|
||||
if [ ! -L $INSTALL_PATH/$KERNEL_NAME ]; then
|
||||
if [ -e $INSTALLPATH/$KERNEL_NAME ]; then
|
||||
mv $INSTALL_PATH/$KERNEL_NAME $INSTALL_PATH/$KERNEL_NAME.old
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -f $INSTALL_PATH/System.map-$KERNEL_VERSION ]; then
|
||||
mv $INSTALL_PATH/System.map-$KERNEL_VERSION \
|
||||
$INSTALL_PATH/System.map-$KERNEL_VERSION.old;
|
||||
fi
|
||||
|
||||
if [ ! -L $INSTALL_PATH/System.map ]; then
|
||||
if [ -e $INSTALLPATH/System.map ]; then
|
||||
mv $INSTALL_PATH/System.map $INSTALL_PATH/System.map.old
|
||||
fi
|
||||
fi
|
||||
ln -sf ${RELATIVE_PATH}$INSTALL_PATH/System.map-$KERNEL_VERSION $LINK_PATH/System.map
|
||||
|
||||
cat $BOOTIMAGE > $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION
|
||||
cp $MAPFILE $INSTALL_PATH/System.map-$KERNEL_VERSION
|
||||
|
||||
ln -fs ${RELATIVE_PATH}$INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION $LINK_PATH/$KERNEL_NAME
|
||||
ln -fs ${RELATIVE_PATH}$INSTALL_PATH/System.map-$KERNEL_VERSION $LINK_PATH/System.map
|
||||
|
||||
if [ -n "$cfgLoader" ]; then
|
||||
kernel-install add $KERNEL_VERSION $INSTALL_PATH/$KERNEL_NAME-$KERNEL_VERSION
|
||||
exit $?
|
||||
fi
|
||||
6
kernel.sysconfig
Normal file
6
kernel.sysconfig
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# UPDATEDEFAULT specifies if kernel-install should make
|
||||
# new kernels the default
|
||||
UPDATEDEFAULT=yes
|
||||
|
||||
# DEFAULTKERNEL specifies the default kernel package type
|
||||
DEFAULTKERNEL=kernel-core
|
||||
356
rpm-sort.c
356
rpm-sort.c
|
|
@ -1,356 +0,0 @@
|
|||
#define _GNU_SOURCE
|
||||
|
||||
#include <argp.h>
|
||||
#include <assert.h>
|
||||
#include <err.h>
|
||||
#include <errno.h>
|
||||
#include <rpm/rpmlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
typedef enum {
|
||||
RPMNVRCMP,
|
||||
VERSNVRCMP,
|
||||
RPMVERCMP,
|
||||
STRVERSCMP,
|
||||
} comparitors;
|
||||
|
||||
static comparitors comparitor = RPMNVRCMP;
|
||||
|
||||
static inline void *xmalloc(size_t sz)
|
||||
{
|
||||
void *ret = malloc(sz);
|
||||
|
||||
assert(sz == 0 || ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void *xrealloc(void *p, size_t sz)
|
||||
{
|
||||
void *ret = realloc(p, sz);
|
||||
|
||||
assert(sz == 0 || ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline char *xstrdup(const char * const s)
|
||||
{
|
||||
void *ret = strdup(s);
|
||||
|
||||
assert(s == NULL || ret != NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t
|
||||
read_file (const char *input, char **ret)
|
||||
{
|
||||
FILE *in;
|
||||
size_t s;
|
||||
size_t sz = 2048;
|
||||
size_t offset = 0;
|
||||
char *text;
|
||||
|
||||
if (!strcmp(input, "-"))
|
||||
in = stdin;
|
||||
else
|
||||
in = fopen(input, "r");
|
||||
|
||||
text = xmalloc (sz);
|
||||
|
||||
if (!in)
|
||||
err(1, "cannot open `%s'", input);
|
||||
|
||||
while ((s = fread (text + offset, 1, sz - offset, in)) != 0)
|
||||
{
|
||||
offset += s;
|
||||
if (sz - offset == 0)
|
||||
{
|
||||
sz += 2048;
|
||||
text = xrealloc (text, sz);
|
||||
}
|
||||
}
|
||||
|
||||
text[offset] = '\0';
|
||||
*ret = text;
|
||||
|
||||
if (in != stdin)
|
||||
fclose(in);
|
||||
|
||||
return offset + 1;
|
||||
}
|
||||
|
||||
/* returns name/version/release */
|
||||
/* NULL string pointer returned if nothing found */
|
||||
static void
|
||||
split_package_string (char *package_string, char **name,
|
||||
char **version, char **release)
|
||||
{
|
||||
char *package_version, *package_release;
|
||||
|
||||
/* Release */
|
||||
package_release = strrchr (package_string, '-');
|
||||
|
||||
if (package_release != NULL)
|
||||
*package_release++ = '\0';
|
||||
|
||||
*release = package_release;
|
||||
|
||||
/* Version */
|
||||
package_version = strrchr(package_string, '-');
|
||||
|
||||
if (package_version != NULL)
|
||||
*package_version++ = '\0';
|
||||
|
||||
*version = package_version;
|
||||
/* Name */
|
||||
*name = package_string;
|
||||
|
||||
/* Bubble up non-null values from release to name */
|
||||
if (*name == NULL)
|
||||
{
|
||||
*name = (*version == NULL ? *release : *version);
|
||||
*version = *release;
|
||||
*release = NULL;
|
||||
}
|
||||
if (*version == NULL)
|
||||
{
|
||||
*version = *release;
|
||||
*release = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
cmprpmversp(const void *p1, const void *p2)
|
||||
{
|
||||
return rpmvercmp(*(char * const *)p1, *(char * const *)p2);
|
||||
}
|
||||
|
||||
static int
|
||||
cmpstrversp(const void *p1, const void *p2)
|
||||
{
|
||||
return strverscmp(*(char * const *)p1, *(char * const *)p2);
|
||||
}
|
||||
|
||||
/*
|
||||
* package name-version-release comparator for qsort
|
||||
* expects p, q which are pointers to character strings (char *)
|
||||
* which will not be altered in this function
|
||||
*/
|
||||
static int
|
||||
package_version_compare (const void *p, const void *q)
|
||||
{
|
||||
char *local_p, *local_q;
|
||||
char *lhs_name, *lhs_version, *lhs_release;
|
||||
char *rhs_name, *rhs_version, *rhs_release;
|
||||
int vercmpflag = 0;
|
||||
int (*cmp)(const char *s1, const char *s2);
|
||||
|
||||
switch(comparitor)
|
||||
{
|
||||
default: /* just to shut up -Werror=maybe-uninitialized */
|
||||
case RPMNVRCMP:
|
||||
cmp = rpmvercmp;
|
||||
break;
|
||||
case VERSNVRCMP:
|
||||
cmp = strverscmp;
|
||||
break;
|
||||
case RPMVERCMP:
|
||||
return cmprpmversp(p, q);
|
||||
break;
|
||||
case STRVERSCMP:
|
||||
return cmpstrversp(p, q);
|
||||
break;
|
||||
}
|
||||
|
||||
local_p = alloca (strlen (*(char * const *)p) + 1);
|
||||
local_q = alloca (strlen (*(char * const *)q) + 1);
|
||||
|
||||
/* make sure these allocated */
|
||||
assert (local_p);
|
||||
assert (local_q);
|
||||
|
||||
strcpy (local_p, *(char * const *)p);
|
||||
strcpy (local_q, *(char * const *)q);
|
||||
|
||||
split_package_string (local_p, &lhs_name, &lhs_version, &lhs_release);
|
||||
split_package_string (local_q, &rhs_name, &rhs_version, &rhs_release);
|
||||
|
||||
/* Check Name and return if unequal */
|
||||
vercmpflag = cmp ((lhs_name == NULL ? "" : lhs_name),
|
||||
(rhs_name == NULL ? "" : rhs_name));
|
||||
if (vercmpflag != 0)
|
||||
return vercmpflag;
|
||||
|
||||
/* Check version and return if unequal */
|
||||
vercmpflag = cmp ((lhs_version == NULL ? "" : lhs_version),
|
||||
(rhs_version == NULL ? "" : rhs_version));
|
||||
if (vercmpflag != 0)
|
||||
return vercmpflag;
|
||||
|
||||
/* Check release and return the version compare value */
|
||||
vercmpflag = cmp ((lhs_release == NULL ? "" : lhs_release),
|
||||
(rhs_release == NULL ? "" : rhs_release));
|
||||
|
||||
return vercmpflag;
|
||||
}
|
||||
|
||||
static void
|
||||
add_input (const char *filename, char ***package_names, size_t *n_package_names)
|
||||
{
|
||||
char *orig_input_buffer = NULL;
|
||||
char *input_buffer;
|
||||
char *position_of_newline;
|
||||
char **names = *package_names;
|
||||
char **new_names = NULL;
|
||||
size_t n_names = *n_package_names;
|
||||
|
||||
if (!*package_names)
|
||||
new_names = names = xmalloc (sizeof (char *) * 2);
|
||||
|
||||
if (read_file (filename, &orig_input_buffer) < 2)
|
||||
{
|
||||
if (new_names)
|
||||
free (new_names);
|
||||
if (orig_input_buffer)
|
||||
free (orig_input_buffer);
|
||||
return;
|
||||
}
|
||||
|
||||
input_buffer = orig_input_buffer;
|
||||
while (input_buffer && *input_buffer &&
|
||||
(position_of_newline = strchrnul (input_buffer, '\n')))
|
||||
{
|
||||
size_t sz = position_of_newline - input_buffer;
|
||||
char *new;
|
||||
|
||||
if (sz == 0)
|
||||
{
|
||||
input_buffer = position_of_newline + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
new = xmalloc (sz+1);
|
||||
strncpy (new, input_buffer, sz);
|
||||
new[sz] = '\0';
|
||||
|
||||
names = xrealloc (names, sizeof (char *) * (n_names + 1));
|
||||
names[n_names] = new;
|
||||
n_names++;
|
||||
|
||||
/* move buffer ahead to next line */
|
||||
input_buffer = position_of_newline + 1;
|
||||
if (*position_of_newline == '\0')
|
||||
input_buffer = NULL;
|
||||
}
|
||||
|
||||
free (orig_input_buffer);
|
||||
|
||||
*package_names = names;
|
||||
*n_package_names = n_names;
|
||||
}
|
||||
|
||||
static char *
|
||||
help_filter (int key, const char *text, void *input __attribute__ ((unused)))
|
||||
{
|
||||
return (char *)text;
|
||||
}
|
||||
|
||||
static struct argp_option options[] = {
|
||||
{ "comparitor", 'c', "COMPARITOR", 0, "[rpm-nvr-cmp|vers-nvr-cmp|rpmvercmp|strverscmp]", 0},
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
struct arguments
|
||||
{
|
||||
size_t ninputs;
|
||||
size_t input_max;
|
||||
char **inputs;
|
||||
};
|
||||
|
||||
static error_t
|
||||
argp_parser (int key, char *arg, struct argp_state *state)
|
||||
{
|
||||
struct arguments *arguments = state->input;
|
||||
switch (key)
|
||||
{
|
||||
case 'c':
|
||||
if (!strcmp(arg, "rpm-nvr-cmp") || !strcmp(arg, "rpmnvrcmp"))
|
||||
comparitor = RPMNVRCMP;
|
||||
else if (!strcmp(arg, "vers-nvr-cmp") || !strcmp(arg, "versnvrcmp"))
|
||||
comparitor = VERSNVRCMP;
|
||||
else if (!strcmp(arg, "rpmvercmp"))
|
||||
comparitor = RPMVERCMP;
|
||||
else if (!strcmp(arg, "strverscmp"))
|
||||
comparitor = STRVERSCMP;
|
||||
else
|
||||
err(1, "Invalid comparitor \"%s\"", arg);
|
||||
break;
|
||||
case ARGP_KEY_ARG:
|
||||
assert (arguments->ninputs < arguments->input_max);
|
||||
arguments->inputs[arguments->ninputs++] = xstrdup (arg);
|
||||
break;
|
||||
default:
|
||||
return ARGP_ERR_UNKNOWN;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct argp argp = {
|
||||
options, argp_parser, "[INPUT_FILES]",
|
||||
"Sort a list of strings in RPM version sort order.",
|
||||
NULL, help_filter, NULL
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct arguments arguments;
|
||||
char **package_names = NULL;
|
||||
size_t n_package_names = 0;
|
||||
int i;
|
||||
|
||||
memset (&arguments, 0, sizeof (struct arguments));
|
||||
arguments.input_max = argc+1;
|
||||
arguments.inputs = xmalloc ((arguments.input_max + 1)
|
||||
* sizeof (arguments.inputs[0]));
|
||||
memset (arguments.inputs, 0, (arguments.input_max + 1)
|
||||
* sizeof (arguments.inputs[0]));
|
||||
|
||||
/* Parse our arguments */
|
||||
if (argp_parse (&argp, argc, argv, 0, 0, &arguments) != 0)
|
||||
errx(1, "%s", "Error in parsing command line arguments\n");
|
||||
|
||||
/* If there's no inputs in argv, add one for stdin */
|
||||
if (!arguments.ninputs)
|
||||
{
|
||||
arguments.ninputs = 1;
|
||||
arguments.inputs[0] = xmalloc (2);
|
||||
strcpy(arguments.inputs[0], "-");
|
||||
}
|
||||
|
||||
for (i = 0; i < arguments.ninputs; i++)
|
||||
add_input(arguments.inputs[i], &package_names, &n_package_names);
|
||||
|
||||
if (package_names == NULL || n_package_names < 1)
|
||||
errx(1, "Invalid input");
|
||||
|
||||
qsort (package_names, n_package_names, sizeof (char *),
|
||||
package_version_compare);
|
||||
|
||||
/* send sorted list to stdout */
|
||||
for (i = 0; i < n_package_names; i++)
|
||||
{
|
||||
fprintf (stdout, "%s\n", package_names[i]);
|
||||
free (package_names[i]);
|
||||
}
|
||||
|
||||
free (package_names);
|
||||
for (i = 0; i < arguments.ninputs; i++)
|
||||
free (arguments.inputs[i]);
|
||||
|
||||
free (arguments.inputs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue