I am still working on the idea so don't have concrete example.That sounds like a very interesting idea, and I wonder how that would look if used throughout the system
pingtoo wrote:"atd" is very old concept in Unix world. I think go back to SysV3 if not earlier. it was part of cron.
I am still working on the idea so don't have concrete example.That sounds like a very interesting idea, and I wonder how that would look if used throughout the system
time event in init workflow could be happen in following pointSorry this is not very organized. Just some quick brain dump.
- as timeout after start of searching root device.
- start a "beacon" so some how it can be detected a node boot up. (some idea I am floating is bluetooth, so may be my phone would know boot happen)
- in parallel to search root device, start network configuration, primary target on dhcp. (not sure about static setup)
- I want to be able load a simple rootfs over network and ran it in memory for recovery or simple system (distcc helper)
- continue above thoughts, I want to use a container based (like CoreOS) environment, so I want a very static Gentoo rootfs and everything else live in container(s)
- so I want to have a way to easily time out and I want to be sure it is not kernel error (therefor node paniced)
pingtoo wrote: I try to follow your code, it took me quick some time to figure out how you implement the "init" script because I was expecting there is a script or template somewhere in your code tree. This is where we have fundamental design differences. you are creating a generator that at execution time user will choose one specific target/path therefor a script generated for that path/target. I want to create one solution for all that will work on all scenarios that I can come up so I don't need to rewrite this program for each installation.
More or less, the way it works, is the "toml" definition portion of modules has the "imports" sections. Key names under here are used to say what part of the init process functions are imported to. If specific ordering is needed within an init level, init_order can be used.pingtoo wrote:Thanks for information.
I look the pr, I can understand the simple python logic, but I am not able to understand how it relate to actual init flow. But no worries I guess I just need to dig a bit more deeper in to your code base to see how it work.
We have different design goal but I appreciate your effort and sharing. it gave me some more to think about how to work on my project, especially those crypto modules because I never have to work on those concept before.
Code: Select all
[imports.init_main]
"hello_world" = [ "hello_world" ]
Code: Select all
def foo(self) -> str:
return "echo 'foo'"
def bar(self) -> str:
return """
echo bar
echo baz
"""
Code: Select all
[imports.init_main]
"foo" = [ "bar", "foo" ]
[imports.init_final]
"foo" = ["bar"]
Code: Select all
# Begin init_main
mount_fstab
bar
echo 'foo'
I mostly mean for the generated init script, I want most of the complexity to be in the python portion if possible (opposed to the POSIX shell portion), nothing is stopping users from making shell specific modules, but I try to keep the built in modules POSIX compatible if possible. I'm much more comfortable with python than any type of shell, so keeping the shell simple also helps me.pingtoo wrote:"readability"? do you refer to generated "init" script or somewhere else?
the init "level" my interpretation, does it mean a state (stage) of the program flow? If yes, do you have a place (document) how many "level" there are and is there order or control to manage there order?
In order words, it is like programming language, it is subroutinethere is a bit of added complexity because in cases where something like agetty is used, the init is split into 2 files, so this process ensures the primary init file gets the most basic init done, then it jumps to the "main" init which does something else, such as use agetty, or run SSH, could really be anything. That process should eventually die and execution returns to the original init which should finish things.
If you run ugrd with the "--print-init" arg it lists init functions:pingtoo wrote:Thanks for information.
I found it after my post. It is in the "Dev manual". Because it is dev manual so I did not read it first.
In order words, it is like programming language, it is subroutinethere is a bit of added complexity because in cases where something like agetty is used, the init is split into 2 files, so this process ensures the primary init file gets the most basic init done, then it jumps to the "main" init which does something else, such as use agetty, or run SSH, could really be anything. That process should eventually die and execution returns to the original init which should finish things.Thank you I got it.
Overall I think it is fine. I am just not prepare for this design idea. so I was looking for traditional design where there is basic shell/template then stuff were included in external call or subroutine manner.
Do you envision where someone would debug the final result at runtime? if not I think the "readability" consideration could be reduced. instead create a runtime flow printout like dracut create a /run/initramfs/<something>.log. Another idea, could you generate some sort of "flow map" upon create initrd image so at runtime one can review in rescue shell to expect what will happen?
also you mention something about "/etc/profile", I am not sure how it relate to initrd stage, do you create a /etc/profile in the initrd image?
Code: Select all
init_pre:
mount_base
make_run_dirs
export_exports
parse_cmdline
set_loglevel
print_banner
load_modules
init_main:
mount_fstab
start_agent
import_keys
crypt_init
init_mount:
btrfs_scan
set_root_subvol
select_subvol
mount_root
mount_late
init_final:
umount_fstab
do_switch_root
Code: Select all
> cat /tmp/initramfs_build/init
#!/bin/sh -l
# Begin init_pre
mount_base
edebug Creating run dir: "$(mkdir -pv /run/ugrd)"
export_exports
parse_cmdline
readvar loglevel > /proc/sys/kernel/printk
print_banner
load_modules
# !!custom_init
agetty --autologin root --login-program init_main.sh tty0 tty || rd_restart
# Begin init_final
umount_fstab
do_switch_root
# END INIT
I did a very basic implementation of your idea, and looking at it now, I just noticed it includes functions which were excluded, as in ones which were skipped for some reason, so it really shows the _imported_ functions at each run level regardless of whether or not they are used.pingtoo wrote:Thanks. So you already thought about my ideas that is great.
The only thing I think (I may be wrong about this) is that my ideas are target at runtime for who may not know about ugRD as in just a third party who inherit the image and at run time need information to troubleshoot. so it would be nice for example the print out of "--print-init" is save somewhere for the user to reference. Just as well the generated init script does not have reference to /etc/profile so it is not intuitive for some one new to ugRD to know where to look.
On the other hand, the generated script are great for me, very easy to understand. (however I been doing this "init" script design on and off for more than a year now)
It would be nice to include you posted script in to document for other to quick pick up of the runtime flow.
Back when I was first writing it, the functions, PATH, etc were just dumped into the main init file. This sorta worked but started to get really messy once you consider things like re-execing the shell, using multiple portions, etc. I think "sh -l" should be very compatible and helps reduce duplication. It's definitely worth explaining, could probably be a note in the dev manual and comment in the module so it's more clear. The shebang can be manually set using config (like most things in ugrd) if you want to experiment with other methods.pingtoo wrote:You are right, the script is easy enough for someone who doing initrd debug should be able to know.
The "sh -l" concept is really smart. only until you point out I realize the /etc/profile is implicit read. although my personally believe is be explicit. So I usually write code either in comment or just code the line even it will happen automatically. because it just make it know without guessing.
It is great to have this discussion. You have wake my coding personality.
I don't know what is "multiline" shebang. never encounter one before.making the shebang technically a multiline thing could possibly make sourcing reliable and more clear?
I mean right now the shebang exists as a string which gets added to the top of the file, it could technically add multiple lines instead of just one, and later lines could source the profile or similar.pingtoo wrote:I don't know what is "multiline" shebang. never encounter one before.making the shebang technically a multiline thing could possibly make sourcing reliable and more clear?
for test drive, I have an idea, use unshare(1) with -p option which will let you run the generated init with pid 1, if you setup the test environment correctly you can even let it run to finish with swich_root. If you want I can try to develop the exact unshare command for you to incorporate into ugRD. I would not able to create as some sort of module because I am not python programmer.
Code: Select all
cd /tmp
INITRD_PATH="/path/to/your/initrd.img" # Replace with the actual path
TEST_ROOT="/tmp/test_rootfs" # Directory to simulate the new root
# 1. Prepare the test environment
rm -rf initrd_test $TEST_ROOT
mkdir -p initrd_test $TEST_ROOT/sbin
# 2. Extract the initrd
cd initrd_test
zcat "$INITRD_PATH" | cpio -idmvCode: Select all
# Create a fake /sbin/init for test
touch $TEST_ROOT/sbin/init
chmod 755 $TEST_ROOT/sbin/init
cat<<'EOF'>$TEST_ROOT/sbin/init
echo "--- 'init' on Real Rootfs (This is a test) ---"
exit 0
EOF
Code: Select all
unshare --mount --pid --fork $TEST_ROOT/initpingtoo wrote:from the fullauto.toml I cannot get the picture on how it work with VM.
--edit--
Sorry, I am being impatient, did not read the test.py
--edit--
but here I come up on using unshare(1) example. I did not test is so please take it as example. DON'T RUN IT.
Code: Select all
cd /tmp INITRD_PATH="/path/to/your/initrd.img" # Replace with the actual path TEST_ROOT="/tmp/test_rootfs" # Directory to simulate the new root # 1. Prepare the test environment rm -rf initrd_test $TEST_ROOT mkdir -p initrd_test $TEST_ROOT/sbin # 2. Extract the initrd cd initrd_test zcat "$INITRD_PATH" | cpio -idmvCode: Select all
# Create a fake /sbin/init for test touch $TEST_ROOT/sbin/init chmod 755 $TEST_ROOT/sbin/init cat<<'EOF'>$TEST_ROOT/sbin/init echo "--- 'init' on Real Rootfs (This is a test) ---" exit 0 EOFunshare(1) create a container alike environment so there is no post process require to cleanup after unshare(1) command finish. Except you may want to wipe out $TEST_ROOT.Code: Select all
unshare --mount --pid --fork $TEST_ROOT/init
I understand I am being intrusive, Please forgive meI am just feel like kid want to play new toy.
The lofty goal for the test module is that it should somewhat transparently and automatically handle tests for any other module. Basically, in theory, you could just make your module and attempt to run "ugrd -m mymodule --test" and it would run tests on it using your kernel and the exact same initramfs image it would be installing. In reality, for more complex setups, the user will likely have to write some of their own tests, but if the were able to integrate them into the existing unit tests, that would make everything very unified and cohesive.pingtoo wrote:Thanks.
I think we are going different direction here againYou are thinking incorprate ugRD in part of automation of portage install. Whereas I am thinking someone want to develop their own module(s) therefor they want to test run the process to verify their own project.
In container or namespace, kernel were did not change, so kmod should just work (kind of no-op because they should be already loaded)
Although I think for a initrd project kernel should not be included in testing. May be you have some insight that why you think you should also test kernel together with initrd?
My point being I want my initrd not tie to any kernel. I understand may be the kmod module is to address that need for kernel but isn't that your project expect the process run on the target machine anyway. so module should already be there.
I see your namespace project. So you are well versed for using "namespace". My shell script above just a illustration of sequence. I think with little or no modification you can incorporate that directly in to ugRD.
Also Catalyst in here use namespace too, just for your reference.
I don't know anything about Github Action, so no comment.

Code: Select all
ERROR | [btrfs] Failed to get modinfo for init kernel module: [btrfs] Modinfo returned no output.
ERROR | [crc32c] Failed to get modinfo for init kernel module: [crc32c] Modinfo returned no output.
ERROR | [dm_crypt] Failed to get modinfo for init kernel module: [dm_crypt] Modinfo returned no output.
WARNING | [dm_mod] Failed to process autodetected kernel module dependencies: [dm_mod] Modinfo returned no output.
WARNING | [nvme] Failed to process autodetected kernel module dependencies: [nvme] Modinfo returned no output.
WARNING | [xts] Failed to process autodetected kernel module dependencies: [xts] Modinfo returned no output.
WARNING | [aesni_intel] Failed to process autodetected kernel module dependencies: [aesni_intel] Modinfo returned no output.
CRITICAL | Required module cannot be imported and is not builtin: btrfs
* Failed to generate initramfs for kernel 6.12.41-gentoo
Code: Select all
[ugrd.kmod.kmod]
no_kmod = true