├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── AUTHORS ├── HACKING ├── LICENSE.LGPL2.1 ├── README.md ├── VERSION ├── data ├── clr-boot-manager-booted.service.in ├── completions │ ├── bash │ │ ├── clr-boot-manager.in │ │ └── meson.build │ └── zsh │ │ ├── _clr-boot-manager.in │ │ └── meson.build └── meson.build ├── docker ├── Dockerfile └── dockerrun.sh ├── how-to-make-a-release ├── man ├── clr-boot-manager.1.in └── meson.build ├── meson.build ├── meson_options.txt ├── scripts ├── continuous.sh ├── git-archive-all.sh ├── mkrelease.sh ├── run-test-suite.sh └── update-format.sh ├── sgcheck.suppressions ├── src ├── bootloaders │ ├── bootloader.h │ ├── extlinux.c │ ├── grub2.c │ ├── mbr.c │ ├── mbr.h │ ├── shim-systemd.c │ ├── syslinux-common.c │ ├── syslinux-common.h │ ├── syslinux.c │ ├── systemd-boot.c │ ├── systemd-class.c │ └── systemd-class.h ├── bootman │ ├── bootman.c │ ├── bootman.h │ ├── bootman_private.h │ ├── kernel.c │ ├── sysconfig.c │ ├── timeout.c │ └── update.c ├── cli │ ├── cli.c │ ├── cli.h │ ├── main.c │ └── ops │ │ ├── kernels.c │ │ ├── kernels.h │ │ ├── report_booted.c │ │ ├── report_booted.h │ │ ├── timeout.c │ │ ├── timeout.h │ │ ├── update.c │ │ └── update.h ├── lib │ ├── blkid_stub.c │ ├── blkid_stub.h │ ├── bootvar.c │ ├── bootvar.h │ ├── cmdline.c │ ├── cmdline.h │ ├── files.c │ ├── files.h │ ├── log.c │ ├── log.h │ ├── os-release.c │ ├── os-release.h │ ├── probe.c │ ├── probe.h │ ├── system_stub.c │ ├── system_stub.h │ ├── util.c │ ├── util.h │ ├── writer.c │ └── writer.h └── meson.build └── tests ├── blkid-harness.h ├── check-cmdline.c ├── check-core.c ├── check-files.c ├── check-grub2.c ├── check-legacy.c ├── check-os-release.c ├── check-probe.c ├── check-select-bootloader.c ├── check-syslinux.c ├── check-uefi.c ├── data ├── blobfile ├── clear.os-release ├── cmdline │ ├── comments │ ├── mangledmess │ ├── multi │ └── oneline ├── cmdline_delete_all │ ├── etc │ │ └── kernel │ │ │ └── cmdline-removal.d │ │ │ ├── comments.conf │ │ │ ├── mangledmess.conf │ │ │ ├── multi.conf │ │ │ └── oneline.conf │ └── usr │ │ └── share │ │ └── kernel │ │ └── cmdline.d │ │ └── full.conf ├── cmdline_delete_ends │ ├── etc │ │ └── kernel │ │ │ └── cmdline-removal.d │ │ │ └── ends.conf │ └── usr │ │ └── share │ │ └── kernel │ │ └── cmdline.d │ │ └── full.conf ├── cmdline_delete_middle │ ├── etc │ │ └── kernel │ │ │ └── cmdline-removal.d │ │ │ ├── comments.conf │ │ │ ├── mangledmess.conf │ │ │ ├── multi.conf │ │ │ └── oneline.conf │ └── usr │ │ └── share │ │ └── kernel │ │ └── cmdline.d │ │ └── full.conf ├── cmdline_vendor_merged │ ├── etc │ │ └── kernel │ │ │ ├── cmdline │ │ │ └── cmdline.d │ │ │ ├── 10_local_first.conf │ │ │ ├── 20_local_second.conf │ │ │ ├── 30_local_third.conf │ │ │ └── 40_masked.conf │ └── usr │ │ └── share │ │ └── kernel │ │ └── cmdline.d │ │ ├── 00_empty.conf │ │ ├── 00_newline.conf │ │ ├── 10_first.conf │ │ ├── 20_second.conf │ │ ├── 30_third.conf │ │ └── 40_masked.conf ├── cmdline_vendor_only │ └── usr │ │ └── share │ │ └── kernel │ │ └── cmdline.d │ │ ├── 10_first.conf │ │ ├── 20_second.conf │ │ └── 30_third.conf ├── etc │ └── kernel │ │ ├── cmdline │ │ └── cmdline.d │ │ ├── 00_empty.conf │ │ ├── 00_newline.conf │ │ ├── 10_first.conf │ │ ├── 20_second.conf │ │ └── 30_third.conf ├── gptmbr.bin ├── gptmbr.bin.v2 ├── match ├── match1 ├── nomatch1 ├── nomatch2 └── solus.os-release ├── harness.c ├── harness.h ├── meson.build └── system-harness.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | AccessModifierOffset: 0 3 | AlignAfterOpenBracket: true 4 | AlignConsecutiveAssignments: false 5 | #uncomment for clang 3.9 6 | #AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlinesLeft: false 8 | AlignOperands: true 9 | AlignTrailingComments: true 10 | AllowAllParametersOfDeclarationOnNextLine: true 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: None 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | # AlwaysBreakAfterDefinitionReturnType: None 17 | #uncomment for clang 3.9 18 | #AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: true 20 | AlwaysBreakTemplateDeclarations: false 21 | BinPackArguments: false 22 | BinPackParameters: true 23 | # BraceWrapping: (not set since BreakBeforeBraces is not Custom) 24 | BreakBeforeBinaryOperators: None 25 | # BreakAfterJavaFieldAnnotations: (not java) 26 | BreakBeforeBinaryOperators: None 27 | BreakBeforeBraces: Linux 28 | BreakBeforeTernaryOperators: true 29 | BreakConstructorInitializersBeforeComma: false 30 | #uncomment for clang 3.9 31 | #BreakStringLiterals: false 32 | ColumnLimit: 100 33 | CommentPragmas: '\*\<' 34 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 35 | ConstructorInitializerIndentWidth: 4 36 | ContinuationIndentWidth: 4 37 | Cpp11BracedListStyle: false 38 | DerivePointerAlignment: false 39 | DisableFormat: false 40 | ExperimentalAutoDetectBinPacking: false 41 | ForEachMacros: [ NC_LIST_FOREACH ] 42 | #Uncomment for clang 3.9 43 | #IncludeCategories: 44 | # - Regex: '^"' 45 | # Priority: 1 46 | # IncludeIsMainRegex: (project doesn't use a main includes that can add other includes via regex) 47 | IndentCaseLabels: false 48 | IndentWidth: 8 49 | IndentWrappedFunctionNames: false 50 | # JavaScriptQuotes: (not javascript) 51 | KeepEmptyLinesAtTheStartOfBlocks: false 52 | Language: Cpp 53 | MacroBlockBegin: '' 54 | MacroBlockEnd: '' 55 | MaxEmptyLinesToKeep: 1 56 | NamespaceIndentation: None 57 | # ObjCBlockIndentWidth: (not objc) 58 | # ObjCSpaceAfterProperty: (not objc) 59 | # ObjCSpaceBeforeProtocolList: (not objc) 60 | PenaltyBreakBeforeFirstCallParameter: 400 61 | PenaltyBreakComment: 0 62 | # PenaltyBreakFirstLessLess: (not cpp) 63 | PenaltyBreakString: 500 64 | PenaltyExcessCharacter: 10000 65 | PenaltyReturnTypeOnItsOwnLine: 600 66 | PointerAlignment: Right 67 | #uncomment for clang 3.9 68 | #ReflowComments: true 69 | #uncomment for clang 3.9 70 | #SortIncludes: true 71 | SpaceAfterCStyleCast: false 72 | SpaceBeforeAssignmentOperators: true 73 | SpaceBeforeParens: ControlStatements 74 | SpaceInEmptyParentheses: false 75 | SpacesBeforeTrailingComments: 1 76 | SpacesInAngles: false 77 | SpacesInCStyleCastParentheses: false 78 | # SpacesInContainerLiterals: (not objc or javascript) 79 | SpacesInParentheses: false 80 | SpacesInSquareBrackets: false 81 | Standard: Cpp11 82 | TabWidth: 8 83 | UseTab: Never 84 | ... 85 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Environment (please complete the following information):** 24 | - Clear Linux OS Version: [swupd info] 25 | - clr-boot-manager Version: [clr-boot-manager version] 26 | - Platform: [hardware infomation] 27 | 28 | ** Block Devices:** 29 | - List of Block Devices: [lsblk -a --json] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v1 10 | with: 11 | submodules: true 12 | - name: Prepare 13 | run: | 14 | sudo apt-get update 15 | sudo apt-get install libefiboot-dev check grep ninja-build meson gcc libblkid-dev lcov valgrind gnu-efi libefivar-dev ruby ruby-dev 16 | sudo gem install coveralls-lcov 17 | - name: "Run Test: stock" 18 | env: 19 | CC: "gcc-9" 20 | run: | 21 | ./scripts/run-test-suite.sh stock && coveralls-lcov outCoverage/coverage.info 22 | - name: "Run Test: systemd" 23 | env: 24 | CC: "gcc-9" 25 | run: | 26 | ./scripts/run-test-suite.sh systemd && coveralls-lcov outCoverage/coverage.info 27 | - name: "Run Test: shim-systemd-boot" 28 | env: 29 | CC: "gcc-9" 30 | run: | 31 | ./scripts/run-test-suite.sh shim-systemd-boot && coveralls-lcov outCoverage/coverage.info 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # we meson into ./build/ 2 | /build/ 3 | 4 | # coverage when using ./travis_test.sh 5 | /outCoverage/ 6 | 7 | # distributed tarball 8 | clr-boot-manager-*.tar.xz 9 | clr-boot-manager-*.tar.xz.asc 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/libnica"] 2 | path = src/libnica 3 | url = https://github.com/intel/libnica.git 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Ikey Doherty 2 | William Douglas 3 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | Hacking clr-boot-manager 2 | ---------------------- 3 | 4 | clr-boot-manager makes use of clang-format and a .clang-format configuration 5 | file found in the source root in order to validate changes conform to most of 6 | the style rules around spacing and indentation. 7 | 8 | Indentation is strictly 8 spaces (set tab stops to 8 spaces) - No tabs 9 | No spaces between function name and parentheses. Only use space after 10 | "if (", etc. 11 | 12 | Curly braces must be on the same line (i.e. expressions) unless it 13 | is the function declaration: 14 | 15 | Acceptable: 16 | int main(int argc, char **argv) 17 | { 18 | if (someThingOrOther) { 19 | // Do something 20 | } 21 | return 0; 22 | } 23 | 24 | Unacceptable: 25 | int main(int argc, char **argv) { 26 | 27 | if(someThingOrOther) 28 | { 29 | // Do something 30 | } 31 | return 0; 32 | } 33 | 34 | When appropriate remember to declare your function first! It helps when 35 | looking back through the file. 36 | 37 | Use consistent pointers! "*" should prefix your variable name. Also ensure 38 | your pointers (where appropriate) are not left uninitialized, resulting 39 | in broken free() calls. 40 | 41 | Variable and function names are lower case and functions should be fully 42 | spelled out words. Use '_' to split words in variables and functions. 43 | 44 | Acceptable: 45 | char *something = NULL; 46 | do_function(&something); 47 | 48 | Unacceptable: 49 | char* something; 50 | doFunc(&someThing); 51 | 52 | Minimise your use of "goto"'s, and test every code path is reached. Also 53 | ensure *every* if/else, etc, even if single line, is wrapped in curly braces. 54 | 55 | All conditional statements (if, if-else, while, do-while) should always use 56 | brackets regardless of the number of lines in the consequent blocks. 57 | 58 | Memory management: 59 | ------------------ 60 | clr-boot-manager prefers a scope-based approach to memory management, 61 | employing a RAII-like system for allocations. Where possible, avoid 62 | explicit free's and reuse of unrelated variables. 63 | 64 | util.h defines a number of autofree()-ready types. These are implemented 65 | using __attribute__ ((cleanup(x))), available in GCC and Clang. Thus, 66 | MSVC (and potentially other compilers) are not supported. 67 | 68 | An autofree variable is declared using the autofree() macro, which is 69 | primarily provided for syntatical sugar. Here is an example of a 70 | variable that is automatically reaped/freed when it goes out of scope: 71 | 72 | autofree(char) *error = NULL; 73 | 74 | Remember that these *are* scope sensitive, so the following would result 75 | in undefined behaviour: 76 | 77 | char *somestr = NULL; 78 | { 79 | autofree(char) *str = strdup("Scoped string\n"); 80 | somestr = str; 81 | } 82 | printf("%s: %d\n", somestr, strlen(somestr)); 83 | 84 | At this point, 'str' has been freed, and somestr still points to the 85 | memory that has now been freed. 86 | 87 | As a rule of thumb, if you find yourself in an instance where you have 88 | used an explicit free/unref in a fashion that could be automated, you 89 | should define the cleanup function in util.h (see DEF_AUTOFREE) 90 | 91 | C99 vs GLibisms 92 | --------------- 93 | clr-boot-manager is implemented using C99 (not GNU C99) and as such must 94 | build with either GCC or Clang using C99 mode (-std=c99). We use the 95 | stdbool type "bool", and public methods should use these in place of 96 | GLib's "gboolean" (which is an integer) 97 | 98 | GLib usage is not permitted in clr-boot-manager 99 | 100 | Pull Requests/commiting: 101 | ------------------------ 102 | Commits should clearly define the purpose in less than 80 columns in 103 | the first line. Futher expansion, if needed, should be provided in a 104 | following paragraph, separated by one blank line. 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | clr-boot-manager 2 | ---------------- 3 | 4 | ![](https://github.com/clearlinux/clr-boot-manager/workflows/CI/badge.svg) 5 | 6 | clr-boot-manager exists to enable the correct maintenance of vendor kernels and appropriate garbage collection tactics over the course of upgrades. The implementation provides the means to enable correct cohabitation on a shared boot directory, such as the EFI System Partition for UEFI-booting operating systems. 7 | 8 | Special care is taken to ensure the boot partition is handled gracefully, and in the instance that it is not already mounted, then clr-boot-manager will automatically discover and mount it, and automatically unmount the boot partition again when it is complete. 9 | 10 | Most importantly, clr-boot-manager provides a simple mechanism to provide kernel updates, with the ability for users to rollback to an older kernel should the new update be problematic. This is achieved through the use of strict namespace policies, permanent source paths, and clr-boot-manager's own internal logic, without the need for "meta packages" or undue complexity on the distribution side. 11 | 12 | Requirements 13 | ------------ 14 | 15 | clr-boot-manager is primarily designed to install the bootloader, kernel, initrd and accompanying metadata files for GPT disks using UEFI, however it does contain fallback support for legacy bootloaders such as GRUB2 to allow all users to benefit from automated kernel management when MBR partition tables are used. 16 | 17 | clr-boot-manager should be the only tool responsible within the OS for generating boot entries, and will automatically incorporate the correct `root=` portions. 18 | 19 | Kernel Integration 20 | ------------------ 21 | 22 | The way that a kernel is packaged changes significantly with clr-boot-manager. First and foremost, no files shall be shipped in `/boot`. The distribution should choose a namespace to identify their system in dual-boot situations, i.e: 23 | 24 | org.someproject 25 | 26 | All paths known to CBM must have follow a specific format and encoding, whereby 27 | the version, release number, and *type* are encoded: 28 | 29 | /usr/lib/kernel 30 | -> config-4.9.17-9.lts 31 | -> org.someproject.lts.4.9.17-9 32 | -> System.map-4.9.17-9.lts 33 | -> cmdline-4.9.17-9.lts 34 | -> initrd-org.someproject.lts.4.9.17-9 (Optional) 35 | /usr/src/linux-headers-4.9.17-9.lts 36 | /usr/lib/modules/4.9.17-9.lts 37 | 38 | The directories can be altered via the `./configure` options. See `./configure --help` for further details. 39 | 40 | Additionally, each kernel shall be compiled with the versioning information built 41 | in, which can be achieved by doing something similar to this in the build spec: 42 | 43 | extraVersion="-${release}.lts" 44 | sed -e "s/EXTRAVERSION =.*/EXTRAVERSION = $extraVersion/" -i Makefile 45 | 46 | This results in an easily identifiable `uname` which CBM can use to manage kernels: 47 | 48 | 49 | $ uname -a 50 | Linux some-host 4.9.17-9.lts #1 SMP Wed Mar 22 16:02:52 UTC 2017 x86_64 GNU/Linux 51 | 52 | The `initrd` file should be shipped with the kernel package itself, built for a generic target. This minimises the errors that can happen when having a non reproducible command. Users may override the initrd by providing the same filename within `/etc/kernel`. 53 | 54 | All of the above paths should be marked as resident/permanent in the software deployment mechanism as they will be automatically destroyed when clr-boot-manager performs the garbage collection cycle. Note that each "type" of kernel is up to the distribution to define, however it should be alphabetical only with no dots or hyphens. 55 | 56 | The next "default" kernel (i.e. tip for a given series) is defined with the `symlink-$(type)` notation, and allows clr-boot-manager to know that a kernel is not yet up to date. No version comparison is performed, ensuring that the symlink is always the source of information: 57 | 58 | `/usr/lib/kernel/default-lts: symbolic link to org.someproject.lts.4.9.17-9` 59 | 60 | The "post install" step for a kernel shall call `clr-boot-manager update` to push the new configuration & updates to disk. This can be called multiple times, as clr-boot-manager will only update exactly what needs to be updated, saving unnecessary writes to the ESP or `/boot` partition. 61 | 62 | Supported Filesystems/Partition Table 63 | ------------------------------------- 64 | The clr-boot-manager supports the following filesystems combination: 65 | 66 | UEFI | Filesystem | Backend 67 | -----| -----------| ------- 68 | no | ext[2-4] | extlinux 69 | no | vfat | syslinux 70 | yes | vfat | systemd-boot 71 | 72 | License 73 | ------- 74 | LGPL-2.1 75 | 76 | Copyright © 2016-2020 Intel Corporation 77 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.3.1 2 | -------------------------------------------------------------------------------- /data/clr-boot-manager-booted.service.in: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=clr-boot-manager tracking kernel boot success 3 | 4 | [Service] 5 | Type=oneshot 6 | ExecStart=@BINDIR@/clr-boot-manager report-booted 7 | 8 | [Install] 9 | WantedBy=multi-user.target 10 | -------------------------------------------------------------------------------- /data/completions/bash/clr-boot-manager.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # ----------------------------------------------------------------------- 3 | # Kernel & Boot Loader Management - autocompletion script 4 | # 5 | # Author: Lucius Hu - http://github.com/lebensterben 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 2 or later of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # ----------------------------------------------------------------------- 19 | 20 | _clr_boot_manager() { 21 | local IFS=$' \t\n' 22 | local opts _has_path 23 | 24 | case "$3" in 25 | "$1"|help) 26 | opts="version report-booted help update set-timeout get-timeout set-kernel remove-kernel list-kernels help" 27 | COMPREPLY=($(compgen -W "${opts}" -- "${2}")) 28 | ;; 29 | get-timeout|list-kernels|update|set-timeout) 30 | opts="--path --image --no-efi-update" 31 | COMPREPLY=($(compgen -W "${opts}" -- "${2}")) 32 | ;; 33 | set-kernel|remove-kernel) 34 | opts="--path --image --no-efi-update" 35 | COMPREPLY=($(compgen -W "${opts}" -- "${2}")) 36 | COMPREPLY+=($(compgen -G "@KERNEL_DIRECTORY@/@KERNEL_NAMESPACE@*" )) 37 | ;; 38 | '--path') 39 | # Tilde expansion 40 | case "$2" in 41 | \~*) 42 | eval cur="$2" 43 | ;; 44 | *) 45 | cur="$2" 46 | ;; 47 | esac 48 | # If no $CDPATH or Absolute pathname 49 | if [ -z "$CDPATH" ] || [[ "$cur" == @(./*|../*|/*) ]]; then 50 | # Print path one per line in completion, and reset it 51 | IFS=$'\n' 52 | COMPREPLY=($(compgen -d -- "$cur")) 53 | IFS=$' \t\n' 54 | # CDPATH+directories in the current directory if not in CDPATH 55 | else 56 | IFS=$'\n' 57 | _skipdot=false 58 | # preprocess CDPATH to convert null directory names to . 59 | _cdpath=${CDPATH/#:/.:} 60 | _cdpath=${_cdpath//::/:.:} 61 | _cdpath=${_cdpath/%:/:.} 62 | for i in ${_cdpath//:/$'\n'}; do 63 | if [[ $i -ef . ]]; then _skipdot=true; fi 64 | k="${#COMPREPLY[@]}" 65 | for j in $( compgen -d -- "$i/$cur" ); do 66 | COMPREPLY[k++]=${j#$i/} # cut off directory 67 | done 68 | done 69 | $_skipdot || COMPREPLY+=( $(compgen -d -- "$cur") ) 70 | IFS=$' \t\n' 71 | fi 72 | ;; 73 | *) 74 | i=${COMP_CWORD} 75 | if [ "${COMP_WORDS[$i-2]}" == "--path" ]; then 76 | _has_path="${COMP_WORDS[$i-1]}" 77 | COMPREPLY=($(compgen -W "$(find "$_has_path@KERNEL_DIRECTORY@" -maxdepth 1 -name "@KERNEL_NAMESPACE@*" -printf "%f\t" 2>/dev/null)" -- "$2" )) 78 | fi 79 | ;; 80 | esac 81 | 82 | } 83 | 84 | complete -o filenames -o nospace -o bashdefault -F _clr_boot_manager clr-boot-manager 85 | -------------------------------------------------------------------------------- /data/completions/bash/meson.build: -------------------------------------------------------------------------------- 1 | # Install commandline completion files 2 | completions_conf = configuration_data() 3 | completions_conf.set('KERNEL_DIRECTORY', with_kernel_dir) 4 | completions_conf.set('KERNEL_NAMESPACE', with_kernel_namespace) 5 | 6 | if (get_option('bash_completions')) 7 | with_bash_completions_dir = get_option('with-bash-completions-dir') 8 | if with_bash_completions_dir == '' 9 | with_bash_completions_dir = join_paths(path_datadir, 'bash-completion', 'completions') 10 | endif 11 | configure_file( 12 | input: 'clr-boot-manager.in', 13 | output: 'clr-boot-manager', 14 | configuration: completions_conf, 15 | install_dir: with_bash_completions_dir, 16 | ) 17 | endif 18 | -------------------------------------------------------------------------------- /data/completions/zsh/_clr-boot-manager.in: -------------------------------------------------------------------------------- 1 | #compdef clr-boot-manager 2 | # ----------------------------------------------------------------------- 3 | # Kernel & Boot Loader Management - autocompletion script 4 | # 5 | # Author: Lucius Hu - http://github.com/lebensterben 6 | # 7 | # This program is free software: you can redistribute it and/or modify 8 | # it under the terms of the GNU General Public License as published by 9 | # the Free Software Foundation, version 2 or later of the License. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # You should have received a copy of the GNU General Public License 17 | # along with this program. If not, see . 18 | # ----------------------------------------------------------------------- 19 | 20 | local context curcontext="$curcontext" state state_descr line ret=1 21 | local -A opt_args val_args 22 | local -a subcmds; subcmds=( 23 | "version:Print the version and quit" 24 | "report-booted:Report the current kernel as successfully booted" 25 | "update:Perform post-update configuration of the system" 26 | "set-timeout:Set the timeout to be used by the bootloader" 27 | "get-timeout:Get the timeout to be used by the bootloader" 28 | "set-kernel:Configure kernel to be used at next boot" 29 | "remove-kernel:Remove kernel from system" 30 | "list-kernels:Display currently selectable kernels to boot" 31 | "help:Display help information on available commands" 32 | ) 33 | 34 | _arguments -C \ 35 | '1:clr-boot-manager subcommand:->subcmd' \ 36 | '*::clr-boot-mannager argument:->args' \ 37 | && ret=0 38 | 39 | if [[ -n "$state" ]]; then 40 | local -a args=( 41 | '(-p --path)'{-p,--path=}'[Set the base path for boot management operations]:path: _files -/' 42 | '(-i --image)'{-i,--image}'[Force clr-boot-manager to run in image mode]' 43 | '(-n --no-efi-update)'{-n,--no-efi-update}'[Don`t update efi vars when using shim-systemd backend]' 44 | ) 45 | case "$state" in 46 | subcmd) 47 | _describe -t subcmds 'clr-boot-manager subcommand' subcmds && ret=0 48 | ;; 49 | args) 50 | case $line[1] in 51 | get-timeout|list-kernels|update) 52 | _arguments $args && ret=0 53 | ;; 54 | set-kernel|remove-kernel) 55 | local -a kernelpath 56 | 57 | kernelpath=(${opt_args[--path=]:-${opt_args[-p]}}) 58 | if (( $#kernelpath )); then 59 | # Filename expansion, path start with `~` (zsh completion system doesn't expand ~ 60 | eval kernelpath=$kernelpath 61 | # Convert to absolute path (_path_files function cannot understand relative path) 62 | kernelpath=$(realpath -e "$kernelpath") 63 | fi 64 | # Prepend it to /usr/lib/kernel 65 | kernelpath="$kernelpath@KERNEL_DIRECTORY@" 66 | if [ -r "$kernelpath" ]; then 67 | args+=(':kernel: _path_files -W "$kernelpath" -g @KERNEL_NAMESPACE@.\*') 68 | else 69 | args+=(': : _message -r "Directory \"$kernelpath\" does not exist."') 70 | fi 71 | _arguments $args && ret=0 72 | ;; 73 | set-timeout) 74 | local -a args=($args) 75 | args+=(':timeout: _message -r "Please enter an integer value"') 76 | _arguments $args && ret=0 77 | ;; 78 | help) 79 | _describe -t subcmds 'clr-boot-manager subcommand' subcmds && ret=0 80 | ;; 81 | esac 82 | ;; 83 | *) 84 | ret=1 85 | ;; 86 | esac 87 | fi 88 | 89 | return ret 90 | -------------------------------------------------------------------------------- /data/completions/zsh/meson.build: -------------------------------------------------------------------------------- 1 | # Install commandline completion files 2 | completions_conf = configuration_data() 3 | completions_conf.set('KERNEL_DIRECTORY', with_kernel_dir) 4 | completions_conf.set('KERNEL_NAMESPACE', with_kernel_namespace) 5 | 6 | if (get_option('zsh_completions')) 7 | with_zsh_completions_dir = get_option('with-zsh-completions-dir') 8 | if with_zsh_completions_dir == '' 9 | with_zsh_completions_dir = join_paths(path_datadir, 'zsh', 'site-functions') 10 | endif 11 | configure_file( 12 | input: '_clr-boot-manager.in', 13 | output: '_clr-boot-manager', 14 | configuration: completions_conf, 15 | install_dir: with_zsh_completions_dir, 16 | ) 17 | endif 18 | -------------------------------------------------------------------------------- /data/meson.build: -------------------------------------------------------------------------------- 1 | # Write systemd unit 2 | data_conf = configuration_data() 3 | data_conf.set('BINDIR', path_bindir) 4 | 5 | configure_file( 6 | input: 'clr-boot-manager-booted.service.in', 7 | output: 'clr-boot-manager-booted.service', 8 | configuration: data_conf, 9 | install_dir: with_systemd_system_unit_dir, 10 | ) 11 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # This file is part of clr-boot-manager. 3 | # 4 | # Copyright © 2017-2018 Intel Corporation 5 | # 6 | # clr-boot-manager is free software; you can redistribute it and/or 7 | # modify it under the terms of the GNU Lesser General Public License as 8 | # published by the Free Software Foundation; either version 2.1 9 | # of the License, or (at your option) any later version. 10 | # 11 | 12 | FROM clearlinux:latest 13 | ADD dockerrun.sh /dockerrun.sh 14 | RUN swupd bundle-add os-core-update-dev c-basic dev-utils-dev 15 | RUN swupd update 16 | 17 | CMD ["/dockerrun.sh"] 18 | -------------------------------------------------------------------------------- /docker/dockerrun.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of clr-boot-manager. 4 | # 5 | # Copyright © 2017-2018 Intel Corporation 6 | # 7 | # clr-boot-manager is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 10 | # of the License, or (at your option) any later version. 11 | # 12 | mkdir -p /build 13 | cd /build 14 | 15 | if [[ ! -d /source ]]; then 16 | echo "Missing source tree!" >&2 17 | exit 1 18 | fi 19 | 20 | # Copy all the files across to prevent contaminating the bind mount 21 | cp -Ra /source/. /build 22 | 23 | ./scripts/run-test-suite.sh || exit 1 24 | -------------------------------------------------------------------------------- /how-to-make-a-release: -------------------------------------------------------------------------------- 1 | 1) Run "./scripts/mkrelease.sh -n ${VERSION}" 2 | 2) Push command and tag to github and use github ui to draft a new release and upload the tarball 3 | -------------------------------------------------------------------------------- /man/clr-boot-manager.1.in: -------------------------------------------------------------------------------- 1 | .TH "CLR\-BOOT\-MANAGER" "1" "" "clr\-boot\-manager 1" "clr\-boot\-manager" 2 | 3 | .SH "NAME" 4 | clr\-boot\-manager \- Boot Loader Management 5 | 6 | .SH "SYNOPSIS" 7 | .HP \w'\clr\-boot\-manager\fR\ 'u 8 | \fBclr\-boot\-manager\fR [OPTIONS...] 9 | 10 | .SH "DESCRIPTION" 11 | .PP 12 | \fBclr\-boot\-manager\fR 13 | exists to enable the correct maintainence of vendor kernels 14 | and appropriate garbage collection tactics over the course of upgrades. 15 | The implementation provides the means to enable correct cohabitation on 16 | a shared boot directory, such as the EFI System Partition for UEFI-booting 17 | operating systems. 18 | 19 | Special care is taken to ensure the ESP is handled gracefully, and in the 20 | instance that it is not already mounted, then \fBclr\-boot\-manager\fR will 21 | automatically discover and mount it, and automatically unmount the ESP again 22 | when it is complete. 23 | 24 | .SH "OPTIONS" 25 | .PP 26 | The following options are understood: 27 | .PP 28 | \fB\-h\fR, \fB\-\-help\fR, \fBhelp\fR 29 | .RS 4 30 | Prints a help message\&. 31 | .RE 32 | .PP 33 | \fB\-p\fR, \fB\-\-path\fR 34 | .RS 4 35 | Set the base path for boot management operations\&. 36 | .RE 37 | .PP 38 | \fB\-i\fR, \fB\-\-image\fR 39 | .RS 4 40 | Force \fBclr\-boot\-manager\fR to run in image mode\&. 41 | .RE 42 | .PP 43 | \fB\-n\fR, \fB\-\-no-efi-update\fR 44 | .RS 4 45 | Force \fBclr\-boot\-manager\fR to skip efi variables update (when using shim-systemd 46 | backend)\&. 47 | .RE 48 | .PP 49 | 50 | .PP 51 | \fB\-v\fR, \fB\-\-version\fR, \fBversion\fR 52 | .RS 4 53 | Print the version of \fBclr\-boot\-manager\fR and exit\&. 54 | .RE 55 | 56 | .SH "COMMANDS" 57 | .PP 58 | The following commands are understood: 59 | 60 | .PP 61 | \fBreport-booted\fR 62 | .RS 4 63 | Report the current kernel as successfully booted. Ideally this should be 64 | invoked from the accompanying systemd unit upon boot, in order for 65 | \fBclr\-boot\-manager\fR to track known-booting kernels\&. 66 | .RE 67 | 68 | .PP 69 | \fBupdate\fR 70 | .RS 4 71 | Perform an update operation on the configured boot directory. This will 72 | analyze kernels available from the software distribution that are currently 73 | installed, and pick the ideal candidates for installation. 74 | 75 | This includes the current vendor selection for each kernel type, 76 | the currently running kernel, and the most recent successfully booted kernel 77 | of each type currently installed. 78 | 79 | All other kernels not fitting these parameters are 80 | then removed in accordance with vendor policy, and removed from the boot 81 | directory. For UEFI systems this is the EFI System Partition.\&. 82 | .RE 83 | 84 | .PP 85 | \fBset\-timeout\fR [TIMEOUT IN SECONDS] 86 | .RS 4 87 | Configure the timeout that will be used when next writing the boot loader 88 | configuration, i.e. when \fBclr\-boot\-manager update\fR is called. 89 | Setting this to a value of 0 will remove the timout entirely\&. 90 | .RE 91 | 92 | .PP 93 | \fBget\-timeout\fR 94 | .RS 4 95 | Returns the currently configured timeout as set by \fBclr\-boot\-manager set\-timeout\fR\&. 96 | .RE 97 | 98 | .PP 99 | \fBlist-kernels\fR 100 | .RS 4 101 | Display kernels currently available for booting that were provisioned by clr-boot-manager. 102 | 103 | This command will present a sorted list of kernels with the kernel that is selected for 104 | the next boot highlighted with a * prefix\&. 105 | .RE 106 | 107 | .PP 108 | \fBset-kernel\fR 109 | .RS 4 110 | Configure the default booting kernel. 111 | 112 | This command will not prevent the update command from changing the default kernel\&. 113 | .RE 114 | 115 | .PP 116 | \fBremove-kernel\fR 117 | .RS 4 118 | Remove a kernel from the system (both /boot and /usr locations). 119 | 120 | Warning: This can remove the only kernel from the system, ensure you have a default kernel 121 | set after running this command\&. 122 | .RE 123 | 124 | .SH "EXIT STATUS" 125 | .PP 126 | On success, 0 is returned, a non\-zero failure code otherwise\& 127 | 128 | .SH "CONFIGURATION" 129 | .PP 130 | clr-boot-manager takes into account the following paths to modify its behavior: 131 | 132 | .PP 133 | \fB@KERNEL_CONF_DIRECTORY@/cmdline.d/*.conf\fR 134 | .RS 4 135 | A set of files that will be used to modify the kernel commandline. The files can 136 | also be used to mask the vendor cmdline if the filename matches a vendor 137 | configuration file and is linked to /dev/null. The vendor configuration files are 138 | \fB@KERNEL_DIRECTORY@/cmdline-*\fR and \fB@VENDOR_KERNEL_CONF_DIRECTORY@/cmdline.d/*.conf\fR. 139 | 140 | The files should be in plain text format and each line will be appended directly 141 | to the kernel commandline\&. 142 | .RE 143 | 144 | .PP 145 | \fB@KERNEL_CONF_DIRECTORY@/cmdline-removal.d/*.conf\fR 146 | .RS 4 147 | A set of files that will be used to modify the kernel commandline by removing 148 | string matches from the final consolidated commandline (removal happens after 149 | the content from cmdline and cmdline.d/*.conf files are added). The matches 150 | are made on a per line basis so multiple different removals should be placed 151 | on their own line or file\&. 152 | .RE 153 | 154 | .PP 155 | \fB@KERNEL_CONF_DIRECTORY@/update_efi_vars\fR 156 | .RS 4 157 | A system-wide configuration to avoid clr-boot-manager changing efi variables when 158 | using shim-systemd backend (see flag --no-efi-update). This configuration file will 159 | be applied every time clr-boot-manager is called - even when called by a external 160 | tool non interactively. Possible values are: \fBno\fR, \fBfalse\fR\&. 161 | .RE 162 | 163 | .PP 164 | \fB@USER_INITRD_DIRECTORY@/*\fR 165 | .RS 4 166 | A set of files that will be used as additional user's freestanding initrd files. 167 | Additional initrd arguments will be added to the kernel argument list, if desired 168 | the user may mask out system installed initrd files by creating symbolic links 169 | within \fB@USER_INITRD_DIRECTORY@\fR pointing to \fB/dev/null\fR with same 170 | name of system installed files. 171 | 172 | To support early microcode updates, clr-boot-manager will identify the first file it 173 | finds named *-ucode.cpio, and ensure that is the first initrd loaded by the boot 174 | manager. There is currently no deterministic sorting, however, a matching file in 175 | \fB@USER_INITRD_DIRECTORY@\fR will take precedence over the system-provided 176 | microcode initrd in \fB@INITRD_DIRECTORY@\fR. 177 | .RE 178 | 179 | .SH "ENVIRONMENT" 180 | \fI$CBM_DEBUG\fR 181 | .RS 4 182 | Debug level to use within \fBclr\-boot\-manager\fR. This has various levels, 183 | 1 through 6, that will affect the level of debugging information printed during 184 | execution. The default log level is \fB4\fR, errors and above. 185 | 186 | \fB1\fR - Set output level to debug and above. 187 | 188 | \fB2\fR - Set output level to info and above. 189 | 190 | \fB3\fR - Set output level to success and above. 191 | 192 | \fB4\fR - Set output level to error and above. 193 | 194 | \fB5\fR - Set output level to warning and above. 195 | 196 | \fB6\fR - Set output level to fatal only.\& 197 | 198 | .RE 199 | 200 | .PP 201 | .SH "COPYRIGHT" 202 | .PP 203 | Copyright © 2016-2018 Intel Corporation\&. License: Creative Commons 204 | Attribution\-ShareAlike 3.0 Unported\s-2\u[1]\d\s+2\&. 205 | 206 | .SH "NOTES" 207 | .IP " 1." 4 208 | Creative Commons Attribution\-ShareAlike 3.0 Unported 209 | .RS 4 210 | \%https://creativecommons.org/licenses/by-sa/3.0/ 211 | .RE 212 | -------------------------------------------------------------------------------- /man/meson.build: -------------------------------------------------------------------------------- 1 | mandir = join_paths(path_prefix, get_option('mandir'), 'man1') 2 | 3 | # Update man page with paths 4 | man_data = configuration_data() 5 | man_data.set('KERNEL_CONF_DIRECTORY', with_kernel_conf_dir) 6 | man_data.set('KERNEL_DIRECTORY', with_kernel_dir) 7 | man_data.set('VENDOR_KERNEL_CONF_DIRECTORY', with_kernel_vendor_conf_dir) 8 | man_data.set('INITRD_DIRECTORY', with_initrd_dir) 9 | man_data.set('USER_INITRD_DIRECTORY', with_user_initrd_dir) 10 | man_1 = configure_file(input : 'clr-boot-manager.1.in', 11 | output : 'clr-boot-manager.1', 12 | configuration : man_data, 13 | ) 14 | 15 | install_data( 16 | man_1, 17 | install_dir: mandir, 18 | ) 19 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | # Bootloader to use 2 | option('with-bootloader', type: 'combo', choices: 3 | ['systemd-boot', 'shim-systemd-boot'], value: 'shim-systemd-boot') 4 | option('with-grub2-backend', type: 'boolean', value: true, 5 | description: 'Enables grub2 backend support.') 6 | 7 | # Currently we'll only look for gnu-efi when using shim-systemd-boot 8 | option('with-gnu-efi', type: 'string', description: 'Location of the gnu-efi headers') 9 | option('with-efi-var', type: 'string', description: 'Location of the efivar headers') 10 | 11 | # Kernel configuration 12 | option('with-kernel-conf-dir', type: 'string', description: 'System kernel configuration directory') 13 | option('with-kernel-dir', type: 'string', description: 'System kernel directory') 14 | option('with-kernel-modules-dir', type: 'string', description: 'System kernel modules directory') 15 | option('with-kernel-namespace', type: 'string', description: 'Identifier for boot assets', value: 'org.clearlinux') 16 | option('with-kernel-vendor-conf-dir', type: 'string', description: 'Vendor kernel configuration directory') 17 | 18 | # Initrd options 19 | option('with-initrd-dir', type: 'string', description: 'Directory containing freestanding initrds') 20 | 21 | # Users initrd options 22 | option('with-user-initrd-dir', type: 'string', description: 'Directory containing users freestanding initrds') 23 | 24 | # General options 25 | option('with-boot-dir', type: 'string', description: 'System boot directory', value: '/boot') 26 | option('with-vendor-prefix', type: 'string', description: 'Prefix for files created by clr-boot-manager', value: 'generic-linux-os') 27 | option('with-systemd-system-unit-dir', type: 'string', description: 'systemd unit directory') 28 | option('bash_completions', type: 'boolean', value: true, description: 'Install bash shell completions.') 29 | option('zsh_completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') 30 | option('with-bash-completions-dir', type: 'string', description: 'System bash completions directory') 31 | option('with-zsh-completions-dir', type: 'string', description: 'System zsh completions directory') 32 | option('with-uefi-entry-label', type: 'string', description: 'uefi entry label') 33 | -------------------------------------------------------------------------------- /scripts/continuous.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of clr-boot-manager. 4 | # 5 | # Copyright © 2017-2018 Intel Corporation 6 | # 7 | # clr-boot-manager is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 10 | # of the License, or (at your option) any later version. 11 | # 12 | 13 | DIRN="$(basename $(pwd))" 14 | PROJ_NAME="clr-boot-manager" 15 | PROJ_CI_NAME="docker-ci-${PROJ_NAME}" 16 | FORCE_BUILD=${FORCE_BUILD:-"false"} 17 | 18 | # Check docker is available 19 | if ! type docker &>/dev/null; then 20 | echo "Please ensure docker is installed first" 21 | exit 1 22 | fi 23 | 24 | # Check docker is running 25 | if ! docker version &>/dev/null; then 26 | echo "Docker is not running" 27 | exit 1 28 | fi 29 | 30 | # Check we're in the right directory 31 | if [[ "${DIRN}" != "${PROJ_NAME}" ]]; then 32 | echo "Please run from the root ${PROJ_NAME} directory" 33 | exit 1 34 | fi 35 | 36 | # Check that docker-ci image is installed 37 | if ! docker inspect "${PROJ_CI_NAME}" || "$FORCE_BUILD" = "true" &>/dev/null; then 38 | echo "${PROJ_CI_NAME} not installed, building docker image.." 39 | echo "....Please wait, this may take some time." 40 | docker build -t "${PROJ_CI_NAME}" docker/ || exit 1 41 | fi 42 | 43 | # Build the current tree through bind mount within the docker image 44 | echo "Beginning build of ${PROJ_NAME}..." 45 | exec docker run -ti -v $(pwd):/source:ro --rm "${PROJ_CI_NAME}" 46 | -------------------------------------------------------------------------------- /scripts/mkrelease.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of clr-boot-manager. 4 | # 5 | # Copyright © 2017 Ikey Doherty 6 | # Copyright © 2020 Intel Corporation 7 | # 8 | # clr-boot-manager is free software; you can redistribute it and/or 9 | # modify it under the terms of the GNU Lesser General Public License as 10 | # published by the Free Software Foundation; either version 2.1 11 | # of the License, or (at your option) any later version. 12 | # 13 | 14 | set -e 15 | 16 | pkg="clr-boot-manager" 17 | SIGN=0 18 | 19 | print_help() { 20 | echo -e "mkrelease.sh [--help] [options] 21 | 22 | mkrelease.sh executes all the required steps before cutting a new release(set 23 | new version, creates bundled artifacts including vendored components, creates 24 | the release tag etc). 25 | 26 | Help Options: 27 | -h, --help Show this help list 28 | 29 | Options: 30 | -n, --new-version The release's new version" 31 | } 32 | 33 | for curr in "$@"; do 34 | case $curr in 35 | "--new-version"|"-n") 36 | version=$2 37 | shift 38 | shift 39 | ;; 40 | "--sign"|"-s") 41 | SIGN=1 42 | shift 43 | ;; 44 | "--help"|"-h") 45 | print_help; 46 | exit 0;; 47 | esac 48 | done 49 | 50 | if [ "$version" == "" ]; then 51 | echo "No version provided, please use \"--new-version\" flag. Use --help for more information." 52 | exit 1 53 | fi 54 | 55 | echo "${version}" > VERSION 56 | git commit -a -s -m "v${version} release" 57 | git tag "v${version}" 58 | 59 | git submodule init 60 | git submodule update 61 | 62 | ./scripts/git-archive-all.sh --format tar --prefix ${pkg}-${version}/ \ 63 | --verbose -t "v${version}" ${pkg}-${version}.tar 64 | 65 | xz -9 "${pkg}-${version}.tar" 66 | 67 | # Automatically sign the tarball 68 | if [ $SIGN -eq 1 ]; then 69 | gpg --armor --detach-sign "${pkg}-${version}.tar.xz" 70 | gpg --verify "${pkg}-${version}.tar.xz.asc" 71 | fi 72 | -------------------------------------------------------------------------------- /scripts/run-test-suite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This file is part of clr-boot-manager. 4 | # 5 | # Copyright © 2017 Ikey Doherty 6 | # 7 | # clr-boot-manager is free software; you can redistribute it and/or 8 | # modify it under the terms of the GNU Lesser General Public License as 9 | # published by the Free Software Foundation; either version 2.1 10 | # of the License, or (at your option) any later version. 11 | # 12 | 13 | set -e 14 | 15 | testRoot=`pwd` 16 | suppressions="$testRoot/sgcheck.suppressions" 17 | coverDir="$testRoot/outCoverage" 18 | 19 | # build configuration/arguments 20 | configs=() 21 | systemdConfig="-Dwith-bootloader=systemd-boot" 22 | shimSystemdConfig="-Dwith-bootloader=shim-systemd-boot" 23 | withCoverage=true 24 | fullConfigSet=false 25 | stockConfig=false 26 | 27 | print_help() { 28 | echo -e "run-test-suite.sh [flags] [targets] 29 | Flags: 30 | --help|help Show this help list 31 | --no-coverage Don't run the coverage generation 32 | 33 | Targets: 34 | shim-systemd-boot run test with shim-systemd-boot backend 35 | stock run test on top of a stock configuration 36 | systemd run test with systemd backend 37 | all run all the above" 38 | } 39 | 40 | # Just perform a single build 41 | build_one() { 42 | meson build --buildtype debugoptimized -Db_coverage=true --prefix=/usr --sysconfdir=/etc \ 43 | --datadir=/usr/share -Dwith-systemd-system-unit-dir=/lib/systemd/system $* 44 | ninja -C build 45 | } 46 | 47 | # Do a check with the various valgrind tools 48 | check_valgrind() { 49 | local valgrindArgs="valgrind --suppressions=\"$suppressions\" --error-exitcode=1" 50 | 51 | # Memory test 52 | meson test -C build --print-errorlogs --logbase=memcheck \ 53 | --wrap="$valgrindArgs --tool=memcheck --leak-check=full --show-reachable=no" 54 | meson test -C build --print-errorlogs --logbase=helgrind --wrap="$valgrindArgs --tool=helgrind" 55 | meson test -C build --print-errorlogs --logbase=drd --wrap="$valgrindArgs --tool=drd" 56 | } 57 | 58 | # Do a "normal" test suite check 59 | check_normal() { 60 | meson test -C build --print-errorlogs 61 | } 62 | 63 | # Store the coverage report. If we have one, merge the new report. Finally, 64 | # strip any unneeded noise from the report, to prepare it for upload 65 | stash_coverage() { 66 | ninja -C build coverage-html 67 | local coverageFile="$coverDir/coverage.info" 68 | local sampleFile="./build/meson-logs/coverage.info" 69 | 70 | if [[ ! -d "$coverDir" ]]; then 71 | mkdir "$coverDir" 72 | fi 73 | 74 | # Does this guy exist? 75 | if [[ ! -s "$coverageFile" ]]; then 76 | cp -v "$sampleFile" "$coverageFile" 77 | else 78 | # Merge them! 79 | lcov -a "$coverageFile" -a "$sampleFile" -o "${coverageFile}.tmp" 80 | 81 | # Stick this guy back as the main coverage file now 82 | mv "${coverageFile}.tmp" "$coverageFile" 83 | fi 84 | 85 | if [[ ! -s "$coverageFile" ]]; then 86 | # Ensure we remove any unnecessary junk now 87 | lcov --remove "$coverageFile" 'tests/*' '/usr/*' --output-file "$coverageFile" 88 | fi 89 | } 90 | 91 | set_full_config() { 92 | fullConfigSet=true 93 | configs=("" $systemdConfig $shimSystemdConfig) 94 | } 95 | 96 | for curr in "$@"; do 97 | case $curr in 98 | "stock") 99 | if [[ "$fullConfigSet" = false ]]; then 100 | stockConfig=true 101 | configs+=("") 102 | fi;; 103 | "systemd") 104 | if [[ "$fullConfigSet" = false ]]; then 105 | configs+=($systemdConfig) 106 | fi;; 107 | "shim-systemd-boot") 108 | if [[ "$fullConfigSet" = false ]]; then 109 | configs+=($shimSystemdConfig) 110 | fi;; 111 | "all") 112 | set_full_config;; 113 | "--no-coverage") 114 | withCoverage=false;; 115 | "help"|"--help") 116 | print_help; 117 | exit 0;; 118 | esac 119 | done 120 | 121 | if [[ ${#configs[@]} -eq 0 ]] && [[ "$stockConfig" = false ]]; then 122 | set_full_config 123 | fi 124 | 125 | for buildArg in "${configs[@]}"; do 126 | # Let's do our stock configuration first 127 | echo "Performing build: $buildArg" 128 | 129 | # nuke the build dir 130 | if [[ -d "build" ]]; then 131 | rm -rf "build" 132 | fi 133 | 134 | build_one $buildArg --libdir=/usr/lib64 135 | check_normal 136 | check_valgrind 137 | 138 | if [[ "$withCoverage" = true ]]; then 139 | # Stash the coverage as we'll want this guy later 140 | stash_coverage 141 | fi 142 | done 143 | -------------------------------------------------------------------------------- /scripts/update-format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | clang-format -i $(find . -not -path '*/libnica/*' -name '*.[ch]') 4 | 5 | # Check we have no typos. 6 | which misspell 2>/dev/null >/dev/null 7 | if [[ $? -eq 0 ]]; then 8 | misspell -error `find . -name '*.[ch]'` 9 | fi 10 | -------------------------------------------------------------------------------- /sgcheck.suppressions: -------------------------------------------------------------------------------- 1 | { 2 | 3 | exp-sgcheck:SorG 4 | fun:_IO_vfscanf 5 | fun:vsscanf 6 | fun:sscanf 7 | fun:boot_manager_inspect_kernel 8 | fun:boot_manager_get_kernels 9 | fun:bootman_list_kernels_test 10 | obj:/usr/*lib*/libcheck.so.0.0.0 11 | fun:srunner_run 12 | fun:main 13 | } 14 | 15 | { 16 | 17 | exp-sgcheck:SorG 18 | fun:vfprintf 19 | fun:__vasprintf_chk 20 | fun:__asprintf_chk 21 | fun:boot_manager_inspect_kernel 22 | fun:boot_manager_get_kernels 23 | fun:bootman_list_kernels_test 24 | obj:/usr/*lib64*/libcheck.so.0.0.0 25 | fun:srunner_run 26 | fun:main 27 | } 28 | 29 | { 30 | 31 | Memcheck:Leak 32 | match-leak-kinds: definite 33 | fun:malloc 34 | fun:UnknownInlinedFun 35 | fun:UnknownInlinedFun 36 | fun:tag_string_to_list 37 | fun:UnknownInlinedFun 38 | fun:srunner_run_tagged 39 | fun:main 40 | } 41 | -------------------------------------------------------------------------------- /src/bootloaders/bootloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "bootman.h" 15 | 16 | #if UINTPTR_MAX == 0xffffffffffffffff 17 | #define DEFAULT_EFI_BLOB "BOOTX64.EFI" 18 | #else 19 | #define DEFAULT_EFI_BLOB "BOOTIA32.EFI" 20 | #endif 21 | 22 | typedef bool (*boot_loader_init)(const BootManager *); 23 | typedef bool (*boot_loader_install_kernel)(const BootManager *, const Kernel *); 24 | typedef const char *(*boot_loader_get_kernel_destination)(const BootManager *); 25 | typedef bool (*boot_loader_remove_kernel)(const BootManager *, const Kernel *); 26 | typedef bool (*boot_loader_set_default_kernel)(const BootManager *, const Kernel *kernel); 27 | typedef char *(*boot_loader_get_default_kernel)(const BootManager *); 28 | typedef bool (*boot_loader_needs_update)(const BootManager *); 29 | typedef bool (*boot_loader_needs_install)(const BootManager *); 30 | typedef bool (*boot_loader_install)(const BootManager *); 31 | typedef bool (*boot_loader_update)(const BootManager *); 32 | typedef bool (*boot_loader_remove)(const BootManager *); 33 | typedef void (*boot_loader_destroy)(const BootManager *); 34 | typedef int (*boot_loader_caps)(const BootManager *); 35 | 36 | typedef enum { 37 | BOOTLOADER_CAP_MIN = 1 << 0, 38 | BOOTLOADER_CAP_UEFI = 1 << 1, /** 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "bootloader.h" 27 | #include "files.h" 28 | #include "log.h" 29 | #include "mbr.h" 30 | #include "nica/files.h" 31 | #include "syslinux-common.h" 32 | #include "system_stub.h" 33 | #include "util.h" 34 | #include "writer.h" 35 | 36 | static bool extlinux_command_writer(struct SyslinuxContext *ctx, const char *prefix, char *boot_device) 37 | { 38 | ctx->syslinux_cmd = string_printf("%s/usr/bin/extlinux -i %s --device %s &> /dev/null", 39 | prefix, ctx->base_path, boot_device); 40 | return ctx->syslinux_cmd != NULL; 41 | } 42 | 43 | static bool extlinux_init(const BootManager *manager) 44 | { 45 | return syslinux_common_init(manager, extlinux_command_writer); 46 | } 47 | 48 | /* No op due since conf file will only have queued kernels anyway */ 49 | static bool extlinux_remove_kernel(__cbm_unused__ const BootManager *manager, 50 | __cbm_unused__ const Kernel *kernel) 51 | { 52 | return true; 53 | } 54 | 55 | static bool extlinux_needs_update(__cbm_unused__ const BootManager *manager) 56 | { 57 | return true; 58 | } 59 | 60 | static bool extlinux_needs_install(__cbm_unused__ const BootManager *manager) 61 | { 62 | return true; 63 | } 64 | 65 | static bool extlinux_update(const BootManager *manager) 66 | { 67 | return syslinux_common_install(manager); 68 | } 69 | 70 | static bool extlinux_remove(__cbm_unused__ const BootManager *manager) 71 | { 72 | /* Maybe should return false? Unsure */ 73 | return true; 74 | } 75 | 76 | static int extlinux_get_capabilities(const BootManager *manager) 77 | { 78 | const char *prefix = NULL; 79 | autofree(char) *command = NULL; 80 | 81 | prefix = boot_manager_get_prefix((BootManager *)manager); 82 | command = string_printf("%s/usr/bin/extlinux", prefix); 83 | 84 | if (access(command, X_OK) != 0) { 85 | LOG_DEBUG("extlinux not found at %s\n", command); 86 | return 0; 87 | } 88 | 89 | return BOOTLOADER_CAP_GPT | BOOTLOADER_CAP_LEGACY | BOOTLOADER_CAP_EXTFS; 90 | } 91 | 92 | __cbm_export__ const BootLoader extlinux_bootloader = {.name = "extlinux", 93 | .init = extlinux_init, 94 | .install_kernel = 95 | syslinux_common_install_kernel, 96 | .remove_kernel = extlinux_remove_kernel, 97 | .set_default_kernel = 98 | syslinux_common_set_default_kernel, 99 | .get_default_kernel = 100 | syslinux_common_get_default_kernel, 101 | .needs_install = extlinux_needs_install, 102 | .needs_update = extlinux_needs_update, 103 | .install = syslinux_common_install, 104 | .update = extlinux_update, 105 | .remove = extlinux_remove, 106 | .destroy = syslinux_common_destroy, 107 | .get_capabilities = 108 | extlinux_get_capabilities }; 109 | 110 | /* 111 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 112 | * 113 | * Local variables: 114 | * c-basic-offset: 8 115 | * tab-width: 8 116 | * indent-tabs-mode: nil 117 | * End: 118 | * 119 | * vi: set shiftwidth=8 tabstop=8 expandtab: 120 | * :indentSize=8:tabSize=8:noTabs=true: 121 | */ 122 | -------------------------------------------------------------------------------- /src/bootloaders/mbr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is based on mbr.bin and gptmbr.bin from SYSLINUX. 3 | * 4 | * SYSLINUX is: 5 | * 6 | * Copyright 1994-2011 H. Peter Anvin et al - All Rights Reserved 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 11 | * Boston MA 02111-1307, USA; either version 2 of the License, or 12 | * (at your option) any later version; incorporated herein by reference. 13 | * 14 | */ 15 | 16 | #define MBR_BIN_LEN 440 17 | 18 | unsigned char syslinux_mbr_bin[] = { 19 | 0x33, 0xc0, 0xfa, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x89, 0xe6, 20 | 0x06, 0x57, 0x8e, 0xc0, 0xfb, 0xfc, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 21 | 0xf3, 0xa5, 0xea, 0x1f, 0x06, 0x00, 0x00, 0x52, 0x52, 0xb4, 0x41, 0xbb, 22 | 0xaa, 0x55, 0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x72, 0x13, 0x81, 23 | 0xfb, 0x55, 0xaa, 0x75, 0x0d, 0xd1, 0xe9, 0x73, 0x09, 0x66, 0xc7, 0x06, 24 | 0x8d, 0x06, 0xb4, 0x42, 0xeb, 0x15, 0x5a, 0xb4, 0x08, 0xcd, 0x13, 0x83, 25 | 0xe1, 0x3f, 0x51, 0x0f, 0xb6, 0xc6, 0x40, 0xf7, 0xe1, 0x52, 0x50, 0x66, 26 | 0x31, 0xc0, 0x66, 0x99, 0xe8, 0x66, 0x00, 0xe8, 0x35, 0x01, 0x4d, 0x69, 27 | 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 28 | 0x69, 0x6e, 0x67, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x0d, 29 | 0x0a, 0x66, 0x60, 0x66, 0x31, 0xd2, 0xbb, 0x00, 0x7c, 0x66, 0x52, 0x66, 30 | 0x50, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0x66, 0xf7, 0x36, 31 | 0xf4, 0x7b, 0xc0, 0xe4, 0x06, 0x88, 0xe1, 0x88, 0xc5, 0x92, 0xf6, 0x36, 32 | 0xf8, 0x7b, 0x88, 0xc6, 0x08, 0xe1, 0x41, 0xb8, 0x01, 0x02, 0x8a, 0x16, 33 | 0xfa, 0x7b, 0xcd, 0x13, 0x8d, 0x64, 0x10, 0x66, 0x61, 0xc3, 0xe8, 0xc4, 34 | 0xff, 0xbe, 0xbe, 0x7d, 0xbf, 0xbe, 0x07, 0xb9, 0x20, 0x00, 0xf3, 0xa5, 35 | 0xc3, 0x66, 0x60, 0x89, 0xe5, 0xbb, 0xbe, 0x07, 0xb9, 0x04, 0x00, 0x31, 36 | 0xc0, 0x53, 0x51, 0xf6, 0x07, 0x80, 0x74, 0x03, 0x40, 0x89, 0xde, 0x83, 37 | 0xc3, 0x10, 0xe2, 0xf3, 0x48, 0x74, 0x5b, 0x79, 0x39, 0x59, 0x5b, 0x8a, 38 | 0x47, 0x04, 0x3c, 0x0f, 0x74, 0x06, 0x24, 0x7f, 0x3c, 0x05, 0x75, 0x22, 39 | 0x66, 0x8b, 0x47, 0x08, 0x66, 0x8b, 0x56, 0x14, 0x66, 0x01, 0xd0, 0x66, 40 | 0x21, 0xd2, 0x75, 0x03, 0x66, 0x89, 0xc2, 0xe8, 0xac, 0xff, 0x72, 0x03, 41 | 0xe8, 0xb6, 0xff, 0x66, 0x8b, 0x46, 0x1c, 0xe8, 0xa0, 0xff, 0x83, 0xc3, 42 | 0x10, 0xe2, 0xcc, 0x66, 0x61, 0xc3, 0xe8, 0x76, 0x00, 0x4d, 0x75, 0x6c, 43 | 0x74, 0x69, 0x70, 0x6c, 0x65, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 44 | 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 45 | 0x0d, 0x0a, 0x66, 0x8b, 0x44, 0x08, 0x66, 0x03, 0x46, 0x1c, 0x66, 0x89, 46 | 0x44, 0x08, 0xe8, 0x30, 0xff, 0x72, 0x27, 0x66, 0x81, 0x3e, 0x00, 0x7c, 47 | 0x58, 0x46, 0x53, 0x42, 0x75, 0x09, 0x66, 0x83, 0xc0, 0x04, 0xe8, 0x1c, 48 | 0xff, 0x72, 0x13, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x0f, 0x85, 0xf2, 49 | 0xfe, 0xbc, 0xfa, 0x7b, 0x5a, 0x5f, 0x07, 0xfa, 0xff, 0xe4, 0xe8, 0x1e, 50 | 0x00, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x73, 51 | 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x65, 52 | 0x72, 0x72, 0x6f, 0x72, 0x2e, 0x0d, 0x0a, 0x5e, 0xac, 0xb4, 0x0e, 0x8a, 53 | 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10, 0x3c, 0x0a, 0x75, 0xf1, 0xcd, 54 | 0x18, 0xf4, 0xeb, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 55 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 56 | }; 57 | 58 | unsigned char syslinux_gptmbr_bin[] = { 59 | 0x33, 0xc0, 0xfa, 0x8e, 0xd8, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x89, 0xe6, 60 | 0x06, 0x57, 0x8e, 0xc0, 0xfb, 0xfc, 0xbf, 0x00, 0x06, 0xb9, 0x00, 0x01, 61 | 0xf3, 0xa5, 0xea, 0x1f, 0x06, 0x00, 0x00, 0x52, 0x89, 0xe5, 0x83, 0xec, 62 | 0x1c, 0x6a, 0x1e, 0xc7, 0x46, 0xfa, 0x00, 0x02, 0x52, 0xb4, 0x41, 0xbb, 63 | 0xaa, 0x55, 0x31, 0xc9, 0x30, 0xf6, 0xf9, 0xcd, 0x13, 0x5a, 0xb4, 0x08, 64 | 0x72, 0x17, 0x81, 0xfb, 0x55, 0xaa, 0x75, 0x11, 0xd1, 0xe9, 0x73, 0x0d, 65 | 0x66, 0xc7, 0x06, 0x59, 0x07, 0xb4, 0x42, 0xeb, 0x13, 0xb4, 0x48, 0x89, 66 | 0xe6, 0xcd, 0x13, 0x83, 0xe1, 0x3f, 0x51, 0x0f, 0xb6, 0xc6, 0x40, 0xf7, 67 | 0xe1, 0x52, 0x50, 0x66, 0x31, 0xc0, 0x66, 0x99, 0x40, 0xe8, 0xdc, 0x00, 68 | 0x8b, 0x4e, 0x56, 0x8b, 0x46, 0x5a, 0x50, 0x51, 0xf7, 0xe1, 0xf7, 0x76, 69 | 0xfa, 0x91, 0x41, 0x66, 0x8b, 0x46, 0x4e, 0x66, 0x8b, 0x56, 0x52, 0x53, 70 | 0xe8, 0xc4, 0x00, 0xe2, 0xfb, 0x31, 0xf6, 0x5f, 0x59, 0x58, 0x66, 0x8b, 71 | 0x15, 0x66, 0x0b, 0x55, 0x04, 0x66, 0x0b, 0x55, 0x08, 0x66, 0x0b, 0x55, 72 | 0x0c, 0x74, 0x0c, 0xf6, 0x45, 0x30, 0x04, 0x74, 0x06, 0x21, 0xf6, 0x75, 73 | 0x19, 0x89, 0xfe, 0x01, 0xc7, 0xe2, 0xdf, 0x21, 0xf6, 0x75, 0x2e, 0xe8, 74 | 0xe1, 0x00, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4f, 0x53, 75 | 0x0d, 0x0a, 0xe8, 0xd2, 0x00, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 76 | 0x65, 0x20, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x61, 0x72, 77 | 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x0d, 0x0a, 0x91, 0xbf, 0xbe, 78 | 0x07, 0x57, 0x66, 0x31, 0xc0, 0xb0, 0x80, 0x66, 0xab, 0xb0, 0xed, 0x66, 79 | 0xab, 0x66, 0x8b, 0x44, 0x20, 0x66, 0x8b, 0x54, 0x24, 0xe8, 0x40, 0x00, 80 | 0x66, 0x8b, 0x44, 0x28, 0x66, 0x8b, 0x54, 0x2c, 0x66, 0x2b, 0x44, 0x20, 81 | 0x66, 0x1b, 0x54, 0x24, 0xe8, 0x70, 0x00, 0xe8, 0x2a, 0x00, 0x66, 0x0f, 82 | 0xb7, 0xc1, 0x66, 0xab, 0xf3, 0xa4, 0x5e, 0x66, 0x8b, 0x44, 0x34, 0x66, 83 | 0x8b, 0x54, 0x38, 0xe8, 0x22, 0x00, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 84 | 0x75, 0x85, 0x89, 0xec, 0x5a, 0x5f, 0x07, 0x66, 0xb8, 0x21, 0x47, 0x50, 85 | 0x54, 0xfa, 0xff, 0xe4, 0x66, 0x21, 0xd2, 0x74, 0x04, 0x66, 0x83, 0xc8, 86 | 0xff, 0x66, 0xab, 0xc3, 0xbb, 0x00, 0x7c, 0x66, 0x60, 0x66, 0x52, 0x66, 87 | 0x50, 0x06, 0x53, 0x6a, 0x01, 0x6a, 0x10, 0x89, 0xe6, 0x66, 0xf7, 0x76, 88 | 0xdc, 0xc0, 0xe4, 0x06, 0x88, 0xe1, 0x88, 0xc5, 0x92, 0xf6, 0x76, 0xe0, 89 | 0x88, 0xc6, 0x08, 0xe1, 0x41, 0xb8, 0x01, 0x02, 0x8a, 0x56, 0x00, 0xcd, 90 | 0x13, 0x8d, 0x64, 0x10, 0x66, 0x61, 0x72, 0x0c, 0x02, 0x7e, 0xfb, 0x66, 91 | 0x83, 0xc0, 0x01, 0x66, 0x83, 0xd2, 0x00, 0xc3, 0xe8, 0x0c, 0x00, 0x44, 92 | 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x0d, 0x0a, 0x5e, 93 | 0xac, 0xb4, 0x0e, 0x8a, 0x3e, 0x62, 0x04, 0xb3, 0x07, 0xcd, 0x10, 0x3c, 94 | 0x0a, 0x75, 0xf1, 0xcd, 0x18, 0xf4, 0xeb, 0xfd, 0x00, 0x00, 0x00, 0x00, 95 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 96 | }; 97 | -------------------------------------------------------------------------------- /src/bootloaders/mbr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is based on mbr.bin and gptmbr.bin from SYSLINUX. 3 | * 4 | * SYSLINUX is: 5 | * 6 | * Copyright 1994-2011 H. Peter Anvin et al - All Rights Reserved 7 | * 8 | * This program is free software; you can redistribute it and/or modify 9 | * it under the terms of the GNU General Public License as published by 10 | * the Free Software Foundation, Inc., 53 Temple Place Ste 330, 11 | * Boston MA 02111-1307, USA; either version 2 of the License, or 12 | * (at your option) any later version; incorporated herein by reference. 13 | * 14 | */ 15 | 16 | #define MBR_BIN_LEN 440 17 | 18 | extern unsigned char syslinux_mbr_bin[]; 19 | extern unsigned char syslinux_gptmbr_bin[]; 20 | -------------------------------------------------------------------------------- /src/bootloaders/syslinux-common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2020 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | struct SyslinuxContext { 15 | KernelArray *kernel_queue; 16 | char *syslinux_cmd; 17 | char *sgdisk_cmd; 18 | char *base_path; 19 | }; 20 | 21 | typedef bool (*command_writer)(struct SyslinuxContext *ctx, const char *prefix, char *boot_device); 22 | 23 | /** 24 | * Common implementation of get_default_kernel for both syslinux and extlinux 25 | */ 26 | char *syslinux_common_get_default_kernel(const BootManager *manager); 27 | 28 | /* Queue kernel to be added to conf */ 29 | bool syslinux_common_install_kernel(const BootManager *manager, const Kernel *kernel); 30 | 31 | /* Actually creates the whole conf by iterating through the queued kernels */ 32 | bool syslinux_common_set_default_kernel(const BootManager *manager, const Kernel *default_kernel); 33 | 34 | /* Cleans up the syslinux bootmanager's instance/private data */ 35 | void syslinux_common_destroy(const BootManager *manager); 36 | 37 | /* Common syslinux boot loader initialization */ 38 | bool syslinux_common_init(const BootManager *manager, command_writer writer); 39 | 40 | /* Installs both syslinux and extlinux bootloaders */ 41 | bool syslinux_common_install(const BootManager *manager); 42 | 43 | /* 44 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 45 | * 46 | * Local variables: 47 | * c-basic-offset: 8 48 | * tab-width: 8 49 | * indent-tabs-mode: nil 50 | * End: 51 | * 52 | * vi: set shiftwidth=8 tabstop=8 expandtab: 53 | * :indentSize=8:tabSize=8:noTabs=true: 54 | */ 55 | -------------------------------------------------------------------------------- /src/bootloaders/syslinux.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "bootloader.h" 27 | #include "files.h" 28 | #include "lib/probe.h" 29 | #include "log.h" 30 | #include "mbr.h" 31 | #include "nica/files.h" 32 | #include "syslinux-common.h" 33 | #include "system_stub.h" 34 | #include "util.h" 35 | #include "writer.h" 36 | 37 | static bool syslinux_command_writer(struct SyslinuxContext *ctx, const char *prefix, char *boot_device) 38 | { 39 | // syslinux -U will not work with a partuuid, the effect of "install" and 40 | // "update" will always be the same, so assume install for all scenarios 41 | ctx->syslinux_cmd = string_printf("%s/usr/bin/syslinux-nomtools -i %s &> /dev/null", 42 | prefix, boot_device); 43 | return ctx->syslinux_cmd != NULL; 44 | } 45 | 46 | static bool syslinux_init(const BootManager *manager) 47 | { 48 | return syslinux_common_init(manager, syslinux_command_writer); 49 | } 50 | 51 | /* No op due since conf file will only have queued kernels anyway */ 52 | static bool syslinux_remove_kernel(__cbm_unused__ const BootManager *manager, 53 | __cbm_unused__ const Kernel *kernel) 54 | { 55 | return true; 56 | } 57 | 58 | static bool syslinux_needs_update(__cbm_unused__ const BootManager *manager) 59 | { 60 | return true; 61 | } 62 | 63 | static bool syslinux_needs_install(__cbm_unused__ const BootManager *manager) 64 | { 65 | return true; 66 | } 67 | 68 | static bool syslinux_update(const BootManager *manager) 69 | { 70 | return syslinux_common_install(manager); 71 | } 72 | 73 | static bool syslinux_remove(__cbm_unused__ const BootManager *manager) 74 | { 75 | /* Maybe should return false? Unsure */ 76 | return true; 77 | } 78 | 79 | static int syslinux_get_capabilities(const BootManager *manager) 80 | { 81 | const char *prefix = NULL; 82 | autofree(char) *command = NULL; 83 | 84 | prefix = boot_manager_get_prefix((BootManager *)manager); 85 | command = string_printf("%s/usr/bin/syslinux", prefix); 86 | if (access(command, X_OK) != 0) { 87 | LOG_DEBUG("syslinux not found at %s\n", command); 88 | return 0; 89 | } 90 | 91 | return BOOTLOADER_CAP_GPT | BOOTLOADER_CAP_LEGACY | BOOTLOADER_CAP_FATFS; 92 | } 93 | 94 | __cbm_export__ const BootLoader syslinux_bootloader = {.name = "syslinux", 95 | .init = syslinux_init, 96 | .install_kernel = 97 | syslinux_common_install_kernel, 98 | .remove_kernel = syslinux_remove_kernel, 99 | .set_default_kernel = 100 | syslinux_common_set_default_kernel, 101 | .get_default_kernel = 102 | syslinux_common_get_default_kernel, 103 | .needs_install = syslinux_needs_install, 104 | .needs_update = syslinux_needs_update, 105 | .install = syslinux_common_install, 106 | .update = syslinux_update, 107 | .remove = syslinux_remove, 108 | .destroy = syslinux_common_destroy, 109 | .get_capabilities = 110 | syslinux_get_capabilities }; 111 | 112 | /* 113 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 114 | * 115 | * Local variables: 116 | * c-basic-offset: 8 117 | * tab-width: 8 118 | * indent-tabs-mode: nil 119 | * End: 120 | * 121 | * vi: set shiftwidth=8 tabstop=8 expandtab: 122 | * :indentSize=8:tabSize=8:noTabs=true: 123 | */ 124 | -------------------------------------------------------------------------------- /src/bootloaders/systemd-boot.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include "systemd-class.h" 15 | 16 | static BootLoaderConfig systemd_boot_config = {.vendor_dir = "systemd", 17 | .efi_dir = "/usr/lib/systemd/boot/efi", 18 | .efi_blob = "systemd-boot" SYSTEMD_EFI_SUFFIX, 19 | .name = "systemd-boot" }; 20 | 21 | static bool systemd_boot_init(const BootManager *manager) 22 | { 23 | return sd_class_init(manager, &systemd_boot_config); 24 | } 25 | 26 | __cbm_export__ const BootLoader 27 | systemd_bootloader = {.name = "systemd", 28 | .init = systemd_boot_init, 29 | .get_kernel_destination = sd_class_get_kernel_destination, 30 | .install_kernel = sd_class_install_kernel, 31 | .remove_kernel = sd_class_remove_kernel, 32 | .set_default_kernel = sd_class_set_default_kernel, 33 | .get_default_kernel = sd_class_get_default_kernel, 34 | .needs_install = sd_class_needs_install, 35 | .needs_update = sd_class_needs_update, 36 | .install = sd_class_install, 37 | .update = sd_class_update, 38 | .remove = sd_class_remove, 39 | .destroy = sd_class_destroy, 40 | .get_capabilities = sd_class_get_capabilities }; 41 | 42 | /* 43 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 44 | * 45 | * Local variables: 46 | * c-basic-offset: 8 47 | * tab-width: 8 48 | * indent-tabs-mode: nil 49 | * End: 50 | * 51 | * vi: set shiftwidth=8 tabstop=8 expandtab: 52 | * :indentSize=8:tabSize=8:noTabs=true: 53 | */ 54 | -------------------------------------------------------------------------------- /src/bootloaders/systemd-class.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include "bootloader.h" 15 | #include "bootman.h" 16 | 17 | #pragma once 18 | 19 | #if UINTPTR_MAX == 0xffffffffffffffff 20 | #define SYSTEMD_EFI_SUFFIX "x64.efi" 21 | #else 22 | #define SYSTEMD_EFI_SUFFIX "ia32.efi" 23 | #endif 24 | 25 | typedef struct BootLoaderConfig { 26 | const char *vendor_dir; 27 | const char *efi_dir; 28 | const char *efi_blob; 29 | const char *name; 30 | } BootLoaderConfig; 31 | 32 | const char *sd_class_get_kernel_destination(const BootManager *manager); 33 | 34 | bool sd_class_install_kernel(const BootManager *manager, const Kernel *kernel); 35 | 36 | bool sd_class_remove_kernel(const BootManager *manager, const Kernel *kernel); 37 | 38 | bool sd_class_set_default_kernel(const BootManager *manager, const Kernel *kernel); 39 | 40 | char *sd_class_get_default_kernel(const BootManager *manager); 41 | 42 | bool sd_class_needs_install(const BootManager *manager); 43 | 44 | bool sd_class_needs_update(const BootManager *manager); 45 | 46 | bool sd_class_install(const BootManager *manager); 47 | 48 | bool sd_class_update(const BootManager *manager); 49 | 50 | bool sd_class_remove(const BootManager *manager); 51 | 52 | bool sd_class_init(const BootManager *manager, BootLoaderConfig *config); 53 | 54 | void sd_class_destroy(const BootManager *manager); 55 | 56 | int sd_class_get_capabilities(const BootManager *manager); 57 | 58 | /* 59 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 60 | * 61 | * Local variables: 62 | * c-basic-offset: 8 63 | * tab-width: 8 64 | * indent-tabs-mode: nil 65 | * End: 66 | * 67 | * vi: set shiftwidth=8 tabstop=8 expandtab: 68 | * :indentSize=8:tabSize=8:noTabs=true: 69 | */ 70 | -------------------------------------------------------------------------------- /src/bootman/bootman_private.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * This file masks private implementation details to share throughout the 5 | * libcbm implementation for the purposes of organisational sanity. 6 | * 7 | * Copyright © 2016-2018 Intel Corporation 8 | * 9 | * clr-boot-manager is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public License as 11 | * published by the Free Software Foundation; either version 2.1 12 | * of the License, or (at your option) any later version. 13 | */ 14 | 15 | #pragma once 16 | 17 | #ifndef _BOOTMAN_INTERNAL_ 18 | #error This file can only be included within libcbm! 19 | #endif 20 | 21 | #include 22 | 23 | #include "bootloader.h" 24 | #include "bootman.h" 25 | #include "os-release.h" 26 | 27 | struct BootManager { 28 | char *kernel_dir; /** 15 | #include 16 | #include 17 | 18 | #include "bootman.h" 19 | #include "bootman_private.h" 20 | #include "config.h" 21 | #include "log.h" 22 | #include "nica/files.h" 23 | 24 | bool boot_manager_set_timeout_value(BootManager *self, int timeout) 25 | { 26 | autofree(FILE) *fp = NULL; 27 | autofree(char) *path = NULL; 28 | autofree(char) *dir = NULL; 29 | 30 | if (!self || !self->sysconfig) { 31 | return false; 32 | } 33 | 34 | dir = string_printf("%s%s", self->sysconfig->prefix, KERNEL_CONF_DIRECTORY); 35 | 36 | if (!nc_mkdir_p(dir, 00755)) { 37 | LOG_ERROR("Failed to create directory %s: %s", dir, strerror(errno)); 38 | return false; 39 | } 40 | 41 | path = string_printf("%s%s/timeout", self->sysconfig->prefix, KERNEL_CONF_DIRECTORY); 42 | 43 | if (timeout <= 0) { 44 | /* Nothing to be done here. */ 45 | if (!nc_file_exists(path)) { 46 | return true; 47 | } 48 | if (unlink(path) < 0) { 49 | LOG_ERROR("Unable to remove %s: %s", path, strerror(errno)); 50 | return false; 51 | } 52 | return true; 53 | } 54 | 55 | fp = fopen(path, "w"); 56 | if (!fp) { 57 | LOG_FATAL("Unable to open %s for writing: %s", path, strerror(errno)); 58 | return false; 59 | } 60 | 61 | if (fprintf(fp, "%d\n", timeout) < 0) { 62 | LOG_FATAL("Unable to set new timeout: %s", strerror(errno)); 63 | return false; 64 | } 65 | return true; 66 | } 67 | 68 | int boot_manager_get_timeout_value(BootManager *self) 69 | { 70 | autofree(FILE) *fp = NULL; 71 | autofree(char) *path = NULL; 72 | int t_val; 73 | 74 | if (!self || !self->sysconfig) { 75 | return false; 76 | } 77 | 78 | path = string_printf("%s%s/timeout", self->sysconfig->prefix, KERNEL_CONF_DIRECTORY); 79 | 80 | /* Default timeout being -1, i.e. don't use one */ 81 | if (!nc_file_exists(path)) { 82 | return -1; 83 | } 84 | 85 | fp = fopen(path, "r"); 86 | if (!fp) { 87 | LOG_FATAL("Unable to open %s for reading: %s", path, strerror(errno)); 88 | return -1; 89 | } 90 | 91 | if (fscanf(fp, "%d\n", &t_val) != 1) { 92 | LOG_ERROR("Failed to parse config file, defaulting to no timeout"); 93 | return -1; 94 | } 95 | 96 | return t_val; 97 | } 98 | 99 | /* 100 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 101 | * 102 | * Local variables: 103 | * c-basic-offset: 8 104 | * tab-width: 8 105 | * indent-tabs-mode: nil 106 | * End: 107 | * 108 | * vi: set shiftwidth=8 tabstop=8 expandtab: 109 | * :indentSize=8:tabSize=8:noTabs=true: 110 | */ 111 | -------------------------------------------------------------------------------- /src/cli/cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "cli.h" 20 | #include "config.h" 21 | #include "log.h" 22 | #include "nica/files.h" 23 | #include "util.h" 24 | 25 | struct cli_option { 26 | struct option opt; 27 | char *desc; 28 | }; 29 | 30 | #define OPTION(opt, req, flag, short_opt, desc) \ 31 | { {opt, req, flag, short_opt}, desc } \ 32 | 33 | static struct cli_option cli_opts[] = { 34 | OPTION("path", required_argument, 0, 'p', "Set the base path for boot management operations."), 35 | OPTION("image", no_argument, 0, 'i', "Force clr-boot-manager to run in image mode."), 36 | OPTION("no-efi-update", no_argument, 0, 'n', 37 | "Don't update efi vars when using shim-systemd backend."), 38 | OPTION(0, 0, 0, 0, NULL), 39 | }; 40 | 41 | void cli_print_default_args_help(void) 42 | { 43 | int opt_len = (sizeof(cli_opts) / sizeof(struct cli_option)) - 1; 44 | int larger = -1; 45 | const char *flags_mask = " -%c, --%s"; 46 | 47 | fprintf(stdout, "\nOptions:\n"); 48 | 49 | for (int i = 0; i < opt_len; i++) { 50 | struct cli_option curr = cli_opts[i]; 51 | char tmp[60] = {0}; 52 | int len; 53 | 54 | len = sprintf(tmp, flags_mask, curr.opt.val, curr.opt.name); 55 | if (len > larger) { 56 | larger = len; 57 | } 58 | } 59 | 60 | for (int i = 0; i < opt_len; i++) { 61 | struct cli_option curr = cli_opts[i]; 62 | char tmp[60] = {0}; 63 | int len; 64 | 65 | len = sprintf(tmp, flags_mask, curr.opt.val, curr.opt.name); 66 | fprintf(stdout, "%s%*s%s\n", tmp, (larger - len) + 2, "", curr.desc); 67 | } 68 | } 69 | 70 | bool cli_default_args_init(int *argc, char ***argv, char **root, bool *forced_image, 71 | bool *update_efi_vars) 72 | { 73 | int o_in = 0; 74 | int c; 75 | char *_root = NULL; 76 | int opt_len = sizeof(cli_opts) / sizeof(struct cli_option); 77 | struct option *default_opts; 78 | 79 | default_opts = alloca(sizeof(struct option) * (long unsigned int)opt_len); 80 | 81 | for (int i = 0; i < opt_len; i++) { 82 | default_opts[i] = cli_opts[i].opt; 83 | } 84 | 85 | /* We actually want to use getopt, so rewind one for getopt */; 86 | --(*argv); 87 | ++(*argc); 88 | 89 | if (!root) { 90 | return false; 91 | } 92 | 93 | /* Allow setting the root */ 94 | while (true) { 95 | c = getopt_long(*argc, *argv, "nip:", default_opts, &o_in); 96 | if (c == -1) { 97 | break; 98 | } 99 | switch (c) { 100 | case 0: 101 | case 'p': 102 | if (optarg) { 103 | if (_root) { 104 | free(_root); 105 | _root = NULL; 106 | } 107 | _root = strdup(optarg); 108 | } 109 | break; 110 | case 'i': 111 | if (forced_image) { 112 | *forced_image = true; 113 | } 114 | break; 115 | case 'n': 116 | if (update_efi_vars) { 117 | *update_efi_vars = false; 118 | } 119 | break; 120 | case '?': 121 | goto bail; 122 | break; 123 | default: 124 | abort(); 125 | } 126 | } 127 | *argc -= optind; 128 | 129 | if (_root) { 130 | *root = _root; 131 | } 132 | 133 | if (update_efi_vars && *update_efi_vars) { 134 | autofree(FILE) *f = NULL; 135 | autofree(char) *cfg_path = NULL; 136 | char *buf = NULL; 137 | size_t sn; 138 | ssize_t r = 0; 139 | 140 | cfg_path = string_printf("%s/%s/update_efi_vars", (*root != NULL) ? *root : "", 141 | KERNEL_CONF_DIRECTORY); 142 | CHECK_DBG_GOTO(!nc_file_exists(cfg_path), success, "No such file: %s", cfg_path); 143 | 144 | f = fopen(cfg_path, "r"); 145 | CHECK_ERR_RET_VAL(!f, false, "Could not open file: %s", cfg_path); 146 | 147 | while ((r = getline(&buf, &sn, f)) > 0) { 148 | if (!strncmp(buf, "no", 2) || !strncmp(buf, "false", 5)) { 149 | *update_efi_vars = false; 150 | break; 151 | } 152 | } 153 | } 154 | 155 | success: 156 | return true; 157 | bail: 158 | if (_root) { 159 | free(_root); 160 | } 161 | return false; 162 | } 163 | 164 | /* 165 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 166 | * 167 | * Local variables: 168 | * c-basic-offset: 8 169 | * tab-width: 8 170 | * indent-tabs-mode: nil 171 | * End: 172 | * 173 | * vi: set shiftwidth=8 tabstop=8 expandtab: 174 | * :indentSize=8:tabSize=8:noTabs=true: 175 | */ 176 | -------------------------------------------------------------------------------- /src/cli/cli.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | 16 | typedef bool (*subcommand_callback)(int argc, char **argv); 17 | 18 | typedef struct SubCommand { 19 | const char *name; 20 | const char *blurb; 21 | const char *usage; 22 | const char *help; 23 | subcommand_callback callback; 24 | bool requires_root; 25 | } SubCommand; 26 | 27 | bool cli_default_args_init(int *argc, char ***argv, char **root, bool *forced_image, 28 | bool *update_efi_vars); 29 | void cli_print_default_args_help(void); 30 | 31 | /* 32 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 33 | * 34 | * Local variables: 35 | * c-basic-offset: 8 36 | * tab-width: 8 37 | * indent-tabs-mode: nil 38 | * End: 39 | * 40 | * vi: set shiftwidth=8 tabstop=8 expandtab: 41 | * :indentSize=8:tabSize=8:noTabs=true: 42 | */ 43 | -------------------------------------------------------------------------------- /src/cli/ops/kernels.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "bootman.h" 20 | #include "cli.h" 21 | #include "config.h" 22 | #include "log.h" 23 | 24 | bool cbm_command_list_kernels(int argc, char **argv) 25 | { 26 | autofree(char) *root = NULL; 27 | autofree(BootManager) *manager = NULL; 28 | bool forced_image = false; 29 | char **kernels = NULL; 30 | bool update_efi_vars = true; 31 | 32 | if (!cli_default_args_init(&argc, &argv, &root, &forced_image, &update_efi_vars)) { 33 | return false; 34 | } 35 | 36 | manager = boot_manager_new(); 37 | if (!manager) { 38 | DECLARE_OOM(); 39 | return false; 40 | } 41 | 42 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 43 | 44 | if (root) { 45 | autofree(char) *realp = NULL; 46 | 47 | realp = realpath(root, NULL); 48 | if (!realp) { 49 | LOG_FATAL("Path specified does not exist: %s", root); 50 | return false; 51 | } 52 | /* Anything not / is image mode */ 53 | if (!streq(realp, "/")) { 54 | boot_manager_set_image_mode(manager, true); 55 | } else { 56 | boot_manager_set_image_mode(manager, forced_image); 57 | } 58 | 59 | /* CBM will check this again, we just needed to check for 60 | * image mode.. */ 61 | if (!boot_manager_set_prefix(manager, root)) { 62 | return false; 63 | } 64 | } else { 65 | boot_manager_set_image_mode(manager, forced_image); 66 | /* Default to "/", bail if it doesn't work. */ 67 | if (!boot_manager_set_prefix(manager, "/")) { 68 | return false; 69 | } 70 | } 71 | 72 | /* Let CBM take care of the rest */ 73 | kernels = boot_manager_list_kernels(manager); 74 | if (!kernels) { 75 | return false; 76 | } 77 | for (char **k = kernels; *k; k++) { 78 | printf("%s\n", *k); 79 | free(*k); 80 | } 81 | free(kernels); 82 | return true; 83 | } 84 | 85 | bool cbm_command_set_kernel(int argc, char **argv) 86 | { 87 | autofree(char) *root = NULL; 88 | autofree(BootManager) *manager = NULL; 89 | bool forced_image = false; 90 | char type[32] = { 0 }; 91 | char version[16] = { 0 }; 92 | int release = 0; 93 | Kernel kern = { 0 }; 94 | bool update_efi_vars = true; 95 | 96 | if (!cli_default_args_init(&argc, &argv, &root, &forced_image, &update_efi_vars)) { 97 | return false; 98 | } 99 | 100 | manager = boot_manager_new(); 101 | if (!manager) { 102 | DECLARE_OOM(); 103 | return false; 104 | } 105 | 106 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 107 | 108 | if (root) { 109 | autofree(char) *realp = NULL; 110 | 111 | realp = realpath(root, NULL); 112 | if (!realp) { 113 | LOG_FATAL("Path specified does not exist: %s", root); 114 | return false; 115 | } 116 | /* Anything not / is image mode */ 117 | if (!streq(realp, "/")) { 118 | boot_manager_set_image_mode(manager, true); 119 | } else { 120 | boot_manager_set_image_mode(manager, forced_image); 121 | } 122 | 123 | /* CBM will check this again, we just needed to check for 124 | * image mode.. */ 125 | if (!boot_manager_set_prefix(manager, root)) { 126 | return false; 127 | } 128 | } else { 129 | boot_manager_set_image_mode(manager, forced_image); 130 | /* Default to "/", bail if it doesn't work. */ 131 | if (!boot_manager_set_prefix(manager, "/")) { 132 | return false; 133 | } 134 | } 135 | 136 | if (argc != 1) { 137 | fprintf(stderr, 138 | "set-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n", 139 | KERNEL_NAMESPACE); 140 | return false; 141 | } 142 | 143 | if (sscanf(argv[optind], KERNEL_NAMESPACE ".%31[^.].%15[^-]-%d", type, version, &release) != 3) { 144 | fprintf(stderr, 145 | "set-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n", 146 | KERNEL_NAMESPACE); 147 | return false; 148 | } 149 | 150 | kern.meta.ktype = type; 151 | kern.meta.version = version; 152 | kern.meta.release = release; 153 | 154 | /* Let CBM take care of the rest */ 155 | if (!boot_manager_set_default_kernel(manager, &kern)) { 156 | return false; 157 | } 158 | return true; 159 | } 160 | 161 | bool cbm_command_remove_kernel(int argc, char **argv) 162 | { 163 | autofree(char) *root = NULL; 164 | autofree(BootManager) *manager = NULL; 165 | autofree(KernelArray) *kernels = NULL; 166 | bool forced_image = false; 167 | char type[32] = { 0 }; 168 | char version[16] = { 0 }; 169 | int release = 0; 170 | Kernel kern = { 0 }; 171 | bool update_efi_vars = true; 172 | 173 | if (!cli_default_args_init(&argc, &argv, &root, &forced_image, &update_efi_vars)) { 174 | return false; 175 | } 176 | 177 | manager = boot_manager_new(); 178 | if (!manager) { 179 | DECLARE_OOM(); 180 | return false; 181 | } 182 | 183 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 184 | 185 | if (root) { 186 | autofree(char) *realp = NULL; 187 | 188 | realp = realpath(root, NULL); 189 | if (!realp) { 190 | LOG_FATAL("Path specified does not exist: %s", root); 191 | return false; 192 | } 193 | /* Anything not / is image mode */ 194 | if (!streq(realp, "/")) { 195 | boot_manager_set_image_mode(manager, true); 196 | } else { 197 | boot_manager_set_image_mode(manager, forced_image); 198 | } 199 | 200 | /* CBM will check this again, we just needed to check for 201 | * image mode.. */ 202 | if (!boot_manager_set_prefix(manager, root)) { 203 | return false; 204 | } 205 | } else { 206 | boot_manager_set_image_mode(manager, forced_image); 207 | /* Default to "/", bail if it doesn't work. */ 208 | if (!boot_manager_set_prefix(manager, "/")) { 209 | return false; 210 | } 211 | } 212 | 213 | if (argc != 1) { 214 | fprintf(stderr, 215 | "remove-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n", 216 | KERNEL_NAMESPACE); 217 | return false; 218 | } 219 | 220 | if (sscanf(argv[optind], KERNEL_NAMESPACE ".%31[^.].%15[^-]-%d", type, version, &release) != 3) { 221 | fprintf(stderr, 222 | "remove-kernel takes a kernel ID of the form %s.TYPE.VERSION-RELEASE\n", 223 | KERNEL_NAMESPACE); 224 | return false; 225 | } 226 | 227 | kern.meta.ktype = type; 228 | kern.meta.version = version; 229 | kern.meta.release = release; 230 | 231 | /* Let CBM take care of the rest */ 232 | if (!boot_manager_remove_kernel_wrapper(manager, &kern)) { 233 | return false; 234 | } 235 | return true; 236 | } 237 | 238 | /* 239 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 240 | * 241 | * Local variables: 242 | * c-basic-offset: 8 243 | * tab-width: 8 244 | * indent-tabs-mode: nil 245 | * End: 246 | * 247 | * vi: set shiftwidth=8 tabstop=8 expandtab: 248 | * :indentSize=8:tabSize=8:noTabs=true: 249 | */ 250 | -------------------------------------------------------------------------------- /src/cli/ops/kernels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "cli.h" 15 | 16 | bool cbm_command_list_kernels(int argc, char **argv); 17 | bool cbm_command_set_kernel(int argc, char **argv); 18 | bool cbm_command_remove_kernel(int argc, char **argv); 19 | 20 | /* 21 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 22 | * 23 | * Local variables: 24 | * c-basic-offset: 8 25 | * tab-width: 8 26 | * indent-tabs-mode: nil 27 | * End: 28 | * 29 | * vi: set shiftwidth=8 tabstop=8 expandtab: 30 | * :indentSize=8:tabSize=8:noTabs=true: 31 | */ 32 | -------------------------------------------------------------------------------- /src/cli/ops/report_booted.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "bootman.h" 23 | #include "cli.h" 24 | #include "config.h" 25 | #include "files.h" 26 | #include "nica/files.h" 27 | #include "nica/util.h" 28 | #include "report_booted.h" 29 | 30 | bool cbm_command_report_booted(__cbm_unused__ int argc, __cbm_unused__ char **argv) 31 | { 32 | SystemKernel sys = { 0 }; 33 | struct utsname uts = { 0 }; 34 | const char *lib_dir = "/var/lib/kernel"; 35 | autofree(char) *boot_rep_path = NULL; 36 | 37 | /* Try to parse the currently running kernel */ 38 | if (uname(&uts) < 0) { 39 | fprintf(stderr, "uname() broken: %s\n", strerror(errno)); 40 | return false; 41 | } 42 | 43 | if (!cbm_parse_system_kernel(uts.release, &sys)) { 44 | fprintf(stderr, "Booting with unknown kernel: %s\n", uts.release); 45 | return false; 46 | } 47 | 48 | /* Disable syncs during boot ! */ 49 | cbm_set_sync_filesystems(false); 50 | 51 | if (!nc_file_exists(lib_dir)) { 52 | if (!nc_mkdir_p(lib_dir, 00755)) { 53 | fprintf(stderr, "Unable to mkdir_p: %s %s\n", lib_dir, strerror(errno)); 54 | return false; 55 | } 56 | } 57 | 58 | /* /var/lib/kernel/k_booted_4.4.0-120.lts - new */ 59 | boot_rep_path = 60 | string_printf("/var/lib/kernel/k_booted_%s-%d.%s", sys.version, sys.release, sys.ktype); 61 | 62 | /* Report ourselves to new path */ 63 | if (!file_set_text(boot_rep_path, "clr-boot-manager file\n")) { 64 | fprintf(stderr, "Failed to set kernel boot status: %s\n", strerror(errno)); 65 | return false; 66 | } 67 | 68 | /* Done */ 69 | return true; 70 | } 71 | 72 | /* 73 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 74 | * 75 | * Local variables: 76 | * c-basic-offset: 8 77 | * tab-width: 8 78 | * indent-tabs-mode: nil 79 | * End: 80 | * 81 | * vi: set shiftwidth=8 tabstop=8 expandtab: 82 | * :indentSize=8:tabSize=8:noTabs=true: 83 | */ 84 | -------------------------------------------------------------------------------- /src/cli/ops/report_booted.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "cli.h" 15 | 16 | bool cbm_command_report_booted(int argc, char **argv); 17 | 18 | /* 19 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 20 | * 21 | * Local variables: 22 | * c-basic-offset: 8 23 | * tab-width: 8 24 | * indent-tabs-mode: nil 25 | * End: 26 | * 27 | * vi: set shiftwidth=8 tabstop=8 expandtab: 28 | * :indentSize=8:tabSize=8:noTabs=true: 29 | */ 30 | -------------------------------------------------------------------------------- /src/cli/ops/timeout.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include "bootman.h" 17 | #include "cli.h" 18 | #include "update.h" 19 | 20 | static inline bool is_numeric(const char *str) 21 | { 22 | for (char *c = (char *)str; *c; c++) { 23 | if (!isdigit(*c)) { 24 | if (c == str && *c == '-') { 25 | continue; 26 | } 27 | return false; 28 | } 29 | } 30 | return true; 31 | } 32 | 33 | bool cbm_command_set_timeout(int argc, char **argv) 34 | { 35 | int n_val = -1; 36 | autofree(char) *root = NULL; 37 | autofree(BootManager) *manager = NULL; 38 | bool update_efi_vars = false; 39 | 40 | if (!cli_default_args_init(&argc, &argv, &root, NULL, &update_efi_vars)) { 41 | return false; 42 | } 43 | 44 | manager = boot_manager_new(); 45 | if (!manager) { 46 | DECLARE_OOM(); 47 | return false; 48 | } 49 | 50 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 51 | 52 | /* Use specified root if required */ 53 | if (root) { 54 | if (!boot_manager_set_prefix(manager, root)) { 55 | return false; 56 | } 57 | } else { 58 | /* Default to "/", bail if it doesn't work. */ 59 | if (!boot_manager_set_prefix(manager, "/")) { 60 | return false; 61 | } 62 | } 63 | 64 | if (argc != 1) { 65 | fprintf(stderr, "set-timeout takes one integer parameter\n"); 66 | return false; 67 | } 68 | 69 | if (sscanf(argv[optind], "%d", &n_val) < 0) { 70 | fprintf(stderr, "Erroneous input. Please provide an integer value.\n"); 71 | return false; 72 | } 73 | 74 | if (!is_numeric(argv[optind])) { 75 | fprintf(stderr, "Please provide a valid numeric value.\n"); 76 | return false; 77 | } 78 | 79 | if (n_val < -1) { 80 | fprintf(stderr, 81 | "Value of '%d' is incorrect. Use 0 if you mean to disable boot timeout.\n", 82 | n_val); 83 | return false; 84 | } 85 | 86 | if (!boot_manager_set_timeout_value(manager, n_val)) { 87 | fprintf(stderr, "Failed to update timeout\n"); 88 | return false; 89 | } 90 | if (n_val <= 0) { 91 | fprintf(stdout, "Timeout has been removed\n"); 92 | } else { 93 | fprintf(stdout, "New timeout value is: %d\n", n_val); 94 | } 95 | 96 | return cbm_command_update_do(manager, root, false); 97 | } 98 | 99 | bool cbm_command_get_timeout(int argc, char **argv) 100 | { 101 | autofree(char) *root = NULL; 102 | autofree(BootManager) *manager = NULL; 103 | bool update_efi_vars = false; 104 | 105 | cli_default_args_init(&argc, &argv, &root, NULL, &update_efi_vars); 106 | 107 | manager = boot_manager_new(); 108 | if (!manager) { 109 | DECLARE_OOM(); 110 | return false; 111 | } 112 | 113 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 114 | 115 | /* Use specified root if required */ 116 | if (root) { 117 | if (!boot_manager_set_prefix(manager, root)) { 118 | return false; 119 | } 120 | } else { 121 | /* Default to "/", bail if it doesn't work. */ 122 | if (!boot_manager_set_prefix(manager, "/")) { 123 | return false; 124 | } 125 | } 126 | 127 | if (argc != 0) { 128 | fprintf(stderr, "get-timeout does not take any parameters\n"); 129 | return false; 130 | } 131 | 132 | int tval = boot_manager_get_timeout_value(manager); 133 | if (tval <= 0) { 134 | fprintf(stdout, "No timeout is currently configured\n"); 135 | } else { 136 | fprintf(stdout, "Timeout value: %d seconds\n", tval); 137 | } 138 | return true; 139 | } 140 | 141 | /* 142 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 143 | * 144 | * Local variables: 145 | * c-basic-offset: 8 146 | * tab-width: 8 147 | * indent-tabs-mode: nil 148 | * End: 149 | * 150 | * vi: set shiftwidth=8 tabstop=8 expandtab: 151 | * :indentSize=8:tabSize=8:noTabs=true: 152 | */ 153 | -------------------------------------------------------------------------------- /src/cli/ops/timeout.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "cli.h" 15 | 16 | bool cbm_command_set_timeout(int argc, char **argv); 17 | bool cbm_command_get_timeout(int argc, char **argv); 18 | 19 | /* 20 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 21 | * 22 | * Local variables: 23 | * c-basic-offset: 8 24 | * tab-width: 8 25 | * indent-tabs-mode: nil 26 | * End: 27 | * 28 | * vi: set shiftwidth=8 tabstop=8 expandtab: 29 | * :indentSize=8:tabSize=8:noTabs=true: 30 | */ 31 | -------------------------------------------------------------------------------- /src/cli/ops/update.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "bootman.h" 20 | #include "cli.h" 21 | #include "log.h" 22 | #include "nica/files.h" 23 | #include "update.h" 24 | 25 | bool cbm_command_update(int argc, char **argv) 26 | { 27 | autofree(char) *root = NULL; 28 | autofree(BootManager) *manager = NULL; 29 | bool forced_image = false; 30 | bool update_efi_vars = true; 31 | 32 | if (!cli_default_args_init(&argc, &argv, &root, &forced_image, &update_efi_vars)) { 33 | return false; 34 | } 35 | 36 | manager = boot_manager_new(); 37 | if (!manager) { 38 | DECLARE_OOM(); 39 | return false; 40 | } 41 | 42 | boot_manager_set_update_efi_vars(manager, update_efi_vars); 43 | 44 | return cbm_command_update_do(manager, root, forced_image); 45 | } 46 | 47 | bool cbm_command_update_do(BootManager *manager, char *root, bool forced_image) 48 | { 49 | if (!boot_manager_detect_kernel_dir(root)) { 50 | fprintf(stderr, "No kernels detected on system to update\n"); 51 | return true; 52 | } 53 | 54 | if (root) { 55 | autofree(char) *realp = NULL; 56 | 57 | realp = realpath(root, NULL); 58 | if (!realp) { 59 | LOG_FATAL("Path specified does not exist: %s", root); 60 | return false; 61 | } 62 | /* Anything not / is image mode */ 63 | if (!streq(realp, "/")) { 64 | boot_manager_set_image_mode(manager, true); 65 | } else { 66 | boot_manager_set_image_mode(manager, forced_image); 67 | } 68 | 69 | /* CBM will check this again, we just needed to check for 70 | * image mode.. */ 71 | if (!boot_manager_set_prefix(manager, root)) { 72 | return false; 73 | } 74 | } else { 75 | boot_manager_set_image_mode(manager, forced_image); 76 | /* Default to "/", bail if it doesn't work. */ 77 | if (!boot_manager_set_prefix(manager, "/")) { 78 | return false; 79 | } 80 | } 81 | /* Grab the available freestanding initrd */ 82 | if (!boot_manager_enumerate_initrds_freestanding(manager)) { 83 | return false; 84 | } 85 | 86 | /* Let CBM take care of the rest */ 87 | return boot_manager_update(manager); 88 | } 89 | 90 | /* 91 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 92 | * 93 | * Local variables: 94 | * c-basic-offset: 8 95 | * tab-width: 8 96 | * indent-tabs-mode: nil 97 | * End: 98 | * 99 | * vi: set shiftwidth=8 tabstop=8 expandtab: 100 | * :indentSize=8:tabSize=8:noTabs=true: 101 | */ 102 | -------------------------------------------------------------------------------- /src/cli/ops/update.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "bootman.h" 15 | #include "cli.h" 16 | 17 | bool cbm_command_update(int argc, char **argv); 18 | bool cbm_command_update_do(BootManager *manager, char *root, bool forced_image); 19 | 20 | /* 21 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 22 | * 23 | * Local variables: 24 | * c-basic-offset: 8 25 | * tab-width: 8 26 | * indent-tabs-mode: nil 27 | * End: 28 | * 29 | * vi: set shiftwidth=8 tabstop=8 expandtab: 30 | * :indentSize=8:tabSize=8:noTabs=true: 31 | */ 32 | -------------------------------------------------------------------------------- /src/lib/blkid_stub.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #include "blkid_stub.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | /** 20 | * Ensure we check here for the blkid device being correct. 21 | */ 22 | static int cbm_blkid_devno_to_wholedisk_wrapped(dev_t dev, char *diskname, size_t len, 23 | dev_t *diskdevno) 24 | { 25 | if (major(dev) == 0) { 26 | return -1; 27 | } 28 | return blkid_devno_to_wholedisk(dev, diskname, len, diskdevno); 29 | } 30 | 31 | /** 32 | * Default blkid ops vtable passes through to libblkid itself 33 | */ 34 | static CbmBlkidOps default_blkid_ops = { 35 | .probe_new_from_filename = blkid_new_probe_from_filename, 36 | .probe_enable_superblocks = blkid_probe_enable_superblocks, 37 | .probe_set_superblocks_flags = blkid_probe_set_superblocks_flags, 38 | .probe_enable_partitions = blkid_probe_enable_partitions, 39 | .probe_set_partitions_flags = blkid_probe_set_partitions_flags, 40 | .probe_get_wholedisk_devno = blkid_probe_get_wholedisk_devno, 41 | .probe_lookup_value = blkid_probe_lookup_value, 42 | .do_safeprobe = blkid_do_safeprobe, 43 | .free_probe = blkid_free_probe, 44 | 45 | /* Partition functions */ 46 | .probe_get_partitions = blkid_probe_get_partitions, 47 | .partlist_numof_partitions = blkid_partlist_numof_partitions, 48 | .partlist_get_partition = blkid_partlist_get_partition, 49 | .partition_get_flags = blkid_partition_get_flags, 50 | .partition_get_uuid = blkid_partition_get_uuid, 51 | 52 | /* Partition table functions */ 53 | .partlist_get_table = blkid_partlist_get_table, 54 | .parttable_get_type = blkid_parttable_get_type, 55 | 56 | /* Misc */ 57 | .devno_to_wholedisk = cbm_blkid_devno_to_wholedisk_wrapped, 58 | .devno_to_devname = blkid_devno_to_devname, 59 | }; 60 | 61 | /** 62 | * Pointer to the currently active vtable 63 | */ 64 | static CbmBlkidOps *blkid_ops = &default_blkid_ops; 65 | 66 | void cbm_blkid_reset_vtable(void) 67 | { 68 | blkid_ops = &default_blkid_ops; 69 | } 70 | 71 | void cbm_blkid_set_vtable(CbmBlkidOps *ops) 72 | { 73 | if (!ops) { 74 | cbm_blkid_reset_vtable(); 75 | } else { 76 | blkid_ops = ops; 77 | } 78 | /* Ensure the vtable is valid at this point. */ 79 | assert(blkid_ops->probe_new_from_filename != NULL); 80 | assert(blkid_ops->probe_enable_superblocks != NULL); 81 | assert(blkid_ops->probe_set_superblocks_flags != NULL); 82 | assert(blkid_ops->probe_enable_partitions != NULL); 83 | assert(blkid_ops->probe_set_partitions_flags != NULL); 84 | assert(blkid_ops->probe_get_wholedisk_devno != NULL); 85 | assert(blkid_ops->probe_lookup_value != NULL); 86 | assert(blkid_ops->do_safeprobe != NULL); 87 | assert(blkid_ops->free_probe != NULL); 88 | 89 | /* partition functions */ 90 | assert(blkid_ops->probe_get_partitions != NULL); 91 | assert(blkid_ops->partlist_numof_partitions != NULL); 92 | assert(blkid_ops->partlist_get_partition != NULL); 93 | assert(blkid_ops->partition_get_flags != NULL); 94 | assert(blkid_ops->partition_get_uuid != NULL); 95 | 96 | /* partition table functions */ 97 | assert(blkid_ops->partlist_get_table != NULL); 98 | assert(blkid_ops->parttable_get_type != NULL); 99 | 100 | /* misc */ 101 | assert(blkid_ops->devno_to_wholedisk != NULL); 102 | assert(blkid_ops->devno_to_devname != NULL); 103 | } 104 | 105 | /** 106 | * Probe functions 107 | */ 108 | blkid_probe cbm_blkid_new_probe_from_filename(const char *filename) 109 | { 110 | return blkid_ops->probe_new_from_filename(filename); 111 | } 112 | 113 | int cbm_blkid_probe_enable_superblocks(blkid_probe pr, int enable) 114 | { 115 | return blkid_ops->probe_enable_superblocks(pr, enable); 116 | } 117 | 118 | int cbm_blkid_probe_set_superblocks_flags(blkid_probe pr, int flags) 119 | { 120 | return blkid_ops->probe_set_superblocks_flags(pr, flags); 121 | } 122 | 123 | int cbm_blkid_probe_enable_partitions(blkid_probe pr, int enable) 124 | { 125 | return blkid_ops->probe_enable_partitions(pr, enable); 126 | } 127 | 128 | int cbm_blkid_probe_set_partitions_flags(blkid_probe pr, int flags) 129 | { 130 | return blkid_ops->probe_set_partitions_flags(pr, flags); 131 | } 132 | 133 | int cbm_blkid_do_safeprobe(blkid_probe pr) 134 | { 135 | return blkid_ops->do_safeprobe(pr); 136 | } 137 | 138 | int cbm_blkid_probe_lookup_value(blkid_probe pr, const char *name, const char **data, size_t *len) 139 | { 140 | return blkid_ops->probe_lookup_value(pr, name, data, len); 141 | } 142 | 143 | void cbm_blkid_free_probe(blkid_probe pr) 144 | { 145 | blkid_ops->free_probe(pr); 146 | } 147 | 148 | dev_t cbm_probe_get_wholedisk_devno(blkid_probe pr) 149 | { 150 | return blkid_ops->probe_get_wholedisk_devno(pr); 151 | } 152 | 153 | /** 154 | * Partition functions 155 | */ 156 | blkid_partlist cbm_blkid_probe_get_partitions(blkid_probe pr) 157 | { 158 | return blkid_ops->probe_get_partitions(pr); 159 | } 160 | 161 | int cbm_blkid_partlist_numof_partitions(blkid_partlist ls) 162 | { 163 | if (!ls) { 164 | return 0; 165 | } 166 | return blkid_ops->partlist_numof_partitions(ls); 167 | } 168 | 169 | blkid_partition cbm_blkid_partlist_get_partition(blkid_partlist ls, int n) 170 | { 171 | return blkid_ops->partlist_get_partition(ls, n); 172 | } 173 | 174 | unsigned long long cbm_blkid_partition_get_flags(blkid_partition par) 175 | { 176 | return blkid_ops->partition_get_flags(par); 177 | } 178 | 179 | const char *cbm_blkid_partition_get_uuid(blkid_partition par) 180 | { 181 | return blkid_ops->partition_get_uuid(par); 182 | } 183 | 184 | /** 185 | * Partition table related wrappers 186 | */ 187 | blkid_parttable cbm_blkid_partlist_get_table(blkid_partlist ls) 188 | { 189 | return blkid_ops->partlist_get_table(ls); 190 | } 191 | 192 | const char *cbm_blkid_parttable_get_type(blkid_parttable tab) 193 | { 194 | return blkid_ops->parttable_get_type(tab); 195 | } 196 | 197 | /** 198 | * Misc functions 199 | */ 200 | int cbm_blkid_devno_to_wholedisk(dev_t dev, char *diskname, size_t len, dev_t *diskdevno) 201 | { 202 | return blkid_ops->devno_to_wholedisk(dev, diskname, len, diskdevno); 203 | } 204 | 205 | char *cbm_blkid_devno_to_devname(dev_t dev) 206 | { 207 | return blkid_ops->devno_to_devname(dev); 208 | } 209 | 210 | /* 211 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 212 | * 213 | * Local variables: 214 | * c-basic-offset: 8 215 | * tab-width: 8 216 | * indent-tabs-mode: nil 217 | * End: 218 | * 219 | * vi: set shiftwidth=8 tabstop=8 expandtab: 220 | * :indentSize=8:tabSize=8:noTabs=true: 221 | */ 222 | -------------------------------------------------------------------------------- /src/lib/blkid_stub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | #include 16 | 17 | /** 18 | * Defines the vtable used for all blkid operations within clr-boot-manager. 19 | * The default internal vtable will pass through all operations to libblkid. 20 | */ 21 | typedef struct CbmBlkidOps { 22 | /* Probe functions */ 23 | blkid_probe (*probe_new_from_filename)(const char *filename); 24 | int (*probe_enable_superblocks)(blkid_probe pr, int enable); 25 | int (*probe_set_superblocks_flags)(blkid_probe pr, int flags); 26 | int (*probe_enable_partitions)(blkid_probe pr, int enable); 27 | int (*probe_set_partitions_flags)(blkid_probe pr, int flags); 28 | int (*probe_lookup_value)(blkid_probe pr, const char *name, const char **data, size_t *len); 29 | int (*do_safeprobe)(blkid_probe pr); 30 | void (*free_probe)(blkid_probe pr); 31 | dev_t (*probe_get_wholedisk_devno)(blkid_probe pr); 32 | 33 | /* Partition functions */ 34 | blkid_partlist (*probe_get_partitions)(blkid_probe pr); 35 | int (*partlist_numof_partitions)(blkid_partlist ls); 36 | blkid_partition (*partlist_get_partition)(blkid_partlist ls, int n); 37 | unsigned long long (*partition_get_flags)(blkid_partition par); 38 | const char *(*partition_get_uuid)(blkid_partition par); 39 | 40 | /* Partition table functions */ 41 | blkid_parttable (*partlist_get_table)(blkid_partlist ls); 42 | const char *(*parttable_get_type)(blkid_parttable tab); 43 | 44 | /* Misc functions */ 45 | int (*devno_to_wholedisk)(dev_t dev, char *diskname, size_t len, dev_t *diskdevno); 46 | char *(*devno_to_devname)(dev_t dev); 47 | } CbmBlkidOps; 48 | 49 | /** 50 | * Define an empty blkid_probe for testing 51 | */ 52 | #define CBM_BLKID_PROBE_NULL ((blkid_probe)0) 53 | 54 | /** 55 | * Define a "set" blkid_probe for testing 56 | */ 57 | #define CBM_BLKID_PROBE_SET ((blkid_probe)1) 58 | 59 | /** 60 | * Define an empty blkid_partlist for testing 61 | */ 62 | #define CBM_BLKID_PARTLIST_NULL ((blkid_partlist)0) 63 | 64 | /** 65 | * Define a "set" blkid_partlist for testing 66 | */ 67 | #define CBM_BLKID_PARTLIST_SET ((blkid_partlist)1) 68 | 69 | /** 70 | * Define an empty blkid_partition for testing 71 | */ 72 | #define CBM_BLKID_PARTITION_NULL ((blkid_partition)0) 73 | 74 | /** 75 | * Define a "set" blkid_partition for testing 76 | */ 77 | #define CBM_BLKID_PARTITION_SET ((blkid_partition)1) 78 | 79 | /** 80 | * Define a "set" blkid_parttable for testing 81 | */ 82 | #define CBM_BLKID_PARTTABLE_SET ((blkid_parttable)1) 83 | 84 | /** 85 | * Define an empty blkid_parttable for testing 86 | */ 87 | #define CBM_BLKID_PARTTABLE_NULL ((blkid_parttable)0) 88 | 89 | /** 90 | * Reset the blkid vtable 91 | */ 92 | void cbm_blkid_reset_vtable(void); 93 | 94 | /** 95 | * Set the vfunc table used for all blkid operations within clr-boot-manager 96 | * 97 | * @note Passing null has the same effect as calling cbm_blkid_reset 98 | * The vtable will be checked to ensure that it is valid at this point, so 99 | * only call this when the vtable is fully populated. 100 | */ 101 | void cbm_blkid_set_vtable(CbmBlkidOps *ops); 102 | 103 | /** 104 | * Probe related wrappers 105 | */ 106 | blkid_probe cbm_blkid_new_probe_from_filename(const char *filename); 107 | int cbm_blkid_probe_enable_superblocks(blkid_probe pr, int enable); 108 | int cbm_blkid_probe_set_superblocks_flags(blkid_probe pr, int flags); 109 | int cbm_blkid_probe_enable_partitions(blkid_probe pr, int enable); 110 | int cbm_blkid_probe_set_partitions_flags(blkid_probe pr, int flags); 111 | int cbm_blkid_do_safeprobe(blkid_probe pr); 112 | int cbm_blkid_probe_lookup_value(blkid_probe pr, const char *name, const char **data, size_t *len); 113 | void cbm_blkid_free_probe(blkid_probe pr); 114 | dev_t cbm_probe_get_wholedisk_devno(blkid_probe pr); 115 | 116 | /** 117 | * Partition related wrappers 118 | */ 119 | blkid_partlist cbm_blkid_probe_get_partitions(blkid_probe pr); 120 | int cbm_blkid_partlist_numof_partitions(blkid_partlist ls); 121 | blkid_partition cbm_blkid_partlist_get_partition(blkid_partlist ls, int n); 122 | unsigned long long cbm_blkid_partition_get_flags(blkid_partition par); 123 | const char *cbm_blkid_partition_get_uuid(blkid_partition par); 124 | 125 | /** 126 | * Partition table related wrappers 127 | */ 128 | blkid_parttable cbm_blkid_partlist_get_table(blkid_partlist ls); 129 | const char *cbm_blkid_parttable_get_type(blkid_parttable tab); 130 | 131 | /** 132 | * Misc related wrappers 133 | */ 134 | int cbm_blkid_devno_to_wholedisk(dev_t dev, char *diskname, size_t len, dev_t *diskdevno); 135 | char *cbm_blkid_devno_to_devname(dev_t dev); 136 | 137 | /* 138 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 139 | * 140 | * Local variables: 141 | * c-basic-offset: 8 142 | * tab-width: 8 143 | * indent-tabs-mode: nil 144 | * End: 145 | * 146 | * vi: set shiftwidth=8 tabstop=8 expandtab: 147 | * :indentSize=8:tabSize=8:noTabs=true: 148 | */ 149 | -------------------------------------------------------------------------------- /src/lib/bootvar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #include 13 | 14 | #define EBOOT_VAR_ERR 1 /* general error */ 15 | #define EBOOT_VAR_NOSUP 127 /* EFI vars not supported */ 16 | 17 | int bootvar_init(void); 18 | void bootvar_destroy(void); 19 | int bootvar_create(const char *, const char *, char *, size_t); 20 | int bootvar_has_boot_rec(const char *, const char *); 21 | 22 | /* vim: set nosi noai cin ts=8 sw=8 et tw=80: */ 23 | -------------------------------------------------------------------------------- /src/lib/cmdline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include 17 | 18 | /** 19 | * Parse all user & cmdline files within the root prefix, and merge them 20 | * into a single cmdline "entry". 21 | * This is then combined with the final cmdline in the bootloaders 22 | * to allow local overrides and additions. 23 | * 24 | * The file may contain new lines, which are skipped. Additionally, the '#' 25 | * character is treated as a comment and will also be skipped. 26 | */ 27 | char *cbm_parse_cmdline_files(const char *root); 28 | 29 | /** 30 | * Parse a single cmdline, named cmdline file fully. 31 | */ 32 | char *cbm_parse_cmdline_file(const char *file); 33 | 34 | /** 35 | * Modify buffer using cmdline removal configuration to blacklist content. 36 | */ 37 | void cbm_parse_cmdline_removal_files_directory(const char *root, char *buffer); 38 | 39 | /* 40 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 41 | * 42 | * Local variables: 43 | * c-basic-offset: 8 44 | * tab-width: 8 45 | * indent-tabs-mode: nil 46 | * End: 47 | * 48 | * vi: set shiftwidth=8 tabstop=8 expandtab: 49 | * :indentSize=8:tabSize=8:noTabs=true: 50 | */ 51 | -------------------------------------------------------------------------------- /src/lib/files.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "util.h" 21 | 22 | typedef FILE FILE_MNT; 23 | 24 | DEF_AUTOFREE(FILE_MNT, endmntent) 25 | 26 | /** 27 | * Used to track an mmap()'d file's lifecycle. Never allocate one of these. 28 | * Instead, initialise a CbmMappedFile as: 29 | * 30 | * autofree(CbmMappedFile) *file = CBM_MAPPED_FILE_INIT; 31 | * 32 | * This will ensure it is always cleaned up on scope-exit. There is no allocation 33 | * here, this is a pointer to a newly referenced stack object. 34 | */ 35 | typedef struct CbmMappedFile { 36 | int fd; /**< File descriptor for the mapped file */ 37 | char *buffer; /**< Pointer to the mmap()'d contents */ 38 | size_t length; /**< Length of the mmap()'d file (see fstat) */ 39 | } CbmMappedFile; 40 | 41 | /** 42 | * Return the UEFI device that is used for booting (/boot) 43 | * 44 | * @return a newly allocated string, or NULL on error 45 | */ 46 | char *get_boot_device(void); 47 | 48 | /** 49 | * Get the parent disk of a given device 50 | */ 51 | char *get_parent_disk(char *path); 52 | 53 | /** 54 | * Return the partition's index number for the specified partiton devnode 55 | * 56 | * This must be on a GPT disk 57 | */ 58 | int get_partition_index(const char *path, const char *devnode); 59 | 60 | /** 61 | * Return the device for the legacy boot partition on the same 62 | * disk as the specified path 63 | * 64 | * This must be on a GPT disk 65 | */ 66 | char *get_legacy_boot_device(char *path); 67 | 68 | /** 69 | * Determine if the files match in content by comparing 70 | * their checksums 71 | */ 72 | bool cbm_files_match(const char *p1, const char *p2); 73 | 74 | /** 75 | * Return the parent path for a given file 76 | * 77 | * @note This is an allocated string, and must be freed by the caller 78 | * @param p Path to file 79 | * @return a newly allocated string 80 | */ 81 | char *cbm_get_file_parent(const char *p); 82 | 83 | /** 84 | * Quick utility function to write small text files 85 | * 86 | * @note This will _always_ overwrite an existing file 87 | * 88 | * @param path Path of the file to be written 89 | * @param text Contents of the new file 90 | * 91 | * @return True if this succeeded 92 | */ 93 | bool file_set_text(const char *path, char *text); 94 | 95 | /** 96 | * Quick utility for reading very small files into a string 97 | * 98 | * @param path Path of the file to be read 99 | * @param text Pointer to store newly allocated string 100 | * 101 | * @return True if this succeeded, otherwise no allocation is performed 102 | */ 103 | bool file_get_text(const char *path, char **out_buf); 104 | 105 | /** 106 | * Simple utility to copy path @src to path @dst, with mode @mode 107 | * 108 | * @note This will truncate the target if it exists, and does 109 | * not preserve stat information (As we're interested in copying 110 | * to an ESP only) 111 | * 112 | * Note that the implementation uses sendfile() for performance reasons. 113 | * 114 | * @param src Path to the source file 115 | * @param dst Path to the destination file 116 | * @param mode Mode of the new file when creating 117 | * 118 | * @return True if this succeeded 119 | */ 120 | bool copy_file(const char *src, const char *dst, mode_t mode); 121 | 122 | /** 123 | * Wrapper around copy_file to ensure an atomic update of files. This requires 124 | * that a new file first be written with a new unique name, and only when this 125 | * has happened, and is sync()'d, we remove the target path if it exists, 126 | * renaming our newly copied file to match the originally intended filename. 127 | * 128 | * This is designed to make the file replacement operation as atomic as 129 | * possible. 130 | */ 131 | bool copy_file_atomic(const char *src, const char *dst, mode_t mode); 132 | 133 | /** 134 | * Attempt to determine if the given path is actually mounted or not 135 | * 136 | * @param path Path to test is mounted or not 137 | */ 138 | bool cbm_is_mounted(const char *path); 139 | 140 | /** 141 | * Determine the mountpoint for the given device 142 | */ 143 | char *cbm_get_mountpoint_for_device(const char *device); 144 | 145 | /** 146 | * Determine the device for the given mountpoint 147 | * 148 | * @param mount Mount point to get the device for 149 | * @return Device path for the mount point, or NULL if none was found. 150 | */ 151 | char *cbm_get_device_for_mountpoint(const char *mount); 152 | 153 | /** 154 | * Determine whether the system is booted using UEFI 155 | */ 156 | bool cbm_system_has_uefi(void); 157 | 158 | /** 159 | * Override the default syncing behaviour. 160 | */ 161 | void cbm_set_sync_filesystems(bool should_sync); 162 | 163 | /** 164 | * Sync filesystem if should_sync is set 165 | * If not set, then this is a no-op 166 | */ 167 | void cbm_sync(void); 168 | 169 | /** 170 | * Close a previously mapped file 171 | */ 172 | void cbm_mapped_file_close(CbmMappedFile *file); 173 | 174 | /** 175 | * Open the given CbmMappedFile to path and mmap the contents 176 | */ 177 | bool cbm_mapped_file_open(const char *path, CbmMappedFile *file); 178 | 179 | /** 180 | * Cananolize @path and compare with @resolved. Returns true case paths are the same, 181 | * returns false otherwise. 182 | */ 183 | bool cbm_path_check(const char *path, const char *resolved); 184 | 185 | /** 186 | * Check if @path is a directory and if it's empty. Returns true case it exists and 187 | * contains files/directories, returns false otherwise. 188 | */ 189 | bool cbm_is_dir_empty(const char *path); 190 | 191 | /** 192 | * Check if @path exists and if it's empty. 193 | */ 194 | bool cbm_file_has_content(char *path); 195 | 196 | /** 197 | * Ensure a stack pointer vs a heap pointer, to save on copies 198 | */ 199 | #define CBM_MAPPED_FILE_INIT &(CbmMappedFile){ 0 }; 200 | 201 | /** 202 | * Handy macro 203 | */ 204 | DEF_AUTOFREE(CbmMappedFile, cbm_mapped_file_close) 205 | 206 | /* 207 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 208 | * 209 | * Local variables: 210 | * c-basic-offset: 8 211 | * tab-width: 8 212 | * indent-tabs-mode: nil 213 | * End: 214 | * 215 | * vi: set shiftwidth=8 tabstop=8 expandtab: 216 | * :indentSize=8:tabSize=8:noTabs=true: 217 | */ 218 | -------------------------------------------------------------------------------- /src/lib/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "log.h" 19 | #include "nica/util.h" 20 | 21 | static FILE *log_file = NULL; 22 | static CbmLogLevel min_log_level; 23 | 24 | #define PACKAGE_NAME_SHORT "cbm" 25 | 26 | static const char *log_str_table[] = {[CBM_LOG_DEBUG] = "DEBUG", [CBM_LOG_INFO] = "INFO", 27 | [CBM_LOG_SUCCESS] = "SUCCESS", [CBM_LOG_ERROR] = "ERROR", 28 | [CBM_LOG_WARNING] = "WARNING", [CBM_LOG_FATAL] = "FATAL" }; 29 | 30 | void cbm_log_init(FILE *log) 31 | { 32 | const char *env_level = NULL; 33 | log_file = log; 34 | unsigned int nlog_level = CBM_LOG_ERROR; 35 | 36 | env_level = getenv("CBM_DEBUG"); 37 | if (env_level) { 38 | /* =1 becomes 0 */ 39 | nlog_level = ((unsigned int)atoi(env_level)) - 1; 40 | } 41 | if (nlog_level >= CBM_LOG_MAX) { 42 | nlog_level = CBM_LOG_FATAL; 43 | } 44 | min_log_level = nlog_level; 45 | } 46 | 47 | /** 48 | * Ensure we're always at least initialised with stderr 49 | */ 50 | __attribute__((constructor)) static void cbm_log_first_init(void) 51 | { 52 | cbm_log_init(stderr); 53 | } 54 | 55 | static inline const char *cbm_log_level_str(CbmLogLevel l) 56 | { 57 | if (l <= CBM_LOG_FATAL) { 58 | return log_str_table[l]; 59 | } 60 | return "unknown"; 61 | } 62 | 63 | void cbm_log(CbmLogLevel level, const char *filename, int lineno, const char *format, ...) 64 | { 65 | const char *displ = NULL; 66 | va_list vargs; 67 | autofree(char) *rend = NULL; 68 | 69 | /* Respect minimum log level */ 70 | if (level < min_log_level) { 71 | return; 72 | } 73 | 74 | displ = cbm_log_level_str(level); 75 | 76 | va_start(vargs, format); 77 | 78 | if (vasprintf(&rend, format, vargs) < 0) { 79 | fputs("[FATAL] " PACKAGE_NAME_SHORT ": Cannot log to stream", log_file); 80 | goto clean_args; 81 | } 82 | 83 | if (fprintf(log_file, 84 | "[%s] %s (%s:L%d): %s\n", 85 | displ, 86 | PACKAGE_NAME_SHORT, 87 | filename, 88 | lineno, 89 | rend) < 0) { 90 | /* Forcibly fall back to stderr with the error */ 91 | fputs("[FATAL] " PACKAGE_NAME_SHORT ": Cannot log to stream", stderr); 92 | goto clean_args; 93 | } 94 | 95 | clean_args: 96 | va_end(vargs); 97 | } 98 | 99 | /* 100 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 101 | * 102 | * Local variables: 103 | * c-basic-offset: 8 104 | * tab-width: 8 105 | * indent-tabs-mode: nil 106 | * End: 107 | * 108 | * vi: set shiftwidth=8 tabstop=8 expandtab: 109 | * :indentSize=8:tabSize=8:noTabs=true: 110 | */ 111 | -------------------------------------------------------------------------------- /src/lib/log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include 17 | 18 | typedef enum { 19 | CBM_LOG_DEBUG = 0, 20 | CBM_LOG_INFO, 21 | CBM_LOG_SUCCESS, 22 | CBM_LOG_ERROR, 23 | CBM_LOG_WARNING, 24 | CBM_LOG_FATAL, 25 | CBM_LOG_MAX /* Unused */ 26 | } CbmLogLevel; 27 | 28 | /** 29 | * Re-initialise the logging functionality, to use a different file descriptor 30 | * for logging 31 | * 32 | * @note This is already called once with stderr as the log file 33 | */ 34 | void cbm_log_init(FILE *log); 35 | 36 | /** 37 | * Log current status/error to stderr. It is recommended to use the 38 | * macros to achieve this. 39 | */ 40 | void cbm_log(CbmLogLevel level, const char *file, int line, const char *format, ...) 41 | __attribute__((format(printf, 4, 5))); 42 | 43 | /** 44 | * Log a simple debug message 45 | */ 46 | #define LOG_DEBUG(...) (cbm_log(CBM_LOG_DEBUG, __FILE__, __LINE__, __VA_ARGS__)) 47 | 48 | /** 49 | * Log an informational message 50 | */ 51 | #define LOG_INFO(...) (cbm_log(CBM_LOG_INFO, __FILE__, __LINE__, __VA_ARGS__)) 52 | 53 | /** 54 | * Log success 55 | */ 56 | #define LOG_SUCCESS(...) (cbm_log(CBM_LOG_SUCCESS, __FILE__, __LINE__, __VA_ARGS__)) 57 | 58 | /** 59 | * Log a non-fatal error 60 | */ 61 | #define LOG_ERROR(...) (cbm_log(CBM_LOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)) 62 | 63 | /** 64 | * Log a fatal error 65 | */ 66 | #define LOG_FATAL(...) (cbm_log(CBM_LOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)) 67 | 68 | /** 69 | * Log a warning message that must always be seen 70 | */ 71 | #define LOG_WARNING(...) (cbm_log(CBM_LOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)) 72 | 73 | #define check_common_ret_val(level, exp, ret_val, ...) \ 74 | do { \ 75 | if (exp) { \ 76 | LOG_##level(__VA_ARGS__); \ 77 | return ret_val; \ 78 | } \ 79 | } while(false) \ 80 | 81 | #define check_common_ret(level, exp, ...) \ 82 | do { \ 83 | if (exp) { \ 84 | LOG_##level(__VA_ARGS__); \ 85 | return; \ 86 | } \ 87 | } while(false) \ 88 | 89 | #define check_common_goto(level, exp, label, ...) \ 90 | do { \ 91 | if (exp) { \ 92 | LOG_##level(__VA_ARGS__); \ 93 | goto label; \ 94 | } \ 95 | } while(false) \ 96 | 97 | #define check_common_continue(level, exp, ...) \ 98 | if (exp) { \ 99 | LOG_##level(__VA_ARGS__); \ 100 | continue; \ 101 | } \ 102 | 103 | #define check_common(level, exp, ...) \ 104 | do { \ 105 | if (exp) { \ 106 | LOG_##level(__VA_ARGS__); \ 107 | } \ 108 | } while(false) \ 109 | 110 | #define CHECK_ERR(exp, ...) \ 111 | check_common(ERROR, exp, __VA_ARGS__) \ 112 | 113 | #define CHECK_ERR_RET_VAL(exp, ret_val, ...) \ 114 | check_common_ret_val(ERROR, exp, ret_val, __VA_ARGS__) \ 115 | 116 | #define CHECK_ERR_RET(exp, ...) \ 117 | check_common_ret(ERROR, exp, __VA_ARGS__) \ 118 | 119 | #define CHECK_ERR_GOTO(exp, label, ...) \ 120 | check_common_goto(ERROR, exp, label, __VA_ARGS__) \ 121 | 122 | #define CHECK_ERR_CONTINUE(exp, ...) \ 123 | check_common_continue(ERROR, exp, __VA_ARGS__) \ 124 | 125 | #define CHECK_WARN(exp, ...) \ 126 | check_common(WARNING, exp, __VA_ARGS__) \ 127 | 128 | #define CHECK_WARN_RET_VAL(exp, ret_val, ...) \ 129 | check_common_ret_val(WARNING, exp, ret_val, __VA_ARGS__) \ 130 | 131 | #define CHECK_WARN_RET(exp, ...) \ 132 | check_common_ret(WARNING, exp, __VA_ARGS__) \ 133 | 134 | #define CHECK_WARN_GOTO(exp, label, ...) \ 135 | check_common_goto(WARNING, exp, label, __VA_ARGS__) \ 136 | 137 | #define CHECK_WARN_CONTINUE(exp, ...) \ 138 | check_common_continue(WARNING, exp, __VA_ARGS__) \ 139 | 140 | #define CHECK_INF(exp, ...) \ 141 | check_common(INFO, exp, __VA_ARGS__) \ 142 | 143 | #define CHECK_INF_RET_VAL(exp, ret_val, ...) \ 144 | check_common_ret_val(INFO, exp, ret_val, __VA_ARGS__) \ 145 | 146 | #define CHECK_INF_RET(exp, ...) \ 147 | check_common_ret(INFO, exp, __VA_ARGS__) \ 148 | 149 | #define CHECK_INF_GOTO(exp, label, ...) \ 150 | check_common_goto(INFO, exp, label, __VA_ARGS__) \ 151 | 152 | #define CHECK_INF_CONTINUE(exp, ...) \ 153 | check_common_continue(INFO, exp, __VA_ARGS__) \ 154 | 155 | #define CHECK_DBG(exp, ...) \ 156 | check_common(DEBUG, exp, __VA_ARGS__) \ 157 | 158 | #define CHECK_DBG_RET_VAL(exp, ret_val, ...) \ 159 | check_common_ret_val(DEBUG, exp, ret_val, __VA_ARGS__) \ 160 | 161 | #define CHECK_DBG_RET(exp, ...) \ 162 | check_common_ret(DEBUG, exp, __VA_ARGS__) \ 163 | 164 | #define CHECK_DBG_GOTO(exp, label, ...) \ 165 | check_common_goto(DEBUG, exp, label, __VA_ARGS__) \ 166 | 167 | #define CHECK_DBG_CONTINUE(exp, ...) \ 168 | check_common_continue(DEBUG, exp, __VA_ARGS__) \ 169 | 170 | #define CHECK_FATAL(exp, ...) \ 171 | check_common(FATAL, exp, __VA_ARGS__) \ 172 | 173 | #define CHECK_FATAL_RET_VAL(exp, ret_val, ...) \ 174 | check_common_ret_val(FATAL, exp, ret_val, __VA_ARGS__) \ 175 | 176 | #define CHECK_FATAL_RET(exp, ...) \ 177 | check_common_ret(FATAL, exp, __VA_ARGS__) \ 178 | 179 | #define CHECK_FATAL_GOTO(exp, label, ...) \ 180 | check_common_goto(FATAL, exp, label, __VA_ARGS__) \ 181 | 182 | #define CHECK_FATAL_CONTINUE(exp, ...) \ 183 | check_common_continue(FATAL, exp, __VA_ARGS__) \ 184 | 185 | /* 186 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 187 | * 188 | * Local variables: 189 | * c-basic-offset: 8 190 | * tab-width: 8 191 | * indent-tabs-mode: nil 192 | * End: 193 | * 194 | * vi: set shiftwidth=8 tabstop=8 expandtab: 195 | * :indentSize=8:tabSize=8:noTabs=true: 196 | */ 197 | -------------------------------------------------------------------------------- /src/lib/os-release.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #include "os-release.h" 13 | #include "config.h" 14 | #include "log.h" 15 | #include "nica/files.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** 23 | * Statically defined fields for correctness of implementation 24 | */ 25 | static const char *os_release_fields[] = { 26 | [OS_RELEASE_NAME] = "NAME", 27 | [OS_RELEASE_VERSION] = "VERSION", 28 | [OS_RELEASE_ID] = "ID", 29 | [OS_RELEASE_VERSION_ID] = "VERSION_ID", 30 | [OS_RELEASE_PRETTY_NAME] = "PRETTY_NAME", 31 | [OS_RELEASE_ANSI_COLOR] = "ANSI_COLOR", 32 | [OS_RELEASE_HOME_URL] = "HOME_URL", 33 | [OS_RELEASE_SUPPORT_URL] = "SUPPORT_URL", 34 | [OS_RELEASE_BUG_REPORT_URL] = "BUG_REPORT_URL", 35 | }; 36 | 37 | /** 38 | * Return a sane fallback key if one isn't provided in the config. 39 | */ 40 | static const char *cbm_os_release_fallback_value(CbmOsReleaseKey key) 41 | { 42 | switch (key) { 43 | case OS_RELEASE_NAME: 44 | return "generic-linux-os"; 45 | case OS_RELEASE_PRETTY_NAME: 46 | return "generic-linux-os"; 47 | case OS_RELEASE_ID: 48 | /* Similar purpose within CBM */ 49 | return VENDOR_PREFIX; 50 | case OS_RELEASE_VERSION: 51 | case OS_RELEASE_VERSION_ID: 52 | return "1"; 53 | default: 54 | return ""; 55 | } 56 | } 57 | 58 | /** 59 | * Do the actual hard work of parsing the os-release file. 60 | */ 61 | static bool cbm_os_release_parse(CbmOsRelease *self, const char *path) 62 | { 63 | autofree(FILE) *f = NULL; 64 | size_t sn; 65 | ssize_t r = 0; 66 | char *buf = NULL; 67 | bool ret = true; 68 | 69 | f = fopen(path, "r"); 70 | if (!f) { 71 | if (errno != ENOENT) { 72 | LOG_ERROR("Unable to open %s: %s", path, strerror(errno)); 73 | } 74 | return false; 75 | } 76 | 77 | while ((r = getline(&buf, &sn, f)) > 0) { 78 | ssize_t cur = 0; 79 | size_t val_len = 0; 80 | size_t incr = 0; 81 | char *key = NULL; 82 | autofree(char) *value = NULL; 83 | 84 | /* Strip newlines */ 85 | if (r >= 1 && buf[r - 1] == '\n') { 86 | buf[r - 1] = '\0'; 87 | --r; 88 | } 89 | 90 | char *l = buf; 91 | char *c = NULL; 92 | 93 | /* Skip empty lines */ 94 | if (r < 1) { 95 | goto next_line; 96 | } 97 | 98 | /* Skip the starting whitespace */ 99 | while (isspace(*l)) { 100 | ++l; 101 | if (!*l) { 102 | break; 103 | } 104 | } 105 | 106 | /* Skip a comment */ 107 | if (l[0] == '#') { 108 | goto next_line; 109 | } 110 | 111 | /* Reset length */ 112 | cur = (l - buf); 113 | r -= cur; 114 | 115 | /* Strip trailing whitespace */ 116 | l = rstrip(l, (size_t *)&r); 117 | 118 | /* May now be an empty line */ 119 | if (r < 1) { 120 | goto next_line; 121 | } 122 | 123 | /* Look for assignment */ 124 | c = memchr(l, '=', (size_t)r); 125 | if (!c) { 126 | goto next_line; 127 | } 128 | 129 | /* Skip empty value */ 130 | val_len = (size_t)(r - ((c - l) + 1)); 131 | if (val_len < 1) { 132 | goto next_line; 133 | } 134 | 135 | /* Skip empty keys */ 136 | if (c - l < 1) { 137 | goto next_line; 138 | } 139 | 140 | key = strndup(l, (size_t)(c - l)); 141 | value = strndup(c + 1, val_len); 142 | 143 | /* Fix the key to always be upper case */ 144 | char *tkey = key; 145 | while (*tkey != '\0') { 146 | *tkey = (char)toupper(*tkey); 147 | ++tkey; 148 | } 149 | 150 | if (value[val_len - 1] == '\'' || value[val_len - 1] == '\"') { 151 | value[val_len - 1] = '\0'; 152 | } 153 | 154 | if (value[0] == '\'' || value[0] == '\"') { 155 | incr = 1; 156 | } 157 | 158 | if (!nc_hashmap_put(self, key, strdup(value + incr))) { 159 | ret = false; 160 | break; 161 | } 162 | next_line: 163 | free(buf); 164 | buf = NULL; 165 | } 166 | 167 | if (buf) { 168 | free(buf); 169 | buf = NULL; 170 | } 171 | return ret; 172 | } 173 | 174 | CbmOsRelease *cbm_os_release_new(const char *path) 175 | { 176 | NcHashmap *ret = NULL; 177 | 178 | ret = nc_hashmap_new_full(nc_string_hash, nc_string_compare, free, free); 179 | if (!cbm_os_release_parse(ret, path)) { 180 | cbm_os_release_free(ret); 181 | return nc_hashmap_new_full(nc_string_hash, nc_string_compare, free, free); 182 | } 183 | 184 | return ret; 185 | } 186 | 187 | CbmOsRelease *cbm_os_release_new_for_root(const char *root) 188 | { 189 | static const char *files[] = { "etc/os-release", "usr/lib/os-release" }; 190 | CbmOsRelease *release = NULL; 191 | 192 | /* Loop the files until one parses, otherwise return an empty NcHashmap */ 193 | for (size_t i = 0; i < ARRAY_SIZE(files); i++) { 194 | autofree(char) *p = NULL; 195 | 196 | p = string_printf("%s/%s", root, files[i]); 197 | 198 | if (!nc_file_exists(p)) { 199 | continue; 200 | } 201 | 202 | release = cbm_os_release_new(p); 203 | if (release) { 204 | return release; 205 | } 206 | } 207 | 208 | return nc_hashmap_new_full(nc_string_hash, nc_string_compare, free, free); 209 | } 210 | 211 | void cbm_os_release_free(CbmOsRelease *self) 212 | { 213 | nc_hashmap_free(self); 214 | } 215 | 216 | const char *cbm_os_release_get_value(CbmOsRelease *self, CbmOsReleaseKey key) 217 | { 218 | const char *strkey = NULL; 219 | const char *ret = NULL; 220 | 221 | /* Guard against any malloc failures */ 222 | if (!self) { 223 | return cbm_os_release_fallback_value(key); 224 | } 225 | 226 | if (key <= OS_RELEASE_MIN || key >= OS_RELEASE_MAX) { 227 | return NULL; 228 | } 229 | 230 | strkey = os_release_fields[key]; 231 | ret = nc_hashmap_get(self, strkey); 232 | if (!ret) { 233 | ret = cbm_os_release_fallback_value(key); 234 | } 235 | 236 | return ret; 237 | } 238 | 239 | /* 240 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 241 | * 242 | * Local variables: 243 | * c-basic-offset: 8 244 | * tab-width: 8 245 | * indent-tabs-mode: nil 246 | * End: 247 | * 248 | * vi: set shiftwidth=8 tabstop=8 expandtab: 249 | * :indentSize=8:tabSize=8:noTabs=true: 250 | */ 251 | -------------------------------------------------------------------------------- /src/lib/os-release.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include "nica/hashmap.h" 17 | #include "util.h" 18 | 19 | typedef enum { 20 | OS_RELEASE_MIN = 0, 21 | OS_RELEASE_NAME, 22 | OS_RELEASE_VERSION, 23 | OS_RELEASE_ID, 24 | OS_RELEASE_VERSION_ID, 25 | OS_RELEASE_PRETTY_NAME, 26 | OS_RELEASE_ANSI_COLOR, 27 | OS_RELEASE_HOME_URL, 28 | OS_RELEASE_SUPPORT_URL, 29 | OS_RELEASE_BUG_REPORT_URL, 30 | OS_RELEASE_MAX, 31 | } CbmOsReleaseKey; 32 | 33 | /** 34 | * OsRelease is simply a hashmap with forced lower keys, 35 | * and some handy accessor methods. 36 | * 37 | * A CbmOsRelease is parsed from an /etc/os-release style file to provide 38 | * OS version and name information. 39 | */ 40 | typedef NcHashmap CbmOsRelease; 41 | 42 | /** 43 | * Create a new CbmOsRelease by parsing the given os-release file 44 | * This method may return an empty CbmOsRelease map if there was a parsing 45 | * issue. 46 | */ 47 | CbmOsRelease *cbm_os_release_new(const char *path); 48 | 49 | /** 50 | * Find the first os-release file in the standard locations within the 51 | * given root. 52 | * In the instance that no os-release files are found, or a parsing 53 | * error occurred, an empty CbmOsRelease will be returned. 54 | */ 55 | CbmOsRelease *cbm_os_release_new_for_root(const char *root); 56 | 57 | /** 58 | * Return the value of a predefined field in the os-release file. 59 | * This string belongs to the CbmOsRelease instance and should not be 60 | * freed or modified in any way. 61 | * If you need to modify it, strdup it. 62 | * 63 | * This method will only ever return NULL if self is NULL or if the key is 64 | * within an invalid range. 65 | * 66 | * @param key The field to return a value for 67 | */ 68 | const char *cbm_os_release_get_value(CbmOsRelease *self, CbmOsReleaseKey key); 69 | 70 | /** 71 | * Free a previously allocated CbmOsRelease 72 | */ 73 | void cbm_os_release_free(CbmOsRelease *self); 74 | 75 | /* Convenience function */ 76 | DEF_AUTOFREE(CbmOsRelease, nc_hashmap_free) 77 | 78 | /* 79 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 80 | * 81 | * Local variables: 82 | * c-basic-offset: 8 83 | * tab-width: 8 84 | * indent-tabs-mode: nil 85 | * End: 86 | * 87 | * vi: set shiftwidth=8 tabstop=8 expandtab: 88 | * :indentSize=8:tabSize=8:noTabs=true: 89 | */ 90 | -------------------------------------------------------------------------------- /src/lib/probe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include 17 | #include 18 | 19 | #include "util.h" 20 | 21 | /** 22 | * A CbmCbmDeviceProbe is the result of a cbm_probe_path operation, caching 23 | * fields useful to clr-boot-manager in terms of partition analysis. 24 | */ 25 | typedef struct CbmDeviceProbe { 26 | char *uuid; /**< UUID for all partition types */ 27 | char *part_uuid; /**< PartUUID for GPT partitions */ 28 | char *luks_uuid; /**< Parent LUKS UUID for the partition */ 29 | dev_t dev; /**< The device itself */ 30 | bool gpt; /** 15 | #include 16 | #include 17 | #include 18 | 19 | #include "files.h" 20 | #include "log.h" 21 | 22 | /** 23 | * Factory function to convert a dev_t to the full device path 24 | * This is the default internal function 25 | */ 26 | static char *cbm_devnode_to_devpath(dev_t dev) 27 | { 28 | autofree(char) *c = NULL; 29 | 30 | if (major(dev) == 0) { 31 | LOG_ERROR("Invalid block device: %u:%u", major(dev), minor(dev)); 32 | return NULL; 33 | } 34 | 35 | c = string_printf("/dev/block/%u:%u", major(dev), minor(dev)); 36 | return realpath(c, NULL); 37 | } 38 | 39 | static const char *cbm_get_sysfs_path(void) 40 | { 41 | return "/sys"; 42 | } 43 | 44 | static const char *cbm_get_devfs_path(void) 45 | { 46 | return "/dev"; 47 | } 48 | 49 | /** 50 | * Default vtable for system call passthrough 51 | */ 52 | static CbmSystemOps default_system_ops = { 53 | .mount = mount, 54 | .umount = umount, 55 | .system = system, 56 | .is_mounted = cbm_is_mounted, 57 | .get_mountpoint_for_device = cbm_get_mountpoint_for_device, 58 | .get_device_for_mountpoint = cbm_get_device_for_mountpoint, 59 | .devnode_to_devpath = cbm_devnode_to_devpath, 60 | .get_sysfs_path = cbm_get_sysfs_path, 61 | .get_devfs_path = cbm_get_devfs_path, 62 | }; 63 | 64 | /** 65 | * Pointer to the currently active vtable 66 | */ 67 | static CbmSystemOps *system_ops = &default_system_ops; 68 | 69 | void cbm_system_reset_vtable(void) 70 | { 71 | system_ops = &default_system_ops; 72 | } 73 | 74 | void cbm_system_set_vtable(CbmSystemOps *ops) 75 | { 76 | if (!ops) { 77 | cbm_system_reset_vtable(); 78 | } else { 79 | system_ops = ops; 80 | } 81 | /* Ensure the vtable is valid at this point. */ 82 | assert(system_ops->mount != NULL); 83 | assert(system_ops->umount != NULL); 84 | assert(system_ops->is_mounted != NULL); 85 | assert(system_ops->get_mountpoint_for_device != NULL); 86 | assert(system_ops->system != NULL); 87 | assert(system_ops->devnode_to_devpath != NULL); 88 | assert(system_ops->get_sysfs_path != NULL); 89 | assert(system_ops->get_devfs_path != NULL); 90 | } 91 | 92 | int cbm_system_mount(const char *source, const char *target, const char *filesystemtype, 93 | unsigned long mountflags, const void *data) 94 | { 95 | return system_ops->mount(source, target, filesystemtype, mountflags, data); 96 | } 97 | 98 | int cbm_system_umount(const char *target) 99 | { 100 | return system_ops->umount(target); 101 | } 102 | 103 | int cbm_system_system(const char *command) 104 | { 105 | return system_ops->system(command); 106 | } 107 | 108 | bool cbm_system_is_mounted(const char *target) 109 | { 110 | return system_ops->is_mounted(target); 111 | } 112 | 113 | char *cbm_system_get_mountpoint_for_device(const char *device) 114 | { 115 | return system_ops->get_mountpoint_for_device(device); 116 | } 117 | 118 | char *cbm_system_get_device_for_mountpoint(const char *device) 119 | { 120 | return system_ops->get_device_for_mountpoint(device); 121 | } 122 | 123 | char *cbm_system_devnode_to_devpath(dev_t d) 124 | { 125 | return system_ops->devnode_to_devpath(d); 126 | } 127 | 128 | const char *cbm_system_get_sysfs_path() 129 | { 130 | return system_ops->get_sysfs_path(); 131 | } 132 | 133 | const char *cbm_system_get_devfs_path() 134 | { 135 | return system_ops->get_devfs_path(); 136 | } 137 | 138 | /* 139 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 140 | * 141 | * Local variables: 142 | * c-basic-offset: 8 143 | * tab-width: 8 144 | * indent-tabs-mode: nil 145 | * End: 146 | * 147 | * vi: set shiftwidth=8 tabstop=8 expandtab: 148 | * :indentSize=8:tabSize=8:noTabs=true: 149 | */ 150 | -------------------------------------------------------------------------------- /src/lib/system_stub.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include 17 | #include 18 | 19 | /** 20 | * Defines the vtable used for all systen operations within clr-boot-manager. 21 | * The default internal vtable will pass through all operations to the standard 22 | * library. 23 | */ 24 | typedef struct CbmSystemOps { 25 | /* fs functions */ 26 | int (*mount)(const char *source, const char *target, const char *filesystemtype, 27 | unsigned long mountflags, const void *data); 28 | int (*umount)(const char *target); 29 | 30 | /* wrap cbm lib functions */ 31 | bool (*is_mounted)(const char *target); 32 | char *(*get_mountpoint_for_device)(const char *device); 33 | char *(*get_device_for_mountpoint)(const char *mount); 34 | 35 | /* exec family */ 36 | int (*system)(const char *command); 37 | 38 | /* dev utility */ 39 | char *(*devnode_to_devpath)(dev_t t); 40 | const char *(*get_sysfs_path)(void); 41 | const char *(*get_devfs_path)(void); 42 | } CbmSystemOps; 43 | 44 | /** 45 | * Reset the system vtable 46 | */ 47 | void cbm_system_reset_vtable(void); 48 | 49 | /** 50 | * Set the vfunc table used for all system operations within clr-boot-manager 51 | * 52 | * @note Passing null has the same effect as calling cbm_system_reset 53 | * The vtable will be checked to ensure that it is valid at this point, so 54 | * only call this when the vtable is fully populated. 55 | */ 56 | void cbm_system_set_vtable(CbmSystemOps *ops); 57 | 58 | /** 59 | * Wrap the mount syscall 60 | */ 61 | int cbm_system_mount(const char *source, const char *target, const char *filesystemtype, 62 | unsigned long mountflags, const void *data); 63 | 64 | /** 65 | * Determine if the given mount point is already mounted 66 | */ 67 | bool cbm_system_is_mounted(const char *target); 68 | 69 | /** 70 | * Get the mountpoint for the given device path 71 | */ 72 | char *cbm_system_get_mountpoint_for_device(const char *device); 73 | 74 | /** 75 | * Get the device path for a given mountpoint 76 | */ 77 | char *cbm_system_get_device_for_mountpoint(const char *device); 78 | 79 | /** 80 | * Wrap the umount syscall 81 | */ 82 | int cbm_system_umount(const char *target); 83 | 84 | /** 85 | * Wrap the system() call 86 | */ 87 | int cbm_system_system(const char *command); 88 | 89 | /** 90 | * Resolve the path for a given dev_t 91 | */ 92 | char *cbm_system_devnode_to_devpath(dev_t d); 93 | 94 | /** 95 | * Help mocking by allowing /sys to be overridden 96 | */ 97 | const char *cbm_system_get_sysfs_path(void); 98 | 99 | /** 100 | * Help mocking by allowing /dev to be overridden 101 | */ 102 | const char *cbm_system_get_devfs_path(void); 103 | 104 | /* 105 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 106 | * 107 | * Local variables: 108 | * c-basic-offset: 8 109 | * tab-width: 8 110 | * indent-tabs-mode: nil 111 | * End: 112 | * 113 | * vi: set shiftwidth=8 tabstop=8 expandtab: 114 | * :indentSize=8:tabSize=8:noTabs=true: 115 | */ 116 | -------------------------------------------------------------------------------- /src/lib/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include 15 | #include 16 | 17 | #include "util.h" 18 | 19 | char *rstrip(char *a, size_t *len) 20 | { 21 | /* start at the last character in the string */ 22 | char *e = a + *len - 1; 23 | 24 | if (*len < 1) { 25 | return a; 26 | } 27 | 28 | for (;;) { 29 | if (e < a || !isspace(*e)) { 30 | break; 31 | } 32 | --e; 33 | } 34 | 35 | if (e < a) { 36 | *len = 0; 37 | *a = '\0'; 38 | } else { 39 | *len = (size_t)(e - a) + 1; 40 | *(e + 1) = '\0'; 41 | } 42 | 43 | return a; 44 | } 45 | 46 | char *string_printf(const char *fmt, ...) 47 | { 48 | char *ret = NULL; 49 | va_list va; 50 | va_start(va, fmt); 51 | if (vasprintf(&ret, fmt, va) < 0) { 52 | DECLARE_OOM(); 53 | abort(); 54 | } 55 | va_end(va); 56 | return ret; 57 | } 58 | 59 | /* 60 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 61 | * 62 | * Local variables: 63 | * c-basic-offset: 8 64 | * tab-width: 8 65 | * indent-tabs-mode: nil 66 | * End: 67 | * 68 | * vi: set shiftwidth=8 tabstop=8 expandtab: 69 | * :indentSize=8:tabSize=8:noTabs=true: 70 | */ 71 | -------------------------------------------------------------------------------- /src/lib/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #define _GNU_SOURCE 15 | 16 | #include "nica/util.h" 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #define DECLARE_OOM() \ 25 | { \ 26 | fputs("("__FILE__":", stderr); \ 27 | fputs(__func__, stderr); \ 28 | fputs("()) Out of memory\n", stderr); \ 29 | \ 30 | } 31 | 32 | #define OOM_CHECK(x) \ 33 | { \ 34 | if (!x) { \ 35 | DECLARE_OOM(); \ 36 | abort(); \ 37 | } \ 38 | } 39 | #define OOM_CHECK_RET(x, y) \ 40 | { \ 41 | if (!x) { \ 42 | DECLARE_OOM(); \ 43 | return y; \ 44 | } \ 45 | } 46 | 47 | /** Helper for array looping */ 48 | #define ARRAY_SIZE(x) sizeof(x) / sizeof(x[0]) 49 | 50 | /** 51 | * Always inline the function 52 | */ 53 | #define __cbm_inline__ __attribute__((always_inline)) 54 | 55 | /** 56 | * For quicker development 57 | */ 58 | #define __cbm_unused__ __attribute__((unused)) 59 | 60 | /** 61 | * Strip the right side of a string of it's whitespace 62 | * This must be allocated memory 63 | */ 64 | char *rstrip(char *a, size_t *len); 65 | 66 | /** 67 | * Similar to asprintf, but will assert allocation of the string. 68 | * Failure to do so will result in an abort, as there is nothing 69 | * further than clr-boot-manager can do when it has run out of 70 | * memory. 71 | */ 72 | char *string_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 73 | 74 | /* 75 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 76 | * 77 | * Local variables: 78 | * c-basic-offset: 8 79 | * tab-width: 8 80 | * indent-tabs-mode: nil 81 | * End: 82 | * 83 | * vi: set shiftwidth=8 tabstop=8 expandtab: 84 | * :indentSize=8:tabSize=8:noTabs=true: 85 | */ 86 | -------------------------------------------------------------------------------- /src/lib/writer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | 14 | #include "writer.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | bool cbm_writer_open(CbmWriter *writer) 22 | { 23 | if (!writer) { 24 | return false; 25 | } 26 | 27 | if (writer->buffer || writer->memstream) { 28 | return false; 29 | } 30 | 31 | writer->memstream = open_memstream(&writer->buffer, &writer->buffer_n); 32 | if (!writer->memstream) { 33 | writer->error = ENOMEM; 34 | return false; 35 | } 36 | 37 | return true; 38 | } 39 | 40 | void cbm_writer_free(CbmWriter *self) 41 | { 42 | if (!self) { 43 | return; 44 | } 45 | cbm_writer_close(self); 46 | free(self->buffer); 47 | } 48 | 49 | void cbm_writer_close(CbmWriter *self) 50 | { 51 | if (!self) { 52 | return; 53 | } 54 | if (!self->memstream) { 55 | return; 56 | } 57 | fclose(self->memstream); 58 | self->memstream = NULL; 59 | } 60 | 61 | void cbm_writer_append(CbmWriter *self, const char *s) 62 | { 63 | if (!self || self->error != 0) { 64 | return; 65 | } 66 | 67 | /* Set EBADF as we tried to use a closed memstream */ 68 | if (!self->memstream) { 69 | self->error = EBADF; 70 | return; 71 | } 72 | 73 | if (fprintf(self->memstream, "%s", s) < 0) { 74 | self->error = errno; 75 | } 76 | } 77 | 78 | void cbm_writer_append_printf(CbmWriter *self, const char *fmt, ...) 79 | { 80 | if (!self || self->error != 0) { 81 | return; 82 | } 83 | 84 | /* Set EBADF as we tried to use a closed memstream */ 85 | if (!self->memstream) { 86 | self->error = EBADF; 87 | return; 88 | } 89 | 90 | va_list va; 91 | 92 | va_start(va, fmt); 93 | if (vfprintf(self->memstream, fmt, va) < 0) { 94 | self->error = errno; 95 | } 96 | va_end(va); 97 | } 98 | 99 | int cbm_writer_error(CbmWriter *self) 100 | { 101 | if (self) { 102 | return self->error; 103 | } 104 | /* Assume enomem with pointer issues */ 105 | return ENOMEM; 106 | } 107 | 108 | /* 109 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 110 | * 111 | * Local variables: 112 | * c-basic-offset: 8 113 | * tab-width: 8 114 | * indent-tabs-mode: nil 115 | * End: 116 | * 117 | * vi: set shiftwidth=8 tabstop=8 expandtab: 118 | * :indentSize=8:tabSize=8:noTabs=true: 119 | */ 120 | -------------------------------------------------------------------------------- /src/lib/writer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2017-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "nica/util.h" 15 | 16 | #define _GNU_SOURCE 17 | 18 | typedef struct CbmWriter { 19 | FILE *memstream; 20 | char *buffer; 21 | size_t buffer_n; 22 | int error; 23 | } CbmWriter; 24 | 25 | #define CBM_WRITER_INIT &(CbmWriter){ 0 }; 26 | 27 | /** 28 | * Construct a new CbmWriter 29 | */ 30 | bool cbm_writer_open(CbmWriter *writer); 31 | 32 | /** 33 | * Clean up a previously allocated CbmWriter 34 | */ 35 | void cbm_writer_free(CbmWriter *writer); 36 | 37 | /** 38 | * Close the writer, which will ensure that the buffer is NULL terminated. 39 | * No more writes are possible after this close. 40 | */ 41 | void cbm_writer_close(CbmWriter *writer); 42 | 43 | /** 44 | * Append string to the buffer 45 | */ 46 | void cbm_writer_append(CbmWriter *writer, const char *s); 47 | 48 | /** 49 | * Append, printf style, to the buffer 50 | */ 51 | void cbm_writer_append_printf(CbmWriter *writer, const char *fmt, ...) 52 | __attribute__((format(printf, 2, 3))); 53 | 54 | /** 55 | * Return an error that may exist in the stream, otherwise 0. 56 | * This allows utilising CbmWriter in a failsafe fashion, and checking the 57 | * error once only. 58 | */ 59 | int cbm_writer_error(CbmWriter *writer); 60 | 61 | /* Convenience: Automatically clean up the CbmWriter */ 62 | DEF_AUTOFREE(CbmWriter, cbm_writer_free) 63 | 64 | /* 65 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 66 | * 67 | * Local variables: 68 | * c-basic-offset: 8 69 | * tab-width: 8 70 | * indent-tabs-mode: nil 71 | * End: 72 | * 73 | * vi: set shiftwidth=8 tabstop=8 expandtab: 74 | * :indentSize=8:tabSize=8:noTabs=true: 75 | */ 76 | -------------------------------------------------------------------------------- /src/meson.build: -------------------------------------------------------------------------------- 1 | # First things first, set up libnica 2 | libnica_sources = [ 3 | 'libnica/src/array.c', 4 | 'libnica/src/hashmap.c', 5 | 'libnica/src/files.c', 6 | 'libnica/src/inifile.c', 7 | 'libnica/src/list.c', 8 | 'libnica/src/nc-string.c', 9 | 'libnica/src/util.c', 10 | ] 11 | 12 | libnica_includes = [ 13 | include_directories('libnica/src/include'), 14 | include_directories('libnica/src/include/nica'), 15 | config_h_dir, 16 | ] 17 | 18 | libnica = static_library( 19 | 'nica', 20 | sources: libnica_sources, 21 | include_directories: libnica_includes, 22 | ) 23 | 24 | link_libnica = declare_dependency( 25 | link_with: libnica, 26 | include_directories: [ 27 | libnica_includes, 28 | ], 29 | ) 30 | 31 | # Now lets build libcbm (clr-boot-manager core library) 32 | 33 | libcbm_sources = [ 34 | 'bootloaders/systemd-class.c', 35 | 'bootloaders/systemd-boot.c', 36 | 'bootloaders/extlinux.c', 37 | 'bootloaders/syslinux.c', 38 | 'bootloaders/syslinux-common.c', 39 | 'bootloaders/mbr.c', 40 | 'bootman/bootman.c', 41 | 'bootman/kernel.c', 42 | 'bootman/sysconfig.c', 43 | 'bootman/timeout.c', 44 | 'bootman/update.c', 45 | 'lib/blkid_stub.c', 46 | 'lib/cmdline.c', 47 | 'lib/files.c', 48 | 'lib/os-release.c', 49 | 'lib/log.c', 50 | 'lib/probe.c', 51 | 'lib/system_stub.c', 52 | 'lib/writer.c', 53 | 'lib/util.c', 54 | ] 55 | 56 | if with_grub2_backend == true 57 | libcbm_sources += [ 58 | 'bootloaders/grub2.c', 59 | ] 60 | endif 61 | 62 | libcbm_includes = [ 63 | include_directories('bootloaders'), 64 | include_directories('bootman'), 65 | include_directories('lib'), 66 | ] 67 | 68 | libcbm_dependencies = [ 69 | link_libnica, 70 | dep_blkid, 71 | ] 72 | 73 | # Special constraints for efi functionality 74 | if require_efi == true 75 | libcbm_dependencies += dep_efiboot 76 | libcbm_dependencies += dep_efivar 77 | libcbm_sources += [ 78 | 'bootloaders/shim-systemd.c', 79 | 'lib/bootvar.c', 80 | ] 81 | endif 82 | 83 | libcbm = static_library( 84 | 'cbm', 85 | sources: libcbm_sources, 86 | c_args: ['-D_BOOTMAN_INTERNAL_'], 87 | dependencies: libcbm_dependencies, 88 | include_directories: libcbm_includes, 89 | ) 90 | 91 | link_libcbm = declare_dependency( 92 | link_with: libcbm, 93 | include_directories: libcbm_includes + libnica_includes, 94 | ) 95 | 96 | # Now clr-boot-manager itself 97 | clr_boot_manager_sources = [ 98 | 'cli/cli.c', 99 | 'cli/main.c', 100 | 'cli/ops/kernels.c', 101 | 'cli/ops/report_booted.c', 102 | 'cli/ops/timeout.c', 103 | 'cli/ops/update.c', 104 | ] 105 | 106 | 107 | clr_boot_manager = executable( 108 | 'clr-boot-manager', 109 | sources: clr_boot_manager_sources, 110 | include_directories: [ 111 | include_directories('cli'), 112 | ], 113 | dependencies: link_libcbm, 114 | install: true, 115 | ) 116 | -------------------------------------------------------------------------------- /tests/blkid-harness.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "blkid_stub.h" 15 | #include 16 | 17 | const char *DEFAULT_UUID = "Test-UUID"; 18 | const char *DEFAULT_PART_UUID = "Test-PartUUID"; 19 | 20 | /** 21 | * Probe functions 22 | */ 23 | static inline blkid_probe test_blkid_new_probe_from_filename(__cbm_unused__ const char *filename) 24 | { 25 | return CBM_BLKID_PROBE_SET; 26 | } 27 | 28 | static inline int test_blkid_probe_enable_superblocks(__cbm_unused__ blkid_probe pr, 29 | __cbm_unused__ int enable) 30 | { 31 | return 0; 32 | } 33 | 34 | static inline int test_blkid_probe_set_superblocks_flags(__cbm_unused__ blkid_probe pr, 35 | __cbm_unused__ int flags) 36 | { 37 | return 0; 38 | } 39 | 40 | static inline int test_blkid_probe_enable_partitions(__cbm_unused__ blkid_probe pr, 41 | __cbm_unused__ int enable) 42 | { 43 | return 0; 44 | } 45 | 46 | static inline int test_blkid_probe_set_partitions_flags(__cbm_unused__ blkid_probe pr, 47 | __cbm_unused__ int flags) 48 | { 49 | return 0; 50 | } 51 | 52 | static inline dev_t test_blkid_probe_get_wholedisk_devno(__cbm_unused__ blkid_probe pr) 53 | { 54 | /* Prevent legacy testing */ 55 | return makedev(0, 0); 56 | } 57 | 58 | static inline int test_blkid_do_safeprobe(__cbm_unused__ blkid_probe pr) 59 | { 60 | return 0; 61 | } 62 | 63 | static inline int test_blkid_probe_lookup_value(__cbm_unused__ blkid_probe pr, const char *name, 64 | const char **data, size_t *len) 65 | { 66 | if (!name || !data) { 67 | return -1; 68 | } 69 | if (streq(name, "UUID")) { 70 | *data = DEFAULT_UUID; 71 | } else if (streq(name, "PART_ENTRY_UUID")) { 72 | *data = DEFAULT_PART_UUID; 73 | } else { 74 | return -1; 75 | } 76 | if (!*data) { 77 | abort(); 78 | } 79 | if (len) { 80 | *len = strlen(*data); 81 | } 82 | return 0; 83 | } 84 | 85 | static inline void test_blkid_free_probe(__cbm_unused__ blkid_probe pr) 86 | { 87 | } 88 | 89 | /** 90 | * Partition functions 91 | */ 92 | static inline blkid_partlist test_blkid_probe_get_partitions(__cbm_unused__ blkid_probe pr) 93 | { 94 | return CBM_BLKID_PARTLIST_SET; 95 | } 96 | 97 | static inline int test_blkid_partlist_numof_partitions(__cbm_unused__ blkid_partlist ls) 98 | { 99 | return 2; 100 | } 101 | 102 | static inline blkid_partition test_blkid_partlist_get_partition(__cbm_unused__ blkid_partlist ls, 103 | __cbm_unused__ int n) 104 | { 105 | return CBM_BLKID_PARTITION_SET; 106 | } 107 | 108 | static inline unsigned long long test_blkid_partition_get_flags(__cbm_unused__ blkid_partition par) 109 | { 110 | /* Prevents legacy testing */ 111 | return 0; 112 | } 113 | 114 | static inline const char *test_blkid_partition_get_uuid(__cbm_unused__ blkid_partition par) 115 | { 116 | return NULL; 117 | } 118 | 119 | static inline int test_blkid_devno_to_wholedisk(__cbm_unused__ dev_t dev, 120 | __cbm_unused__ char *diskname, 121 | __cbm_unused__ size_t len, 122 | __cbm_unused__ dev_t *diskdevno) 123 | { 124 | /* Prevent legacy testing */ 125 | return -1; 126 | } 127 | 128 | static inline char *test_blkid_devno_to_devname(dev_t dev) 129 | { 130 | return string_printf("%s/dev/block/%u:%u", 131 | TOP_BUILD_DIR "/tests/update_playground", major(dev), minor(dev)); 132 | } 133 | 134 | static inline blkid_parttable test_blkid_partlist_get_table(__cbm_unused__ blkid_partlist ls) 135 | { 136 | /* Return a "valid" partition table */ 137 | return CBM_BLKID_PARTTABLE_SET; 138 | } 139 | 140 | static inline const char *test_blkid_parttable_get_type(__cbm_unused__ blkid_parttable tab) 141 | { 142 | /* Return correct gpt identifier */ 143 | return "gpt"; 144 | } 145 | 146 | /** 147 | * Default vtable for testing. Copy into a local struct and override specific 148 | * fields. 149 | */ 150 | CbmBlkidOps BlkidTestOps = { 151 | .probe_new_from_filename = test_blkid_new_probe_from_filename, 152 | .probe_enable_superblocks = test_blkid_probe_enable_superblocks, 153 | .probe_set_superblocks_flags = test_blkid_probe_set_superblocks_flags, 154 | .probe_enable_partitions = test_blkid_probe_enable_partitions, 155 | .probe_set_partitions_flags = test_blkid_probe_set_partitions_flags, 156 | .probe_get_wholedisk_devno = test_blkid_probe_get_wholedisk_devno, 157 | .probe_lookup_value = test_blkid_probe_lookup_value, 158 | .do_safeprobe = test_blkid_do_safeprobe, 159 | .free_probe = test_blkid_free_probe, 160 | 161 | /* Partition functions */ 162 | .probe_get_partitions = test_blkid_probe_get_partitions, 163 | .partlist_numof_partitions = test_blkid_partlist_numof_partitions, 164 | .partlist_get_partition = test_blkid_partlist_get_partition, 165 | .partition_get_flags = test_blkid_partition_get_flags, 166 | .partition_get_uuid = test_blkid_partition_get_uuid, 167 | 168 | /* Partition table functions */ 169 | .partlist_get_table = test_blkid_partlist_get_table, 170 | .parttable_get_type = test_blkid_parttable_get_type, 171 | 172 | /* Misc */ 173 | .devno_to_wholedisk = test_blkid_devno_to_wholedisk, 174 | .devno_to_devname = test_blkid_devno_to_devname, 175 | }; 176 | 177 | /* 178 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 179 | * 180 | * Local variables: 181 | * c-basic-offset: 8 182 | * tab-width: 8 183 | * indent-tabs-mode: nil 184 | * End: 185 | * 186 | * vi: set shiftwidth=8 tabstop=8 expandtab: 187 | * :indentSize=8:tabSize=8:noTabs=true: 188 | */ 189 | -------------------------------------------------------------------------------- /tests/check-cmdline.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | #include 14 | #include 15 | #include 16 | 17 | #include "cmdline.h" 18 | #include "log.h" 19 | #include "util.h" 20 | 21 | START_TEST(cbm_cmdline_test_comments) 22 | { 23 | const char *file = TOP_DIR "/tests/data/cmdline/comments"; 24 | autofree(char) *p = NULL; 25 | 26 | p = cbm_parse_cmdline_file(file); 27 | fail_if(!p, "Failed to parse cmdline file"); 28 | fail_if(!streq(p, "init=/bin/bash"), "Comments file does not match"); 29 | } 30 | END_TEST 31 | 32 | START_TEST(cbm_cmdline_test_mangledmess) 33 | { 34 | const char *file = TOP_DIR "/tests/data/cmdline/mangledmess"; 35 | autofree(char) *p = NULL; 36 | 37 | p = cbm_parse_cmdline_file(file); 38 | fail_if(!p, "Failed to parse cmdline file"); 39 | fail_if(!streq(p, "init=/bin/bash rw i8042.nomux thing=off"), 40 | "Mangled file does not match"); 41 | } 42 | END_TEST 43 | 44 | START_TEST(cbm_cmdline_test_multi) 45 | { 46 | const char *file = TOP_DIR "/tests/data/cmdline/multi"; 47 | autofree(char) *p = NULL; 48 | 49 | p = cbm_parse_cmdline_file(file); 50 | fail_if(!p, "Failed to parse cmdline file"); 51 | fail_if(!streq(p, "one two three"), "Multi file does not match"); 52 | } 53 | END_TEST 54 | 55 | START_TEST(cbm_cmdline_test_oneline) 56 | { 57 | const char *file = TOP_DIR "/tests/data/cmdline/oneline"; 58 | 59 | autofree(char) *p = NULL; 60 | 61 | p = cbm_parse_cmdline_file(file); 62 | fail_if(!p, "Failed to parse cmdline file"); 63 | fail_if(!streq(p, "a single line command line file"), "Single file does not match"); 64 | } 65 | END_TEST 66 | 67 | START_TEST(cbm_cmdline_test_dirs) 68 | { 69 | const char *dir = TOP_DIR "/tests/data"; 70 | 71 | autofree(char) *p = NULL; 72 | 73 | p = cbm_parse_cmdline_files(dir); 74 | fail_if(!p, "Failed to parse cmdline dirs"); 75 | fail_if(!streq(p, "this is an example of split cmdline handling"), 76 | "cmdline dirs does not match"); 77 | } 78 | END_TEST 79 | 80 | START_TEST(cbm_cmdline_test_dirs_vendor_only) 81 | { 82 | const char *dir = TOP_DIR "/tests/data/cmdline_vendor_only"; 83 | 84 | autofree(char) *p = NULL; 85 | 86 | p = cbm_parse_cmdline_files(dir); 87 | fail_if(!p, "Failed to parse cmdline dirs"); 88 | fail_if(!streq(p, "this is an example of vendor only cmdline handling"), 89 | "cmdline dirs does not match"); 90 | } 91 | END_TEST 92 | 93 | START_TEST(cbm_cmdline_test_dirs_vendor_merged) 94 | { 95 | const char *dir = TOP_DIR "/tests/data/cmdline_vendor_merged"; 96 | 97 | autofree(char) *p = NULL; 98 | 99 | p = cbm_parse_cmdline_files(dir); 100 | fail_if(!p, "Failed to parse cmdline dirs"); 101 | fail_if(!streq(p, 102 | "this goes before /etc/ and this one goes last. :) " 103 | "overridden with mask"), 104 | "cmdline dirs does not match"); 105 | } 106 | END_TEST 107 | 108 | START_TEST(cbm_cmdline_test_delete_middle) 109 | { 110 | const char *dir = TOP_DIR "/tests/data/cmdline_delete_middle"; 111 | const char *cmdline = "pre init=/bin/bash foobar rw i8042.nomux thing=off one two three a single line command line file post\n"; 112 | 113 | autofree(char) *p = strdup(cmdline); 114 | 115 | cbm_parse_cmdline_removal_files_directory(dir, p); 116 | fail_if(!streq(p, "pre post"), "Delete middle file does not match"); 117 | } 118 | END_TEST 119 | 120 | START_TEST(cbm_cmdline_test_delete_ends) 121 | { 122 | const char *dir = TOP_DIR "/tests/data/cmdline_delete_ends"; 123 | const char *cmdline = "one two three four\n"; 124 | 125 | autofree(char) *p = strdup(cmdline); 126 | 127 | cbm_parse_cmdline_removal_files_directory(dir, p); 128 | fail_if(!streq(p, "two three "), "Delete ends does not match"); 129 | } 130 | END_TEST 131 | 132 | START_TEST(cbm_cmdline_test_delete_all) 133 | { 134 | const char *dir = TOP_DIR "/tests/data/cmdline_delete_all"; 135 | const char *cmdline = "init=/bin/bash foobar rw i8042.nomux thing=off one two three a single line command line file\n"; 136 | 137 | autofree(char) *p = strdup(cmdline); 138 | 139 | cbm_parse_cmdline_removal_files_directory(dir, p); 140 | fail_if(!streq(p, ""), "Delete all cmdline does not match"); 141 | } 142 | END_TEST 143 | 144 | static Suite *core_suite(void) 145 | { 146 | Suite *s = NULL; 147 | TCase *tc = NULL; 148 | 149 | s = suite_create("cbm_cmdline"); 150 | tc = tcase_create("cbm_cmdline_functions"); 151 | tcase_add_test(tc, cbm_cmdline_test_comments); 152 | tcase_add_test(tc, cbm_cmdline_test_mangledmess); 153 | tcase_add_test(tc, cbm_cmdline_test_multi); 154 | tcase_add_test(tc, cbm_cmdline_test_oneline); 155 | tcase_add_test(tc, cbm_cmdline_test_dirs); 156 | tcase_add_test(tc, cbm_cmdline_test_dirs_vendor_only); 157 | tcase_add_test(tc, cbm_cmdline_test_dirs_vendor_merged); 158 | tcase_add_test(tc, cbm_cmdline_test_delete_middle); 159 | tcase_add_test(tc, cbm_cmdline_test_delete_ends); 160 | tcase_add_test(tc, cbm_cmdline_test_delete_all); 161 | suite_add_tcase(s, tc); 162 | 163 | return s; 164 | } 165 | 166 | int main(void) 167 | { 168 | Suite *s; 169 | SRunner *sr; 170 | int fail; 171 | 172 | /* Ensure that logging is set up properly. */ 173 | setenv("CBM_DEBUG", "1", 1); 174 | cbm_log_init(stderr); 175 | 176 | /* Turn off the EFI variable manipulation. */ 177 | setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); 178 | 179 | s = core_suite(); 180 | sr = srunner_create(s); 181 | srunner_run_all(sr, CK_VERBOSE); 182 | fail = srunner_ntests_failed(sr); 183 | srunner_free(sr); 184 | 185 | if (fail > 0) { 186 | return EXIT_FAILURE; 187 | } 188 | 189 | return EXIT_SUCCESS; 190 | } 191 | 192 | /* 193 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 194 | * 195 | * Local variables: 196 | * c-basic-offset: 8 197 | * tab-width: 8 198 | * indent-tabs-mode: nil 199 | * End: 200 | * 201 | * vi: set shiftwidth=8 tabstop=8 expandtab: 202 | * :indentSize=8:tabSize=8:noTabs=true: 203 | */ 204 | -------------------------------------------------------------------------------- /tests/check-files.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "util.h" 20 | 21 | #include "files.h" 22 | #include "harness.h" 23 | #include "log.h" 24 | #include "nica/files.h" 25 | #include "system-harness.h" 26 | 27 | START_TEST(bootman_match_test) 28 | { 29 | const char *source_match = TOP_DIR "/tests/data/match"; 30 | const char *good_match = TOP_DIR "/tests/data/match1"; 31 | const char *bad_match_data = TOP_DIR "/tests/data/nomatch1"; 32 | const char *bad_match_len = TOP_DIR "/tests/data/nomatch2"; 33 | /* In a clean environment, anyway. */ 34 | const char *non_exist_path = "PATHTHATWONT@EXIST!"; 35 | 36 | /* Known good */ 37 | fail_if(!cbm_files_match(source_match, good_match), "Known matches failed to match"); 38 | 39 | /* Known different data */ 40 | fail_if(cbm_files_match(source_match, bad_match_data), 41 | "Shouldn't match files with different data"); 42 | 43 | /* Known different data + length */ 44 | fail_if(cbm_files_match(source_match, bad_match_len), 45 | "Shouldn't match files with different length"); 46 | 47 | /* Known missing target, with source present */ 48 | fail_if(cbm_files_match(source_match, non_exist_path), 49 | "Shouldn't match with non existent target"); 50 | 51 | /* Known missing source with existing target */ 52 | fail_if(cbm_files_match(non_exist_path, source_match), 53 | "Shouldn't match with non existent source"); 54 | 55 | /* Known missing both */ 56 | fail_if(cbm_files_match(non_exist_path, non_exist_path), 57 | "Shouldn't match non existent files"); 58 | } 59 | END_TEST 60 | 61 | START_TEST(bootman_find_boot) 62 | { 63 | set_test_system_uefi(); 64 | 65 | autofree(char) *boot = NULL; 66 | 67 | boot = get_boot_device(); 68 | fail_if(!boot, "Unable to determine a boot device"); 69 | } 70 | END_TEST 71 | 72 | START_TEST(bootman_mount_test) 73 | { 74 | if (!nc_file_exists("/proc/self/mounts")) { 75 | LOG_INFO("Skipping mount test as /proc/self/mounts is absent"); 76 | return; 77 | } 78 | fail_if(!cbm_is_mounted("/"), "Apparently / not mounted. Question physics."); 79 | fail_if(cbm_is_mounted("/,^roflcopter"), 80 | "Non-existent path mounted. Or you have a genuinely weird path"); 81 | } 82 | END_TEST 83 | 84 | static Suite *core_suite(void) 85 | { 86 | Suite *s = NULL; 87 | TCase *tc = NULL; 88 | 89 | s = suite_create("bootman_files"); 90 | tc = tcase_create("bootman_files"); 91 | tcase_add_test(tc, bootman_match_test); 92 | tcase_add_test(tc, bootman_mount_test); 93 | tcase_add_test(tc, bootman_find_boot); 94 | suite_add_tcase(s, tc); 95 | 96 | return s; 97 | } 98 | 99 | int main(void) 100 | { 101 | Suite *s; 102 | SRunner *sr; 103 | int fail; 104 | 105 | /* syncing can be problematic during test suite runs */ 106 | cbm_set_sync_filesystems(false); 107 | cbm_system_set_vtable(&SystemTestOps); 108 | 109 | /* Ensure that logging is set up properly. */ 110 | setenv("CBM_DEBUG", "1", 1); 111 | cbm_log_init(stderr); 112 | 113 | /* Turn off the EFI variable manipulation. */ 114 | setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); 115 | 116 | s = core_suite(); 117 | sr = srunner_create(s); 118 | srunner_run_all(sr, CK_VERBOSE); 119 | fail = srunner_ntests_failed(sr); 120 | srunner_free(sr); 121 | 122 | if (fail > 0) { 123 | return EXIT_FAILURE; 124 | } 125 | 126 | return EXIT_SUCCESS; 127 | } 128 | 129 | /* 130 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 131 | * 132 | * Local variables: 133 | * c-basic-offset: 8 134 | * tab-width: 8 135 | * indent-tabs-mode: nil 136 | * End: 137 | * 138 | * vi: set shiftwidth=8 tabstop=8 expandtab: 139 | * :indentSize=8:tabSize=8:noTabs=true: 140 | */ 141 | -------------------------------------------------------------------------------- /tests/check-os-release.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #define _GNU_SOURCE 13 | #include 14 | #include 15 | #include 16 | 17 | #include "log.h" 18 | #include "os-release.h" 19 | 20 | START_TEST(cbm_os_release_test_quoted) 21 | { 22 | const char *quote_file = TOP_DIR "/tests/data/solus.os-release"; 23 | autofree(CbmOsRelease) *os_release = NULL; 24 | 25 | os_release = cbm_os_release_new(quote_file); 26 | fail_if(!os_release, "Failed to parse os-release file"); 27 | 28 | fail_if(!streq(cbm_os_release_get_value(os_release, OS_RELEASE_NAME), "Solus"), 29 | "Invalid os-release name"); 30 | fail_if(!streq(cbm_os_release_get_value(os_release, OS_RELEASE_ID), "solus"), 31 | "Invalid os-release ID"); 32 | } 33 | END_TEST 34 | 35 | START_TEST(cbm_os_release_test_unquoted) 36 | { 37 | const char *quote_file = TOP_DIR "/tests/data/clear.os-release"; 38 | autofree(CbmOsRelease) *os_release = NULL; 39 | 40 | os_release = cbm_os_release_new(quote_file); 41 | fail_if(!os_release, "Failed to parse os-release file"); 42 | 43 | fail_if(!streq(cbm_os_release_get_value(os_release, OS_RELEASE_NAME), 44 | "Clear Linux Software for Intel Architecture"), 45 | "Invalid os-release name"); 46 | 47 | fail_if(!streq(cbm_os_release_get_value(os_release, OS_RELEASE_ID), "clear-linux-os"), 48 | "Invalid os-release ID"); 49 | } 50 | END_TEST 51 | 52 | static Suite *core_suite(void) 53 | { 54 | Suite *s = NULL; 55 | TCase *tc = NULL; 56 | 57 | s = suite_create("cbm_os_release"); 58 | tc = tcase_create("cbm_os_release_functions"); 59 | tcase_add_test(tc, cbm_os_release_test_quoted); 60 | tcase_add_test(tc, cbm_os_release_test_unquoted); 61 | suite_add_tcase(s, tc); 62 | 63 | return s; 64 | } 65 | 66 | int main(void) 67 | { 68 | Suite *s; 69 | SRunner *sr; 70 | int fail; 71 | 72 | /* Ensure that logging is set up properly. */ 73 | setenv("CBM_DEBUG", "1", 1); 74 | cbm_log_init(stderr); 75 | 76 | /* Turn off the EFI variable manipulation. */ 77 | setenv("CBM_BOOTVAR_TEST_MODE", "yes", 1); 78 | 79 | s = core_suite(); 80 | sr = srunner_create(s); 81 | srunner_run_all(sr, CK_VERBOSE); 82 | fail = srunner_ntests_failed(sr); 83 | srunner_free(sr); 84 | 85 | if (fail > 0) { 86 | return EXIT_FAILURE; 87 | } 88 | 89 | return EXIT_SUCCESS; 90 | } 91 | 92 | /* 93 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 94 | * 95 | * Local variables: 96 | * c-basic-offset: 8 97 | * tab-width: 8 98 | * indent-tabs-mode: nil 99 | * End: 100 | * 101 | * vi: set shiftwidth=8 tabstop=8 expandtab: 102 | * :indentSize=8:tabSize=8:noTabs=true: 103 | */ 104 | -------------------------------------------------------------------------------- /tests/data/blobfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clearlinux/clr-boot-manager/86c739ceda5f23f951f0c74f16bfba43680d6fbd/tests/data/blobfile -------------------------------------------------------------------------------- /tests/data/clear.os-release: -------------------------------------------------------------------------------- 1 | NAME="Clear Linux Software for Intel Architecture" 2 | VERSION=1 3 | ID=clear-linux-os 4 | VERSION_ID=10100 5 | PRETTY_NAME="Clear Linux Software for Intel Architecture" 6 | ANSI_COLOR="1;35" 7 | HOME_URL="https://clearlinux.org" 8 | SUPPORT_URL="https://clearlinux.org" 9 | BUG_REPORT_URL="https://bugs.clearlinux.org/jira" 10 | -------------------------------------------------------------------------------- /tests/data/cmdline/comments: -------------------------------------------------------------------------------- 1 | # This file 2 | init=/bin/bash 3 | # has comments! 4 | -------------------------------------------------------------------------------- /tests/data/cmdline/mangledmess: -------------------------------------------------------------------------------- 1 | init=/bin/bash 2 | # Some things may 3 | rw 4 | # Follow! 5 | i8042.nomux thing=off 6 | -------------------------------------------------------------------------------- /tests/data/cmdline/multi: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | -------------------------------------------------------------------------------- /tests/data/cmdline/oneline: -------------------------------------------------------------------------------- 1 | a single line command line file 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_all/etc/kernel/cmdline-removal.d/comments.conf: -------------------------------------------------------------------------------- 1 | # This file 2 | init=/bin/bash 3 | # has comments! 4 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_all/etc/kernel/cmdline-removal.d/mangledmess.conf: -------------------------------------------------------------------------------- 1 | foobar 2 | # Some things may 3 | rw 4 | # Follow! 5 | i8042.nomux thing=off 6 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_all/etc/kernel/cmdline-removal.d/multi.conf: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_all/etc/kernel/cmdline-removal.d/oneline.conf: -------------------------------------------------------------------------------- 1 | a single line command line file 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_all/usr/share/kernel/cmdline.d/full.conf: -------------------------------------------------------------------------------- 1 | init=/bin/bash foobar rw i8042.nomux thing=off one two three a single line command line file 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_ends/etc/kernel/cmdline-removal.d/ends.conf: -------------------------------------------------------------------------------- 1 | one 2 | four 3 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_ends/usr/share/kernel/cmdline.d/full.conf: -------------------------------------------------------------------------------- 1 | one two three four 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_middle/etc/kernel/cmdline-removal.d/comments.conf: -------------------------------------------------------------------------------- 1 | # This file 2 | init=/bin/bash 3 | # has comments! 4 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_middle/etc/kernel/cmdline-removal.d/mangledmess.conf: -------------------------------------------------------------------------------- 1 | foobar 2 | # Some things may 3 | rw 4 | # Follow! 5 | i8042.nomux thing=off 6 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_middle/etc/kernel/cmdline-removal.d/multi.conf: -------------------------------------------------------------------------------- 1 | one 2 | two 3 | three 4 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_middle/etc/kernel/cmdline-removal.d/oneline.conf: -------------------------------------------------------------------------------- 1 | a single line command line file 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_delete_middle/usr/share/kernel/cmdline.d/full.conf: -------------------------------------------------------------------------------- 1 | pre init=/bin/bash foobar rw i8042.nomux thing=off one two three a single line command line file post 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/etc/kernel/cmdline: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/10_local_first.conf: -------------------------------------------------------------------------------- 1 | and this one 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/20_local_second.conf: -------------------------------------------------------------------------------- 1 | goes 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/30_local_third.conf: -------------------------------------------------------------------------------- 1 | last. :) 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/etc/kernel/cmdline.d/40_masked.conf: -------------------------------------------------------------------------------- 1 | overridden with mask 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_empty.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clearlinux/clr-boot-manager/86c739ceda5f23f951f0c74f16bfba43680d6fbd/tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_empty.conf -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/00_newline.conf: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/10_first.conf: -------------------------------------------------------------------------------- 1 | this 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/20_second.conf: -------------------------------------------------------------------------------- 1 | goes 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/30_third.conf: -------------------------------------------------------------------------------- 1 | before /etc/ 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_merged/usr/share/kernel/cmdline.d/40_masked.conf: -------------------------------------------------------------------------------- 1 | My text will never be seen 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/10_first.conf: -------------------------------------------------------------------------------- 1 | this is an 2 | # comment 3 | example 4 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/20_second.conf: -------------------------------------------------------------------------------- 1 | of vendor only 2 | -------------------------------------------------------------------------------- /tests/data/cmdline_vendor_only/usr/share/kernel/cmdline.d/30_third.conf: -------------------------------------------------------------------------------- 1 | cmdline 2 | # Awesomeness. 3 | handling -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline: -------------------------------------------------------------------------------- 1 | this 2 | -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline.d/00_empty.conf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/clearlinux/clr-boot-manager/86c739ceda5f23f951f0c74f16bfba43680d6fbd/tests/data/etc/kernel/cmdline.d/00_empty.conf -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline.d/00_newline.conf: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline.d/10_first.conf: -------------------------------------------------------------------------------- 1 | is an 2 | # comment 3 | example -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline.d/20_second.conf: -------------------------------------------------------------------------------- 1 | of split -------------------------------------------------------------------------------- /tests/data/etc/kernel/cmdline.d/30_third.conf: -------------------------------------------------------------------------------- 1 | cmdline 2 | # Awesomeness. 3 | handling -------------------------------------------------------------------------------- /tests/data/gptmbr.bin: -------------------------------------------------------------------------------- 1 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -------------------------------------------------------------------------------- /tests/data/gptmbr.bin.v2: -------------------------------------------------------------------------------- 1 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb -------------------------------------------------------------------------------- /tests/data/match: -------------------------------------------------------------------------------- 1 | This file is for matching. 2 | -------------------------------------------------------------------------------- /tests/data/match1: -------------------------------------------------------------------------------- 1 | This file is for matching. 2 | -------------------------------------------------------------------------------- /tests/data/nomatch1: -------------------------------------------------------------------------------- 1 | This file is for matching! 2 | -------------------------------------------------------------------------------- /tests/data/nomatch2: -------------------------------------------------------------------------------- 1 | This file is for matching. It differs in length 2 | -------------------------------------------------------------------------------- /tests/data/solus.os-release: -------------------------------------------------------------------------------- 1 | NAME="Solus" 2 | VERSION="2017.01.01.0" 3 | ID="solus" 4 | VERSION_ID="2017.01.01.0" 5 | PRETTY_NAME="Solus 2017.01.01.0" 6 | ANSI_COLOR="1;34" 7 | HOME_URL="https://www.solus-project.com" 8 | SUPPORT_URL="https://www.solus-project.com/forums/" 9 | BUG_REPORT_URL="https://dev.solus-project.com/" 10 | 11 | = 12 | =rofl 13 | 14 | = 15 | 16 | = 17 | -------------------------------------------------------------------------------- /tests/harness.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include 15 | #include 16 | 17 | #include "bootman.h" 18 | 19 | /** 20 | * Needed for intiialisation 21 | */ 22 | typedef struct PlaygroundKernel { 23 | const char *version; 24 | const char *ktype; 25 | int release; 26 | bool default_for_type; 27 | bool legacy_name; /**.efi) 88 | */ 89 | bool confirm_bootloader_match(bool check_default); 90 | 91 | /** 92 | * Assert that the kernel is fully installed 93 | */ 94 | bool confirm_kernel_installed(BootManager *manager, PlaygroundConfig *config, 95 | PlaygroundKernel *kernel); 96 | 97 | /** 98 | * Assert that the kernel is fully uninstalled 99 | */ 100 | bool confirm_kernel_uninstalled(BootManager *manager, PlaygroundKernel *kernel); 101 | 102 | /** 103 | * Create boot_timeout.conf in /etc 104 | */ 105 | bool create_timeout_conf(void); 106 | 107 | /** 108 | * Set up the test harness to emulate UEFI 109 | */ 110 | void set_test_system_uefi(void); 111 | 112 | /** 113 | * Set up the test harness to emulate legacy boot 114 | */ 115 | void set_test_system_legacy(void); 116 | 117 | /** 118 | * Check initrd nodeps in BootManager 119 | */ 120 | bool check_freestanding_initrds_available(BootManager *manager, const char *file_name); 121 | 122 | /** 123 | * Check if initrd file exist 124 | */ 125 | bool check_initrd_file_exist(BootManager *manager, const char *file_name); 126 | /* 127 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 128 | * 129 | * Local variables: 130 | * c-basic-offset: 8 131 | * tab-width: 8 132 | * indent-tabs-mode: nil 133 | * End: 134 | * 135 | * vi: set shiftwidth=8 tabstop=8 expandtab: 136 | * :indentSize=8:tabSize=8:noTabs=true: 137 | */ 138 | -------------------------------------------------------------------------------- /tests/meson.build: -------------------------------------------------------------------------------- 1 | # Each test must follow the convention: check-$name.c, i.e. "check-os-release.c" 2 | desired_tests = [ 3 | 'cmdline', 4 | 'core', 5 | 'grub2', 6 | 'legacy', 7 | 'os-release', 8 | 'probe', 9 | 'select-bootloader', 10 | 'syslinux', 11 | 'uefi', 12 | ] 13 | 14 | test_dependencies = [ 15 | link_libcbm, 16 | libcbm_dependencies, 17 | dep_check, 18 | ] 19 | 20 | # Shared sources between each test run 21 | libtest_sources = [ 22 | 'harness.c', 23 | ] 24 | 25 | # Create a new executable for every given test in desired_tests 26 | foreach test_name : desired_tests 27 | tmp_exec = executable( 28 | 'test-@0@'.format(test_name), 29 | sources: [ 30 | 'check-@0@.c'.format(test_name), 31 | ] + libtest_sources, 32 | dependencies: [ 33 | test_dependencies, 34 | ], 35 | c_args: [ 36 | '-DTOP_BUILD_DIR="@0@/root/test-root-@1@"'.format(meson.current_build_dir(), test_name), 37 | '-DTOP_DIR="@0@"'.format(test_top_dir), 38 | ], 39 | install: false, 40 | ) 41 | test(test_name, tmp_exec) 42 | endforeach 43 | -------------------------------------------------------------------------------- /tests/system-harness.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of clr-boot-manager. 3 | * 4 | * Copyright © 2016-2018 Intel Corporation 5 | * 6 | * clr-boot-manager is free software; you can redistribute it and/or 7 | * modify it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation; either version 2.1 9 | * of the License, or (at your option) any later version. 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "system_stub.h" 15 | 16 | static inline int test_mount(__cbm_unused__ const char *source, __cbm_unused__ const char *target, 17 | __cbm_unused__ const char *filesystemtype, 18 | __cbm_unused__ unsigned long mountflags, 19 | __cbm_unused__ const void *data) 20 | { 21 | return 0; 22 | } 23 | 24 | static inline int test_umount(__cbm_unused__ const char *target) 25 | { 26 | return 0; 27 | } 28 | 29 | static inline int test_system(__cbm_unused__ const char *command) 30 | { 31 | return 0; 32 | } 33 | 34 | static inline bool test_is_mounted(__cbm_unused__ const char *target) 35 | { 36 | return false; 37 | } 38 | 39 | static inline char *test_get_mountpoint_for_device(__cbm_unused__ const char *device) 40 | { 41 | return NULL; 42 | } 43 | 44 | static inline char *test_get_device_for_mountpoint(__cbm_unused__ const char *device) 45 | { 46 | return string_printf("%s/dev/testRoot", TOP_BUILD_DIR "/tests/update_playground"); 47 | } 48 | 49 | static inline char *test_devnode_to_devpath(__cbm_unused__ dev_t d) 50 | { 51 | return test_get_device_for_mountpoint(NULL); 52 | } 53 | 54 | static inline const char *test_get_sysfs_path(void) 55 | { 56 | return TOP_BUILD_DIR "/tests/update_playground/sys"; 57 | } 58 | 59 | static const char *test_get_devfs_path(void) 60 | { 61 | return TOP_BUILD_DIR "/tests/update_playground/dev"; 62 | } 63 | 64 | /** 65 | * Default vtable for testing. Copy into a local struct and override specific 66 | * fields. 67 | */ 68 | CbmSystemOps SystemTestOps = { 69 | .mount = test_mount, 70 | .umount = test_umount, 71 | .system = test_system, 72 | .is_mounted = test_is_mounted, 73 | .get_mountpoint_for_device = test_get_mountpoint_for_device, 74 | .get_device_for_mountpoint = test_get_device_for_mountpoint, 75 | .devnode_to_devpath = test_devnode_to_devpath, 76 | .get_sysfs_path = test_get_sysfs_path, 77 | .get_devfs_path = test_get_devfs_path, 78 | }; 79 | 80 | /* 81 | * Editor modelines - https://www.wireshark.org/tools/modelines.html 82 | * 83 | * Local variables: 84 | * c-basic-offset: 8 85 | * tab-width: 8 86 | * indent-tabs-mode: nil 87 | * End: 88 | * 89 | * vi: set shiftwidth=8 tabstop=8 expandtab: 90 | * :indentSize=8:tabSize=8:noTabs=true: 91 | */ 92 | --------------------------------------------------------------------------------