crypt_reboot 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +3 -0
- data/LICENSE.txt +21 -0
- data/README.md +169 -0
- data/exe/cryptreboot +9 -0
- data/lib/basic_loader.rb +60 -0
- data/lib/crypt_reboot/boot_config.rb +24 -0
- data/lib/crypt_reboot/cli/exiter.rb +25 -0
- data/lib/crypt_reboot/cli/happy_exiter.rb +14 -0
- data/lib/crypt_reboot/cli/params/definition.rb +125 -0
- data/lib/crypt_reboot/cli/params/flattener.rb +24 -0
- data/lib/crypt_reboot/cli/params/help_generator.rb +22 -0
- data/lib/crypt_reboot/cli/params/parser.rb +29 -0
- data/lib/crypt_reboot/cli/params_parsing_executor.rb +73 -0
- data/lib/crypt_reboot/cli/sad_exiter.rb +14 -0
- data/lib/crypt_reboot/cli.rb +8 -0
- data/lib/crypt_reboot/concatenator.rb +24 -0
- data/lib/crypt_reboot/config.rb +20 -0
- data/lib/crypt_reboot/crypt_tab/deserializer.rb +28 -0
- data/lib/crypt_reboot/crypt_tab/entry.rb +39 -0
- data/lib/crypt_reboot/crypt_tab/entry_deserializer.rb +51 -0
- data/lib/crypt_reboot/crypt_tab/entry_serializer.rb +21 -0
- data/lib/crypt_reboot/crypt_tab/keyfile_locator.rb +21 -0
- data/lib/crypt_reboot/crypt_tab/luks_to_plain_converter.rb +39 -0
- data/lib/crypt_reboot/crypt_tab/serializer.rb +29 -0
- data/lib/crypt_reboot/files_generator.rb +44 -0
- data/lib/crypt_reboot/files_writer.rb +17 -0
- data/lib/crypt_reboot/gziper.rb +22 -0
- data/lib/crypt_reboot/initramfs/archiver.rb +35 -0
- data/lib/crypt_reboot/initramfs/decompressor/intolerant_decompressor.rb +65 -0
- data/lib/crypt_reboot/initramfs/decompressor/tolerant_decompressor.rb +28 -0
- data/lib/crypt_reboot/initramfs/decompressor.rb +12 -0
- data/lib/crypt_reboot/initramfs/extractor.rb +36 -0
- data/lib/crypt_reboot/initramfs/patcher.rb +47 -0
- data/lib/crypt_reboot/initramfs_patch_squeezer.rb +28 -0
- data/lib/crypt_reboot/instantiable_config.rb +52 -0
- data/lib/crypt_reboot/kexec/loader.rb +30 -0
- data/lib/crypt_reboot/kexec_patching_loader.rb +28 -0
- data/lib/crypt_reboot/lazy_config.rb +22 -0
- data/lib/crypt_reboot/luks/checker.rb +27 -0
- data/lib/crypt_reboot/luks/data.rb +37 -0
- data/lib/crypt_reboot/luks/data_fetcher.rb +30 -0
- data/lib/crypt_reboot/luks/dumper/luks_v1_parser.rb +64 -0
- data/lib/crypt_reboot/luks/dumper/luks_v2_parser.rb +62 -0
- data/lib/crypt_reboot/luks/dumper.rb +30 -0
- data/lib/crypt_reboot/luks/key_fetcher.rb +50 -0
- data/lib/crypt_reboot/luks/version_detector.rb +32 -0
- data/lib/crypt_reboot/passphrase_asker.rb +15 -0
- data/lib/crypt_reboot/patched_initramfs_generator.rb +21 -0
- data/lib/crypt_reboot/rebooter.rb +20 -0
- data/lib/crypt_reboot/runner/binary.rb +12 -0
- data/lib/crypt_reboot/runner/boolean.rb +18 -0
- data/lib/crypt_reboot/runner/generic.rb +46 -0
- data/lib/crypt_reboot/runner/lines.rb +13 -0
- data/lib/crypt_reboot/runner/no_result.rb +13 -0
- data/lib/crypt_reboot/runner/text.rb +12 -0
- data/lib/crypt_reboot/runner.rb +8 -0
- data/lib/crypt_reboot/safe_temp/directory.rb +28 -0
- data/lib/crypt_reboot/safe_temp/file_name.rb +23 -0
- data/lib/crypt_reboot/safe_temp/mounter.rb +33 -0
- data/lib/crypt_reboot/single_assign_restricted_map.rb +26 -0
- data/lib/crypt_reboot/version.rb +5 -0
- data/lib/crypt_reboot.rb +17 -0
- metadata +138 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 449c9b12be881f213dffc9090686e7d73bb3f2523806c5edf41dc2e4d7d17c4b
|
4
|
+
data.tar.gz: ba391871d8d5f438ba2474a8a21d8738be020636ac8c4bfcd0fd8100d7e07aec
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 466befee2a5027cae8be7cb036c87e8c779e64fb4725775111b112e53ff5bf2691bc543ac86e7c229e8e75642c0c3eb0168fed1bca14a2b0598b94bf3c5245c0
|
7
|
+
data.tar.gz: 68bef507bea7444722f3281b94d8ea5af0bda0d031871f82fc9ff0398614e7b83564f2b541a42d745d2eefecde9f0a409817dcd29332b01797cd13b434bd7db0
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2023 Paweł Pokrywka
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
# Cryptreboot
|
2
|
+
|
3
|
+
Convenient reboot for Linux systems with encrypted root partition.
|
4
|
+
|
5
|
+
> Just type `cryptreboot` instead of `reboot`.
|
6
|
+
|
7
|
+
It asks for a passphrase and reboots the system afterward, automatically
|
8
|
+
unlocking the drive on startup using in-memory initramfs patching and kexec.
|
9
|
+
Without explicit consent, no secrets are stored on disk, even temporarily.
|
10
|
+
|
11
|
+
Useful when unlocking the drive at startup is difficult, such as on headless
|
12
|
+
and remote systems.
|
13
|
+
|
14
|
+
By default, it uses the current kernel command line, `/boot/vmlinuz` as kernel
|
15
|
+
and `/boot/initrd.img` as initramfs.
|
16
|
+
|
17
|
+
Will work properly when using standard passphrase-based disk unlocking.
|
18
|
+
Fancy methods such as using an external USB with a passphrase file will fail.
|
19
|
+
|
20
|
+
## Compatible Linux distributions
|
21
|
+
|
22
|
+
Currently, cryptreboot depends on `initramfs-tools` package which is available in
|
23
|
+
Debian-based distributions. Therefore one should expect, this tool to work on
|
24
|
+
Debian, Ubuntu, Linux Mint, Pop!_OS, etc.
|
25
|
+
|
26
|
+
On the other hand, do not expect it to work on other distributions now.
|
27
|
+
But support for them may come in upcoming versions.
|
28
|
+
|
29
|
+
Following distributions were tested by the author:
|
30
|
+
- Ubuntu 22.04 LTS
|
31
|
+
- Ubuntu 20.04 LTS needs tiny adjustments to system settings,
|
32
|
+
specifically [changing compression](#lz4-initramfs-compression) and
|
33
|
+
[fixing systemd kexec support](#staged-kernel-not-being-executed-by-systemd)
|
34
|
+
- ~~Ubuntu 18.04 LTS~~ is not supported (initramfs uses *pre-crypttab* format)
|
35
|
+
- Pop!_OS 22.04 LTS
|
36
|
+
|
37
|
+
If you have successfully run cryptreboot on another distribution,
|
38
|
+
please contact me and I will update the list.
|
39
|
+
|
40
|
+
## Requirements
|
41
|
+
|
42
|
+
You need to ensure those are installed:
|
43
|
+
- `ruby` >= 2.7
|
44
|
+
- `kexec-tools`
|
45
|
+
- `initramfs-tools` (other initramfs generators, such as `dracut` are
|
46
|
+
not supported yet)
|
47
|
+
|
48
|
+
If you use recent, mainstream Linux distribution, other requirements are
|
49
|
+
probably already met:
|
50
|
+
- `kexec` support in the kernel
|
51
|
+
- `tmpfs` filesystem support in kernel
|
52
|
+
- `cryptsetup` (if you use disk encryption, it should be installed)
|
53
|
+
- `systemd` or another way to guarantee staged kernel is executed on reboot
|
54
|
+
- `strace` (not required if `--skip-lz4-check` flag is specified)
|
55
|
+
|
56
|
+
## Installation
|
57
|
+
|
58
|
+
Make sure the required software is installed, then install the gem by executing:
|
59
|
+
|
60
|
+
$ gem install crypt_reboot
|
61
|
+
|
62
|
+
## Usage
|
63
|
+
|
64
|
+
Cryptreboot performs operations normally only available to the root user,
|
65
|
+
so it is suggested to use sudo or a similar utility.
|
66
|
+
|
67
|
+
To perform a reboot type:
|
68
|
+
|
69
|
+
$ sudo cryptreboot
|
70
|
+
|
71
|
+
To see the usage, run:
|
72
|
+
|
73
|
+
$ cryptreboot --help
|
74
|
+
|
75
|
+
## Resolutions for common issues
|
76
|
+
|
77
|
+
### LZ4 initramfs compression
|
78
|
+
|
79
|
+
If you get:
|
80
|
+
|
81
|
+
> LZ4 compression is not allowed, change the compression algorithm in
|
82
|
+
initramfs.conf and regenerate the initramfs image
|
83
|
+
|
84
|
+
it means initramfs was compressed using the LZ4 algorithm, which seems to
|
85
|
+
have issues with concatenating initramfs images.
|
86
|
+
|
87
|
+
In case you are 100% sure LZ4 won't cause problems, you can use
|
88
|
+
`--skip-lz4-check` command line flag. This will make the error message
|
89
|
+
go away, but you risk automatic disk unlocking at startup to fail randomly.
|
90
|
+
|
91
|
+
Instead, the recommended approach is to change the compression algorithm
|
92
|
+
in `/etc/initramfs-tools/initramfs.conf` file. Look for `COMPRESS` and
|
93
|
+
set it to some other value such as `gzip` (the safe choice), or `zstd`
|
94
|
+
(the best compression, but your kernel and `initramfs-tools` need to support it).
|
95
|
+
|
96
|
+
Here is a one-liner to change compression to `gzip`:
|
97
|
+
|
98
|
+
$ sudo sed -iE 's/^\s*COMPRESS=.*$/COMPRESS=gzip/' /etc/initramfs-tools/initramfs.conf
|
99
|
+
|
100
|
+
Then you need to regenerate all of your initramfs images:
|
101
|
+
|
102
|
+
$ sudo update-initramfs -k all -u
|
103
|
+
|
104
|
+
That's it.
|
105
|
+
|
106
|
+
Resources related to the issue:
|
107
|
+
- [Appending files to initramfs image - reliable? (StackExchange)](https://unix.stackexchange.com/a/737219)
|
108
|
+
- [What is the correct frame format for Linux (Lz4 issue)](https://github.com/lz4/lz4/issues/956)
|
109
|
+
- [Initramfs unpacking failed (Ubuntu bug report)](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1835660)
|
110
|
+
|
111
|
+
### Staged kernel not being executed by systemd
|
112
|
+
|
113
|
+
If rebooting with cryptreboot doesn't seem to differ from a standard
|
114
|
+
reboot, it may suggest staged kernel is not being executed by the
|
115
|
+
`systemd` at the end of the shutdown procedure.
|
116
|
+
|
117
|
+
The solution I found is to execute `kexec -e` instead of
|
118
|
+
`systemctl --force kexec` when the system is ready for a reboot.
|
119
|
+
To do that `systemd-kexec.service` has to be modified.
|
120
|
+
To make the change minimal, let's use `systemd drop-in` for that:
|
121
|
+
|
122
|
+
$ sudo mkdir -p /etc/systemd/system/systemd-kexec.service.d/
|
123
|
+
$ echo -e "[Service]\nExecStart=\nExecStart=kexec -e" | sudo tee /etc/systemd/system/systemd-kexec.service.d/override.conf
|
124
|
+
|
125
|
+
That should work.
|
126
|
+
|
127
|
+
To cancel the change, remove the file:
|
128
|
+
|
129
|
+
$ sudo rm /etc/systemd/system/systemd-kexec.service.d/override.conf
|
130
|
+
|
131
|
+
## Development
|
132
|
+
|
133
|
+
After checking out the repo, run `bundle install` to install
|
134
|
+
dependencies. Then, run `rake spec` to run the tests. You can also
|
135
|
+
run `bin/console` for an interactive prompt that will allow you
|
136
|
+
to experiment.
|
137
|
+
|
138
|
+
To build the gem, run `rake build`. To release a new version, update
|
139
|
+
the version number in `version.rb`, and then run `rake release`, which
|
140
|
+
will create a git tag for the version, push git commits and the created
|
141
|
+
tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
142
|
+
|
143
|
+
## Contributing
|
144
|
+
|
145
|
+
Bug reports and pull requests are welcome on GitHub at
|
146
|
+
https://github.com/phantom-node/cryptreboot.
|
147
|
+
This project is intended to be a safe, welcoming space for collaboration,
|
148
|
+
and contributors are expected to adhere to the
|
149
|
+
[code of conduct](https://github.com/phantom-node/cryptreboot/blob/master/CODE_OF_CONDUCT.md).
|
150
|
+
|
151
|
+
## Author
|
152
|
+
|
153
|
+
My name is Paweł Pokrywka and I'm the author of cryptreboot.
|
154
|
+
|
155
|
+
If you want to contact me or get to know me better, check out
|
156
|
+
[my blog](https://blog.pawelpokrywka.com).
|
157
|
+
|
158
|
+
Thank you for your interest in this project :)
|
159
|
+
|
160
|
+
## License
|
161
|
+
|
162
|
+
The software is available as open source under the terms of the
|
163
|
+
[MIT License](https://opensource.org/licenses/MIT).
|
164
|
+
|
165
|
+
## Code of Conduct
|
166
|
+
|
167
|
+
Everyone interacting in the Cryptreboot project's codebases, issue
|
168
|
+
trackers, chat rooms, and mailing lists is expected to follow the
|
169
|
+
[code of conduct](https://github.com/phantom-node/cryptreboot/blob/master/CODE_OF_CONDUCT.md).
|
data/exe/cryptreboot
ADDED
data/lib/basic_loader.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# File generated automatically, do not edit
|
4
|
+
|
5
|
+
require 'crypt_reboot/version'
|
6
|
+
require 'crypt_reboot/boot_config'
|
7
|
+
require 'crypt_reboot/cli'
|
8
|
+
require 'crypt_reboot/concatenator'
|
9
|
+
require 'crypt_reboot/instantiable_config'
|
10
|
+
require 'crypt_reboot/config'
|
11
|
+
require 'crypt_reboot/files_generator'
|
12
|
+
require 'crypt_reboot/files_writer'
|
13
|
+
require 'crypt_reboot/gziper'
|
14
|
+
require 'crypt_reboot/initramfs_patch_squeezer'
|
15
|
+
require 'crypt_reboot/kexec_patching_loader'
|
16
|
+
require 'crypt_reboot/lazy_config'
|
17
|
+
require 'crypt_reboot/passphrase_asker'
|
18
|
+
require 'crypt_reboot/patched_initramfs_generator'
|
19
|
+
require 'crypt_reboot/rebooter'
|
20
|
+
require 'crypt_reboot/runner'
|
21
|
+
require 'crypt_reboot/single_assign_restricted_map'
|
22
|
+
require 'crypt_reboot/cli/exiter'
|
23
|
+
require 'crypt_reboot/cli/happy_exiter'
|
24
|
+
require 'crypt_reboot/cli/params_parsing_executor'
|
25
|
+
require 'crypt_reboot/cli/sad_exiter'
|
26
|
+
require 'crypt_reboot/crypt_tab/deserializer'
|
27
|
+
require 'crypt_reboot/crypt_tab/entry'
|
28
|
+
require 'crypt_reboot/crypt_tab/entry_deserializer'
|
29
|
+
require 'crypt_reboot/crypt_tab/entry_serializer'
|
30
|
+
require 'crypt_reboot/crypt_tab/keyfile_locator'
|
31
|
+
require 'crypt_reboot/crypt_tab/luks_to_plain_converter'
|
32
|
+
require 'crypt_reboot/crypt_tab/serializer'
|
33
|
+
require 'crypt_reboot/initramfs/archiver'
|
34
|
+
require 'crypt_reboot/initramfs/decompressor'
|
35
|
+
require 'crypt_reboot/initramfs/extractor'
|
36
|
+
require 'crypt_reboot/initramfs/patcher'
|
37
|
+
require 'crypt_reboot/kexec/loader'
|
38
|
+
require 'crypt_reboot/luks/checker'
|
39
|
+
require 'crypt_reboot/luks/data'
|
40
|
+
require 'crypt_reboot/luks/data_fetcher'
|
41
|
+
require 'crypt_reboot/luks/dumper'
|
42
|
+
require 'crypt_reboot/luks/key_fetcher'
|
43
|
+
require 'crypt_reboot/luks/version_detector'
|
44
|
+
require 'crypt_reboot/runner/generic'
|
45
|
+
require 'crypt_reboot/runner/binary'
|
46
|
+
require 'crypt_reboot/runner/boolean'
|
47
|
+
require 'crypt_reboot/runner/lines'
|
48
|
+
require 'crypt_reboot/runner/no_result'
|
49
|
+
require 'crypt_reboot/runner/text'
|
50
|
+
require 'crypt_reboot/safe_temp/directory'
|
51
|
+
require 'crypt_reboot/safe_temp/file_name'
|
52
|
+
require 'crypt_reboot/safe_temp/mounter'
|
53
|
+
require 'crypt_reboot/cli/params/definition'
|
54
|
+
require 'crypt_reboot/cli/params/flattener'
|
55
|
+
require 'crypt_reboot/cli/params/help_generator'
|
56
|
+
require 'crypt_reboot/cli/params/parser'
|
57
|
+
require 'crypt_reboot/initramfs/decompressor/intolerant_decompressor'
|
58
|
+
require 'crypt_reboot/initramfs/decompressor/tolerant_decompressor'
|
59
|
+
require 'crypt_reboot/luks/dumper/luks_v1_parser'
|
60
|
+
require 'crypt_reboot/luks/dumper/luks_v2_parser'
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
# Data required for booting
|
5
|
+
class BootConfig
|
6
|
+
attr_reader :kernel, :initramfs, :cmdline
|
7
|
+
|
8
|
+
def ==(other)
|
9
|
+
kernel == other.kernel && initramfs == other.initramfs && cmdline == other.cmdline
|
10
|
+
end
|
11
|
+
|
12
|
+
def with_initramfs(new_initramfs)
|
13
|
+
self.class.new(kernel: kernel, initramfs: new_initramfs, cmdline: cmdline)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def initialize(kernel:, initramfs: nil, cmdline: nil)
|
19
|
+
@kernel = kernel
|
20
|
+
@initramfs = initramfs
|
21
|
+
@cmdline = cmdline
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
# Print a message and return exit status
|
6
|
+
class Exiter
|
7
|
+
attr_reader :text
|
8
|
+
|
9
|
+
def call
|
10
|
+
stream.puts text.strip if text
|
11
|
+
status
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :status, :stream
|
17
|
+
|
18
|
+
def initialize(text, status:, stream:)
|
19
|
+
@text = text
|
20
|
+
@status = status
|
21
|
+
@stream = stream
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'tty-option'
|
4
|
+
|
5
|
+
module CryptReboot
|
6
|
+
module Cli
|
7
|
+
module Params
|
8
|
+
# Definition of options, flags, help and other CLI related things
|
9
|
+
class Definition
|
10
|
+
include TTY::Option
|
11
|
+
|
12
|
+
# rubocop:disable Metrics/BlockLength
|
13
|
+
usage do
|
14
|
+
header 'Reboot for Linux systems with encrypted root partition.'
|
15
|
+
|
16
|
+
program PROGRAM_NAME
|
17
|
+
no_command
|
18
|
+
|
19
|
+
desc 'It asks for a password and reboots the system afterward, automatically unlocking ' \
|
20
|
+
'the drive on startup using in-memory initramfs patching and kexec. ' \
|
21
|
+
'Without explicit consent, no secrets are stored on disk, even temporarily.',
|
22
|
+
'',
|
23
|
+
'Useful when unlocking the drive at startup is difficult, such as on headless and remote systems.',
|
24
|
+
'',
|
25
|
+
"By default, it uses the current kernel command line, \"#{Config.kernel}\" as " \
|
26
|
+
"kernel and \"#{Config.initramfs}\" as initramfs.",
|
27
|
+
'',
|
28
|
+
'It performs operations normally only available to the root user, so it is suggested to use ' \
|
29
|
+
'sudo or a similar utility.'
|
30
|
+
|
31
|
+
example 'Normal usage:',
|
32
|
+
"$ sudo #{PROGRAM_NAME}"
|
33
|
+
example 'Reboot into custom kernel:',
|
34
|
+
"$ sudo #{PROGRAM_NAME} --kernel /boot/vmlinuz.old --initramfs /boot/initrd.old"
|
35
|
+
example 'Specify custom kernel options:',
|
36
|
+
"$ sudo #{PROGRAM_NAME} --cmdline \"root=UUID=d0...a2 ro nomodeset acpi=off\""
|
37
|
+
example 'Prepare to reboot and perform it manually later:',
|
38
|
+
"$ sudo #{PROGRAM_NAME} --prepare-only",
|
39
|
+
'$ sleep 3600 # do anything else in-between',
|
40
|
+
'$ sudo reboot --no-wall --no-wtmp'
|
41
|
+
|
42
|
+
footer 'To report a bug, get support or contribute, please visit the project page:',
|
43
|
+
'https://phantomno.de/cryptreboot',
|
44
|
+
'',
|
45
|
+
"Thank you for using #{PROGRAM_NAME}. Happy rebooting!"
|
46
|
+
end
|
47
|
+
# rubocop:enable Metrics/BlockLength
|
48
|
+
|
49
|
+
option :kernel do
|
50
|
+
long '--kernel path'
|
51
|
+
desc 'Path to the kernel you want to reboot into'
|
52
|
+
default Config.kernel
|
53
|
+
end
|
54
|
+
|
55
|
+
option :initramfs do
|
56
|
+
long '--initramfs path'
|
57
|
+
desc 'Path to the initramfs to be used by loaded kernel'
|
58
|
+
default Config.initramfs
|
59
|
+
end
|
60
|
+
|
61
|
+
option :cmdline do
|
62
|
+
long '--cmdline string'
|
63
|
+
desc 'Command line for loaded kernel; current command line is used if not provided'
|
64
|
+
end
|
65
|
+
|
66
|
+
option :paths do
|
67
|
+
arity :any
|
68
|
+
long '--tool name:path'
|
69
|
+
desc 'Path to given external tool specified by "name". By default, tools are searched in the PATH. ' \
|
70
|
+
'If you want to specify paths for more than 1 tool, use this option multiple times. Tool names: ' \
|
71
|
+
'cat, cpio, cryptsetup, grep, kexec, mount, reboot, strace, umount, unmkinitramfs'
|
72
|
+
convert :map
|
73
|
+
end
|
74
|
+
|
75
|
+
# Flags
|
76
|
+
|
77
|
+
flag :prepare_only do
|
78
|
+
short '-p'
|
79
|
+
long '--prepare-only'
|
80
|
+
desc 'Load kernel and initramfs, but do not reboot'
|
81
|
+
end
|
82
|
+
|
83
|
+
flag :skip_lz4_check do
|
84
|
+
long '--skip-lz4-check'
|
85
|
+
desc 'Do not check if initramfs is compressed with LZ4 algorithm. ' \
|
86
|
+
'If you use different compression and specify this flag, it will make ' \
|
87
|
+
'initramfs extraction much faster. But if your initramfs uses ' \
|
88
|
+
'LZ4 you risk you will need to manually unlock your disk on startup. ' \
|
89
|
+
'See the README file to learn how to change the compression ' \
|
90
|
+
'algorithm to a more robust one.'
|
91
|
+
end
|
92
|
+
|
93
|
+
flag :debug do
|
94
|
+
short '-d'
|
95
|
+
long '--debug'
|
96
|
+
desc 'Print debug messages'
|
97
|
+
end
|
98
|
+
|
99
|
+
option :patch_save_path do
|
100
|
+
long '--save-patch path'
|
101
|
+
desc 'Save initramfs patch to file for debug purposes. ' \
|
102
|
+
'WARNING: it contains encryption keys, you are responsible for ' \
|
103
|
+
'their safe disposal, which may be difficult after the file comes ' \
|
104
|
+
'into contact with the disk. Deleting the file alone may not be enough.'
|
105
|
+
end
|
106
|
+
|
107
|
+
flag :version do
|
108
|
+
short '-v'
|
109
|
+
long '--version'
|
110
|
+
desc 'Print version and exit'
|
111
|
+
end
|
112
|
+
|
113
|
+
flag :help do
|
114
|
+
short '-h'
|
115
|
+
long '--help'
|
116
|
+
desc 'Print this usage and exit'
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
# This class contains code from external source,
|
121
|
+
# do not expose it anywhere outside of the module
|
122
|
+
private_constant :Definition
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Replace given key in params with new keys obtained from its contents with suffixes added
|
7
|
+
class Flattener
|
8
|
+
def call(params)
|
9
|
+
paths = params.fetch(key, {}).transform_keys { |k| :"#{k}#{suffix}" }
|
10
|
+
params.reject { |k, _| k == key }.merge(paths)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :key, :suffix
|
16
|
+
|
17
|
+
def initialize(key:, suffix:)
|
18
|
+
@key = key.to_sym
|
19
|
+
@suffix = suffix
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Returns usage
|
7
|
+
class HelpGenerator
|
8
|
+
def call
|
9
|
+
definition.help(order: ->(params) { params })
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
attr_reader :definition
|
15
|
+
|
16
|
+
def initialize(definition: Definition.new)
|
17
|
+
@definition = definition
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
module Params
|
6
|
+
# Parse given ARGV and return params hash or raise exception with error summary
|
7
|
+
class Parser
|
8
|
+
ParseError = Class.new StandardError
|
9
|
+
|
10
|
+
def call(raw_params)
|
11
|
+
params = definition.parse(raw_params).params
|
12
|
+
raise ParseError, params.errors.summary unless params.valid?
|
13
|
+
|
14
|
+
flattener.call params.to_h
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :definition, :flattener
|
20
|
+
|
21
|
+
def initialize(definition: Definition.new,
|
22
|
+
flattener: Flattener.new(key: 'paths', suffix: '_path'))
|
23
|
+
@definition = definition
|
24
|
+
@flattener = flattener
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
module Cli
|
5
|
+
# Interprets parameters, executes everything and returns callable object
|
6
|
+
class ParamsParsingExecutor
|
7
|
+
def call(raw_params)
|
8
|
+
params = parser.call(raw_params)
|
9
|
+
handle_action_params!(params) or configure_and_exec(params)
|
10
|
+
rescue StandardError => e
|
11
|
+
raise if debug?
|
12
|
+
|
13
|
+
sad_exiter_class.new(error_message(e))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def debug?
|
19
|
+
debug_checker.call
|
20
|
+
end
|
21
|
+
|
22
|
+
def configure_and_exec(params)
|
23
|
+
config_updater.call(**params)
|
24
|
+
loader.call
|
25
|
+
rebooter
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_action_params!(params)
|
29
|
+
return happy_exiter_class.new(help_generator.call) if params[:help]
|
30
|
+
return happy_exiter_class.new(version_string) if params[:version]
|
31
|
+
|
32
|
+
params.reject! { |param_name, _| %i[help version].include? param_name }
|
33
|
+
|
34
|
+
false
|
35
|
+
end
|
36
|
+
|
37
|
+
def exception_name(exception)
|
38
|
+
name = exception.class.name.split('::').last
|
39
|
+
name.gsub(/([a-z\d])([A-Z])/, '\1 \2').capitalize
|
40
|
+
end
|
41
|
+
|
42
|
+
def error_message(exception)
|
43
|
+
"#{exception_name(exception)}: #{exception.message}"
|
44
|
+
end
|
45
|
+
|
46
|
+
attr_reader :parser, :config_updater, :loader, :help_generator,
|
47
|
+
:version_string, :debug_checker, :rebooter,
|
48
|
+
:happy_exiter_class, :sad_exiter_class
|
49
|
+
|
50
|
+
# rubocop:disable Metrics/ParameterLists
|
51
|
+
def initialize(parser: Params::Parser.new,
|
52
|
+
config_updater: Config.method(:update!),
|
53
|
+
loader: KexecPatchingLoader.new,
|
54
|
+
help_generator: Params::HelpGenerator.new,
|
55
|
+
version_string: "#{PROGRAM_NAME} #{VERSION}",
|
56
|
+
debug_checker: LazyConfig.debug,
|
57
|
+
rebooter: Rebooter.new,
|
58
|
+
happy_exiter_class: HappyExiter,
|
59
|
+
sad_exiter_class: SadExiter)
|
60
|
+
@parser = parser
|
61
|
+
@config_updater = config_updater
|
62
|
+
@loader = loader
|
63
|
+
@help_generator = help_generator
|
64
|
+
@version_string = version_string
|
65
|
+
@debug_checker = debug_checker
|
66
|
+
@rebooter = rebooter
|
67
|
+
@happy_exiter_class = happy_exiter_class
|
68
|
+
@sad_exiter_class = sad_exiter_class
|
69
|
+
end
|
70
|
+
# rubocop:enable Metrics/ParameterLists
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CryptReboot
|
4
|
+
# Concatenate files into one
|
5
|
+
class Concatenator
|
6
|
+
def call(*files, to:)
|
7
|
+
runner.call(tool, *files, output_file: to)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def tool
|
13
|
+
lazy_tool.call
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :lazy_tool, :runner
|
17
|
+
|
18
|
+
def initialize(lazy_tool: LazyConfig.cat_path,
|
19
|
+
runner: Runner::NoResult.new)
|
20
|
+
@lazy_tool = lazy_tool
|
21
|
+
@runner = runner
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|