mirror of
https://github.com/systemd/systemd.git
synced 2024-12-23 21:35:11 +03:00
parent
46083ab321
commit
2367bdcfc9
@ -173,11 +173,12 @@ The following keys are recognized:
|
||||
|
||||
* `version` is a human-readable version for this menu item. This is usually the
|
||||
kernel version and is intended for use by OSes to install multiple kernel
|
||||
versions with the same `title` field. This field shall be in a syntax that is
|
||||
useful for Debian-style version sorts, so that the boot loader UI can
|
||||
determine the newest version easily and show it first or preselect it
|
||||
versions with the same `title` field. This field is used for sorting entries,
|
||||
so that the boot loader can order entries by age or select the newest one
|
||||
automatically. This field is optional.
|
||||
|
||||
See [Sorting](#sorting) below.
|
||||
|
||||
Example: `version 3.7.2-201.fc18.x86_64`
|
||||
|
||||
* `machine-id` is the machine ID of the OS. This can be used by boot loaders
|
||||
@ -192,13 +193,7 @@ The following keys are recognized:
|
||||
* `sort-key` is a short string used for sorting entries on display. This should
|
||||
typically be initialized from the `IMAGE_ID=` or `ID=` fields of
|
||||
[os-release](https://www.freedesktop.org/software/systemd/man/os-release.html),
|
||||
possibly with an additional suffix. This field is optional. If set, it is
|
||||
used as primary sorting key for the entries on display (lexicographically
|
||||
increasing). It does not have to be unique (and usually is not). If
|
||||
non-unique the the `machine-id` (lexicographically increasing) and `version`
|
||||
(lexicographically decreasing, i.e. newest version first) fields described
|
||||
above are used as secondary/ternary sorting keys. If this field is not set
|
||||
entries are typically sorted by the `.conf` file name of the entry.
|
||||
possibly with an additional suffix. This field is optional.
|
||||
|
||||
Example: `sort-key fedora`
|
||||
|
||||
@ -393,6 +388,100 @@ creating a partition and file system for it) and creates the `/loader/entries/`
|
||||
directory in it. It then installs an appropriate boot loader that can read
|
||||
these snippets. Finally, it installs one or more kernel packages.
|
||||
|
||||
## Sorting
|
||||
|
||||
The boot loader menu should generally show entries in some order meaningful to
|
||||
the user. The `title` key is free-form and not suitable to be used as the
|
||||
primary sorting key. Instead, the boot loader should use the following rules:
|
||||
if `sort-key` is set on both entries, use in order of priority,
|
||||
the `sort-key` (A-Z, increasing [alphanumerical order](#alphanumerical-order)),
|
||||
`machine-id` (A-Z, increasing alphanumerical order),
|
||||
and `version` keys (decreasing [version order](#version-order)).
|
||||
If `sort-key` is set on one entry, it sorts earlier.
|
||||
At the end, if necessary, when `sort-key` is not set or those fields are not
|
||||
set or are all equal, the boot loader should sort using the file name of the
|
||||
entry (decreasing version sort), with the suffix removed.
|
||||
|
||||
**Note:** _This description assumes that the boot loader shows entries in a
|
||||
traditional menu, with newest and "best" entries at the top, thus entries with
|
||||
a higher version number are sorter *earlier*. The boot loader is free to
|
||||
use a different direction (or none at all) during display._
|
||||
|
||||
### Alphanumerical order
|
||||
|
||||
Free-form strings and machine IDs should be compared using a method equivalent
|
||||
to [strcmp(3)](https://man7.org/linux/man-pages/man3/strcmp.3.html) on their
|
||||
UTF-8 represenations. If just one of the strings is unspecified or empty, it
|
||||
compares lower. If both strings are unspecified or empty, they compare equal.
|
||||
|
||||
### Version order
|
||||
|
||||
The following method should be used to compare version strings. The algorithm
|
||||
is based on rpm's `rpmvercmp()`, but not identical.
|
||||
|
||||
ASCII letters (`a-z`, `A-Z`) and digits (`0-9`) form alphanumerical components of the version.
|
||||
Minus (`-`) separates the version and release parts.
|
||||
Dot (`.`) separates parts of version or release.
|
||||
Tilde (`~`) is a prefix that always compares lower.
|
||||
Caret (`^`) is a prefix that always compares higher.
|
||||
|
||||
Both strings are compared from the beginning until the end, or until the
|
||||
strings are found to compare as different. In a loop:
|
||||
1. Any characters which are outside of the set of listed above (`a-z`, `A-Z`, `0-9`, `-`, `.`, `~`, `^`)
|
||||
are skipped in both strings. In particular, this means that non-ASCII characters
|
||||
that are Unicode digits or letters are skipped too.
|
||||
2. If one of the strings has ended: if the other string hasn't, the string that
|
||||
has remaining characters compares higher. Otherwise, the strings compare
|
||||
equal.
|
||||
3. If the remaining part of one of strings starts with `~`:
|
||||
if other remaining part does not start with `~`,
|
||||
the string with `~` compares lower. Otherwise, both tilde characters are skipped.
|
||||
4. The check from point 2. is repeated here.
|
||||
5. If the remaining part of one of strings starts with `-`:
|
||||
if the other remaining part does not start with `-`,
|
||||
the string with `-` compares lower. Otherwise, both minus characters are skipped.
|
||||
6. If the remaining part of one of strings starts with `^`:
|
||||
if the other remaining part does not start with `^`,
|
||||
the string with `^` compares higher. Otherwise, both caret characters are skipped.
|
||||
6. If the remaining part of one of strings starts with `.`:
|
||||
if the other remaining part does not start with `.`,
|
||||
the string with `.` compares lower. Otherwise, both dot characters are skipped.
|
||||
7. If either of the remaining parts starts with a digit, numerical prefixes are
|
||||
compared numerically. Any leading zeroes are skipped.
|
||||
The numerical prefixes (until the first non-digit character) are evaluated as numbers.
|
||||
If one of the prefixes is empty, it evaluates as 0.
|
||||
If the numbers are different, the string with the bigger number compares higher.
|
||||
Otherwise, the comparison continues at the following characters at point 1.
|
||||
8. Leading alphabetical prefixes are compared alphabetically.
|
||||
The substrings are compared letter-by-letter.
|
||||
If both letters are the same, the comparison continues with the next letter.
|
||||
Capital letters compare lower than lower-case letters (`A < a`).
|
||||
When the end of one substring has been reached (a non-letter character or the end
|
||||
of the whole string), if the other substring has remaining letters, it compares higher.
|
||||
Otherwise, the comparison continues at the following characters at point 1.
|
||||
|
||||
Examples (with '' meaning the empty string):
|
||||
|
||||
* `11 == 11`
|
||||
* `systemd-123 == systemd-123`
|
||||
* `bar-123 < foo-123`
|
||||
* `123a > 123`
|
||||
* `123.a > 123`
|
||||
* `123.a < 123.b`
|
||||
* `123a > 123.a`
|
||||
* `11α == 11β`
|
||||
* `A < a`
|
||||
* '' < `0`
|
||||
* `0.` > `0`
|
||||
* `0.0` > `0`
|
||||
* `0` < `~`
|
||||
* '' < `~`
|
||||
|
||||
Note: [systemd-analyze](https://www.freedesktop.org/software/systemd/man/systemd-analyze.html)
|
||||
implements this version comparison algorithm as
|
||||
```
|
||||
systemd-analyze compare-versions <version-a> <version-b>
|
||||
```
|
||||
|
||||
## Additional discussion
|
||||
|
||||
@ -467,6 +556,21 @@ functionality, this specfication is still needed for the following reasons:
|
||||
useful if the OS UI has a standardized way to discover available boot options
|
||||
which can be booted to.
|
||||
|
||||
### Why is the version comparsion logic so complicated?
|
||||
|
||||
The `sort-key` allows us to group entries by "operating system", e.g. all
|
||||
versions of Fedora together, no matter if they identify themselves as "Fedora
|
||||
Workstation" or "Fedora Rawhide (prerelease)". The `sort-key` was introduced
|
||||
only recently, so we need to provide a meaningful order for entries both with
|
||||
and without it. Since it is a new concept, it is assumed that entries with
|
||||
`sort-key` are newer.
|
||||
|
||||
In a traditional menu with entries displayed vertically, we want names to be
|
||||
sorter alpabetically (CentOS, Debian, Fedora, OpenSUSE, …), it would be strange
|
||||
to have them in reverse order. But when multiple kernels are available for the
|
||||
same installation, we want to display the latest kernel with highest priority,
|
||||
i.e. earlier in the list.
|
||||
|
||||
### Out of Focus
|
||||
|
||||
There are a couple of items that are out of focus for this specification:
|
||||
|
@ -150,7 +150,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
}
|
||||
|
||||
/* If at least one string reaches the end, then longer is newer.
|
||||
* Note that except for '~' prefixed segments, a string has more segments is newer.
|
||||
* Note that except for '~' prefixed segments, a string which has more segments is newer.
|
||||
* So, this check must be after the '~' check. */
|
||||
if (*a == '\0' || *b == '\0')
|
||||
return CMP(*a, *b);
|
||||
@ -233,7 +233,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* The current segments are equivalent. Let's compare the next one. */
|
||||
/* The current segments are equivalent. Let's move to the next one. */
|
||||
a = aa;
|
||||
b = bb;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user