How to pass arguments to a Linux kernel `init=` bootparam?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
2
down vote

favorite












Update:



I have succeeded in creating a very simple demo of using the init= bootparam to specify that a custom binary (written in golang and compiled) should be used in place of the standard init. The binary in that project is compiled for the ARM processor of the Raspberry Pi, but the source should compile for any platform.




Original Post:



I've successfully put init=/bin/bash in my bootparams and gotten a root shell on boot. Now I'd like to use bootparams to run a "first boot" setup script.



NOTE:



I know there are lots of alternatives that can be offered. Leave those as comments on the question if you'd like. But, I cannot use them; this question is not about them; they are not answers to this question. So, please don't post alternatives as answers.* It's not helpful to people who came here for this question.



Things I've tried that failed:



  • init="/bin/bash -c 'mount /dev/mmcblk0p1 /boot; date > /boot/test.txt'"

  • init='/bin/bash -c "mount /dev/mmcblk0p1 /boot; date > /boot/test.txt"'

  • init="/bin/bash"

  • init='/bin/bash'

So I'm going to assume that even quoting your init= param is not an option.



  1. Correct me if I am wrong here.

I have read The Linux Kernel documentation on the matter. It says:




The kernel parses parameters from the kernel command line up to --; if it doesn’t recognize a parameter and it doesn’t contain a ., the parameter gets passed to init: parameters with = go into init’s environment, others are passed as command line arguments to init. Everything after -- is passed as an argument to init.



...



init= [KNL]
Format: <full_path>
Run specified binary instead of /sbin/init as init
process.



Lesson learned:



That Format: <full_path> would explain why it doesn't like me putting a full command (or multiple) in the init=



I have also read BOOTPARAM(7) (search for "passed to the init process") where they say:




Anything of the form 'foo=bar' that is not accepted as a setup function as described above is then interpreted as an environment variable to be set. A (useless?) example would be to use 'TERM=vt100' as a boot argument.



Any remaining arguments that were not picked up by the kernel and were not interpreted as environment variables are then passed onto PID 1, which is usually the init(1) program. The most common argument that is passed to the init process is the word 'single' which instructs it to boot the computer in single user mode, and not launch all the usual daemons. Check the manual page for the version of init(1) installed on your system to see what arguments it accepts.




  1. Are there any working examples of using this info to pass arguments to a custom specified init=?

If there is, it's hard to find and this question will serve to make it show up in Google results. If there is not, we'll create a working example for the community.







share|improve this question






















  • bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
    – sourcejedi
    Mar 5 at 19:29











  • however remember that the kernel would panic once executable has finished.
    – sourcejedi
    Mar 5 at 19:35










  • 2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
    – sourcejedi
    Mar 5 at 19:41







  • 1




    IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
    – sourcejedi
    Mar 5 at 19:45






  • 1




    Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
    – cas
    Mar 6 at 2:39















up vote
2
down vote

favorite












Update:



I have succeeded in creating a very simple demo of using the init= bootparam to specify that a custom binary (written in golang and compiled) should be used in place of the standard init. The binary in that project is compiled for the ARM processor of the Raspberry Pi, but the source should compile for any platform.




Original Post:



I've successfully put init=/bin/bash in my bootparams and gotten a root shell on boot. Now I'd like to use bootparams to run a "first boot" setup script.



NOTE:



I know there are lots of alternatives that can be offered. Leave those as comments on the question if you'd like. But, I cannot use them; this question is not about them; they are not answers to this question. So, please don't post alternatives as answers.* It's not helpful to people who came here for this question.



Things I've tried that failed:



  • init="/bin/bash -c 'mount /dev/mmcblk0p1 /boot; date > /boot/test.txt'"

  • init='/bin/bash -c "mount /dev/mmcblk0p1 /boot; date > /boot/test.txt"'

  • init="/bin/bash"

  • init='/bin/bash'

So I'm going to assume that even quoting your init= param is not an option.



  1. Correct me if I am wrong here.

I have read The Linux Kernel documentation on the matter. It says:




The kernel parses parameters from the kernel command line up to --; if it doesn’t recognize a parameter and it doesn’t contain a ., the parameter gets passed to init: parameters with = go into init’s environment, others are passed as command line arguments to init. Everything after -- is passed as an argument to init.



...



init= [KNL]
Format: <full_path>
Run specified binary instead of /sbin/init as init
process.



Lesson learned:



That Format: <full_path> would explain why it doesn't like me putting a full command (or multiple) in the init=



I have also read BOOTPARAM(7) (search for "passed to the init process") where they say:




Anything of the form 'foo=bar' that is not accepted as a setup function as described above is then interpreted as an environment variable to be set. A (useless?) example would be to use 'TERM=vt100' as a boot argument.



Any remaining arguments that were not picked up by the kernel and were not interpreted as environment variables are then passed onto PID 1, which is usually the init(1) program. The most common argument that is passed to the init process is the word 'single' which instructs it to boot the computer in single user mode, and not launch all the usual daemons. Check the manual page for the version of init(1) installed on your system to see what arguments it accepts.




  1. Are there any working examples of using this info to pass arguments to a custom specified init=?

If there is, it's hard to find and this question will serve to make it show up in Google results. If there is not, we'll create a working example for the community.







share|improve this question






















  • bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
    – sourcejedi
    Mar 5 at 19:29











  • however remember that the kernel would panic once executable has finished.
    – sourcejedi
    Mar 5 at 19:35










  • 2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
    – sourcejedi
    Mar 5 at 19:41







  • 1




    IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
    – sourcejedi
    Mar 5 at 19:45






  • 1




    Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
    – cas
    Mar 6 at 2:39













up vote
2
down vote

favorite









up vote
2
down vote

favorite











Update:



I have succeeded in creating a very simple demo of using the init= bootparam to specify that a custom binary (written in golang and compiled) should be used in place of the standard init. The binary in that project is compiled for the ARM processor of the Raspberry Pi, but the source should compile for any platform.




Original Post:



I've successfully put init=/bin/bash in my bootparams and gotten a root shell on boot. Now I'd like to use bootparams to run a "first boot" setup script.



NOTE:



I know there are lots of alternatives that can be offered. Leave those as comments on the question if you'd like. But, I cannot use them; this question is not about them; they are not answers to this question. So, please don't post alternatives as answers.* It's not helpful to people who came here for this question.



Things I've tried that failed:



  • init="/bin/bash -c 'mount /dev/mmcblk0p1 /boot; date > /boot/test.txt'"

  • init='/bin/bash -c "mount /dev/mmcblk0p1 /boot; date > /boot/test.txt"'

  • init="/bin/bash"

  • init='/bin/bash'

So I'm going to assume that even quoting your init= param is not an option.



  1. Correct me if I am wrong here.

I have read The Linux Kernel documentation on the matter. It says:




The kernel parses parameters from the kernel command line up to --; if it doesn’t recognize a parameter and it doesn’t contain a ., the parameter gets passed to init: parameters with = go into init’s environment, others are passed as command line arguments to init. Everything after -- is passed as an argument to init.



...



init= [KNL]
Format: <full_path>
Run specified binary instead of /sbin/init as init
process.



Lesson learned:



That Format: <full_path> would explain why it doesn't like me putting a full command (or multiple) in the init=



I have also read BOOTPARAM(7) (search for "passed to the init process") where they say:




Anything of the form 'foo=bar' that is not accepted as a setup function as described above is then interpreted as an environment variable to be set. A (useless?) example would be to use 'TERM=vt100' as a boot argument.



Any remaining arguments that were not picked up by the kernel and were not interpreted as environment variables are then passed onto PID 1, which is usually the init(1) program. The most common argument that is passed to the init process is the word 'single' which instructs it to boot the computer in single user mode, and not launch all the usual daemons. Check the manual page for the version of init(1) installed on your system to see what arguments it accepts.




  1. Are there any working examples of using this info to pass arguments to a custom specified init=?

If there is, it's hard to find and this question will serve to make it show up in Google results. If there is not, we'll create a working example for the community.







share|improve this question














Update:



I have succeeded in creating a very simple demo of using the init= bootparam to specify that a custom binary (written in golang and compiled) should be used in place of the standard init. The binary in that project is compiled for the ARM processor of the Raspberry Pi, but the source should compile for any platform.




Original Post:



I've successfully put init=/bin/bash in my bootparams and gotten a root shell on boot. Now I'd like to use bootparams to run a "first boot" setup script.



NOTE:



I know there are lots of alternatives that can be offered. Leave those as comments on the question if you'd like. But, I cannot use them; this question is not about them; they are not answers to this question. So, please don't post alternatives as answers.* It's not helpful to people who came here for this question.



Things I've tried that failed:



  • init="/bin/bash -c 'mount /dev/mmcblk0p1 /boot; date > /boot/test.txt'"

  • init='/bin/bash -c "mount /dev/mmcblk0p1 /boot; date > /boot/test.txt"'

  • init="/bin/bash"

  • init='/bin/bash'

So I'm going to assume that even quoting your init= param is not an option.



  1. Correct me if I am wrong here.

I have read The Linux Kernel documentation on the matter. It says:




The kernel parses parameters from the kernel command line up to --; if it doesn’t recognize a parameter and it doesn’t contain a ., the parameter gets passed to init: parameters with = go into init’s environment, others are passed as command line arguments to init. Everything after -- is passed as an argument to init.



...



init= [KNL]
Format: <full_path>
Run specified binary instead of /sbin/init as init
process.



Lesson learned:



That Format: <full_path> would explain why it doesn't like me putting a full command (or multiple) in the init=



I have also read BOOTPARAM(7) (search for "passed to the init process") where they say:




Anything of the form 'foo=bar' that is not accepted as a setup function as described above is then interpreted as an environment variable to be set. A (useless?) example would be to use 'TERM=vt100' as a boot argument.



Any remaining arguments that were not picked up by the kernel and were not interpreted as environment variables are then passed onto PID 1, which is usually the init(1) program. The most common argument that is passed to the init process is the word 'single' which instructs it to boot the computer in single user mode, and not launch all the usual daemons. Check the manual page for the version of init(1) installed on your system to see what arguments it accepts.




  1. Are there any working examples of using this info to pass arguments to a custom specified init=?

If there is, it's hard to find and this question will serve to make it show up in Google results. If there is not, we'll create a working example for the community.









share|improve this question













share|improve this question




share|improve this question








edited Apr 16 at 20:34

























asked Mar 5 at 18:53









Bruno Bronosky

1,81511111




1,81511111











  • bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
    – sourcejedi
    Mar 5 at 19:29











  • however remember that the kernel would panic once executable has finished.
    – sourcejedi
    Mar 5 at 19:35










  • 2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
    – sourcejedi
    Mar 5 at 19:41







  • 1




    IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
    – sourcejedi
    Mar 5 at 19:45






  • 1




    Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
    – cas
    Mar 6 at 2:39

















  • bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
    – sourcejedi
    Mar 5 at 19:29











  • however remember that the kernel would panic once executable has finished.
    – sourcejedi
    Mar 5 at 19:35










  • 2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
    – sourcejedi
    Mar 5 at 19:41







  • 1




    IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
    – sourcejedi
    Mar 5 at 19:45






  • 1




    Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
    – cas
    Mar 6 at 2:39
















bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
– sourcejedi
Mar 5 at 19:29





bash -c '$@' bash /bin/echo -arg1 -arg2 works in the shell. So maybe init=/bin/bash -- -c $@ bash /path/to/executable -arg1 -arg2.
– sourcejedi
Mar 5 at 19:29













however remember that the kernel would panic once executable has finished.
– sourcejedi
Mar 5 at 19:35




however remember that the kernel would panic once executable has finished.
– sourcejedi
Mar 5 at 19:35












2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
– sourcejedi
Mar 5 at 19:41





2) whether or not you specify a custom init= is not quite relevant. For an example of an init system which accepts various arguments passed using this mechanism, see the original sysvinit. git.savannah.nongnu.org/cgit/sysvinit.git/tree/src/… It accepted arguments like "single". I am fairly confident the -s option the source code mentions would have been equally striaghtforward to pass on the kernel command line.
– sourcejedi
Mar 5 at 19:41





1




1




IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
– sourcejedi
Mar 5 at 19:45




IMO this is very difficult to answer while respecting your wishes. I think the "correct" solution would be to put your firstboot code in a script file, ending with exec /sbin/init, and simply pass that script as the init. It sounds like you don't want that for some reason though.
– sourcejedi
Mar 5 at 19:45




1




1




Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
– cas
Mar 6 at 2:39





Your wishes and your opinion that "alternatives are not answers to this question" are contrary to the goals of this site. Sometimes the best, or even the only, answer to a question is "don't do that" or "there is no way that can be made to work", both followed by a "here's why" explanation and a "do this instead".
– cas
Mar 6 at 2:39











1 Answer
1






active

oldest

votes

















up vote
4
down vote













Yes, this is how you traditionally tell a regular init system what state to boot into. If you're running sysv-init (or pretty much any widely used init system other than systemd), you can put a number between 1 and 5 at the end of the kernel arguments and it will boot into that run level (1 is always single-user mode, the others are system defined, 3 or 4 is what most Linux distros have conventionally used as the default). If you're using systemd, you can pass single or emergency at the end of the kernel arguments to boot into those modes respectively.



Using this mechanism for passing arbitrary arguments however is somewhat difficult because the kernel does the absolute minimum of parsing, which means in particular that:



  • Arguments with whitespace in them can't be passed at all, because the kernel doesn't parse quoted strings (that is, 'some string' gets parsed as two arguments 'some and string').

  • You can't reference any environment variables at all, because the kernel doesn't do variable substitution (which is normally done by the shell you're running the command from before it even starts the command).

  • In general, the arguments have to be correctly interpretable under the POSIX C locale (essentially US ASCII), which throws internationalization out the window unless you want to use something like base64 or punycode.

  • There is an upper limit on how much data can be passed in kernel arguments, but I forget what it is.

These limitations combined are why you can't find anything on Google about doing this type of thing, no systems integration engineer in their right mind does it, because it's far more effort to work around the above limitations than it is to just write a script containing all the required arguments and call that instead.






share|improve this answer




















  • You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
    – JdeBP
    Mar 6 at 8:47










  • I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
    – Bruno Bronosky
    Mar 6 at 9:50










  • But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
    – Bruno Bronosky
    Mar 6 at 10:04






  • 1




    If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
    – telcoM
    Mar 6 at 13:06










  • @telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
    – Bruno Bronosky
    Mar 6 at 19:14










Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f428347%2fhow-to-pass-arguments-to-a-linux-kernel-init-bootparam%23new-answer', 'question_page');

);

Post as a guest






























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
4
down vote













Yes, this is how you traditionally tell a regular init system what state to boot into. If you're running sysv-init (or pretty much any widely used init system other than systemd), you can put a number between 1 and 5 at the end of the kernel arguments and it will boot into that run level (1 is always single-user mode, the others are system defined, 3 or 4 is what most Linux distros have conventionally used as the default). If you're using systemd, you can pass single or emergency at the end of the kernel arguments to boot into those modes respectively.



Using this mechanism for passing arbitrary arguments however is somewhat difficult because the kernel does the absolute minimum of parsing, which means in particular that:



  • Arguments with whitespace in them can't be passed at all, because the kernel doesn't parse quoted strings (that is, 'some string' gets parsed as two arguments 'some and string').

  • You can't reference any environment variables at all, because the kernel doesn't do variable substitution (which is normally done by the shell you're running the command from before it even starts the command).

  • In general, the arguments have to be correctly interpretable under the POSIX C locale (essentially US ASCII), which throws internationalization out the window unless you want to use something like base64 or punycode.

  • There is an upper limit on how much data can be passed in kernel arguments, but I forget what it is.

These limitations combined are why you can't find anything on Google about doing this type of thing, no systems integration engineer in their right mind does it, because it's far more effort to work around the above limitations than it is to just write a script containing all the required arguments and call that instead.






share|improve this answer




















  • You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
    – JdeBP
    Mar 6 at 8:47










  • I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
    – Bruno Bronosky
    Mar 6 at 9:50










  • But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
    – Bruno Bronosky
    Mar 6 at 10:04






  • 1




    If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
    – telcoM
    Mar 6 at 13:06










  • @telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
    – Bruno Bronosky
    Mar 6 at 19:14














up vote
4
down vote













Yes, this is how you traditionally tell a regular init system what state to boot into. If you're running sysv-init (or pretty much any widely used init system other than systemd), you can put a number between 1 and 5 at the end of the kernel arguments and it will boot into that run level (1 is always single-user mode, the others are system defined, 3 or 4 is what most Linux distros have conventionally used as the default). If you're using systemd, you can pass single or emergency at the end of the kernel arguments to boot into those modes respectively.



Using this mechanism for passing arbitrary arguments however is somewhat difficult because the kernel does the absolute minimum of parsing, which means in particular that:



  • Arguments with whitespace in them can't be passed at all, because the kernel doesn't parse quoted strings (that is, 'some string' gets parsed as two arguments 'some and string').

  • You can't reference any environment variables at all, because the kernel doesn't do variable substitution (which is normally done by the shell you're running the command from before it even starts the command).

  • In general, the arguments have to be correctly interpretable under the POSIX C locale (essentially US ASCII), which throws internationalization out the window unless you want to use something like base64 or punycode.

  • There is an upper limit on how much data can be passed in kernel arguments, but I forget what it is.

These limitations combined are why you can't find anything on Google about doing this type of thing, no systems integration engineer in their right mind does it, because it's far more effort to work around the above limitations than it is to just write a script containing all the required arguments and call that instead.






share|improve this answer




















  • You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
    – JdeBP
    Mar 6 at 8:47










  • I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
    – Bruno Bronosky
    Mar 6 at 9:50










  • But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
    – Bruno Bronosky
    Mar 6 at 10:04






  • 1




    If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
    – telcoM
    Mar 6 at 13:06










  • @telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
    – Bruno Bronosky
    Mar 6 at 19:14












up vote
4
down vote










up vote
4
down vote









Yes, this is how you traditionally tell a regular init system what state to boot into. If you're running sysv-init (or pretty much any widely used init system other than systemd), you can put a number between 1 and 5 at the end of the kernel arguments and it will boot into that run level (1 is always single-user mode, the others are system defined, 3 or 4 is what most Linux distros have conventionally used as the default). If you're using systemd, you can pass single or emergency at the end of the kernel arguments to boot into those modes respectively.



Using this mechanism for passing arbitrary arguments however is somewhat difficult because the kernel does the absolute minimum of parsing, which means in particular that:



  • Arguments with whitespace in them can't be passed at all, because the kernel doesn't parse quoted strings (that is, 'some string' gets parsed as two arguments 'some and string').

  • You can't reference any environment variables at all, because the kernel doesn't do variable substitution (which is normally done by the shell you're running the command from before it even starts the command).

  • In general, the arguments have to be correctly interpretable under the POSIX C locale (essentially US ASCII), which throws internationalization out the window unless you want to use something like base64 or punycode.

  • There is an upper limit on how much data can be passed in kernel arguments, but I forget what it is.

These limitations combined are why you can't find anything on Google about doing this type of thing, no systems integration engineer in their right mind does it, because it's far more effort to work around the above limitations than it is to just write a script containing all the required arguments and call that instead.






share|improve this answer












Yes, this is how you traditionally tell a regular init system what state to boot into. If you're running sysv-init (or pretty much any widely used init system other than systemd), you can put a number between 1 and 5 at the end of the kernel arguments and it will boot into that run level (1 is always single-user mode, the others are system defined, 3 or 4 is what most Linux distros have conventionally used as the default). If you're using systemd, you can pass single or emergency at the end of the kernel arguments to boot into those modes respectively.



Using this mechanism for passing arbitrary arguments however is somewhat difficult because the kernel does the absolute minimum of parsing, which means in particular that:



  • Arguments with whitespace in them can't be passed at all, because the kernel doesn't parse quoted strings (that is, 'some string' gets parsed as two arguments 'some and string').

  • You can't reference any environment variables at all, because the kernel doesn't do variable substitution (which is normally done by the shell you're running the command from before it even starts the command).

  • In general, the arguments have to be correctly interpretable under the POSIX C locale (essentially US ASCII), which throws internationalization out the window unless you want to use something like base64 or punycode.

  • There is an upper limit on how much data can be passed in kernel arguments, but I forget what it is.

These limitations combined are why you can't find anything on Google about doing this type of thing, no systems integration engineer in their right mind does it, because it's far more effort to work around the above limitations than it is to just write a script containing all the required arguments and call that instead.







share|improve this answer












share|improve this answer



share|improve this answer










answered Mar 5 at 20:13









Austin Hemmelgarn

5,104915




5,104915











  • You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
    – JdeBP
    Mar 6 at 8:47










  • I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
    – Bruno Bronosky
    Mar 6 at 9:50










  • But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
    – Bruno Bronosky
    Mar 6 at 10:04






  • 1




    If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
    – telcoM
    Mar 6 at 13:06










  • @telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
    – Bruno Bronosky
    Mar 6 at 19:14
















  • You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
    – JdeBP
    Mar 6 at 8:47










  • I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
    – Bruno Bronosky
    Mar 6 at 9:50










  • But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
    – Bruno Bronosky
    Mar 6 at 10:04






  • 1




    If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
    – telcoM
    Mar 6 at 13:06










  • @telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
    – Bruno Bronosky
    Mar 6 at 19:14















You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
– JdeBP
Mar 6 at 8:47




You can use the numbers with systemd too. It is just that run levels are "obsolete" and not a systemd mechanism. The numbers are just mapped onto the native mechanisms. unix.stackexchange.com/a/394238/5132 Single-user mode was superseded in van Smoorenburg init by the emergency/rescue split nearly a quarter of a century ago, in 1995. unix.stackexchange.com/a/392612/5132
– JdeBP
Mar 6 at 8:47












I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
– Bruno Bronosky
Mar 6 at 9:50




I have written a script. I just can't call it because it is on a filesystem that is not mounted. So, I need to some minimal preparation before I can run the script.
– Bruno Bronosky
Mar 6 at 9:50












But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
– Bruno Bronosky
Mar 6 at 10:04




But, even as I test I have created a file /test.sh (that's on the filesystem that does get mounted) containing only 2 lines: #!/bin/bash and /bin/date > /test.txt and I still get nothing.
– Bruno Bronosky
Mar 6 at 10:04




1




1




If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
– telcoM
Mar 6 at 13:06




If you try init=/test.sh, then when your /test.sh is executed, the real root filesystem has either not been mounted yet, or if you aren't using initramfs (or initrd), it is most likely mounted read-only. So your /test.txt either does not get written (because read-only file system) or gets written to a non-persistent RAM image of initramfs, which will be removed from memory as the system switches over to the real root filesystem.
– telcoM
Mar 6 at 13:06












@telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
– Bruno Bronosky
Mar 6 at 19:14




@telcoM shouldn't output to stdout show up before the kernel panic? I haven't been able to get any echo output either.
– Bruno Bronosky
Mar 6 at 19:14












 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f428347%2fhow-to-pass-arguments-to-a-linux-kernel-init-bootparam%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

How to check contact read email or not when send email to Individual?

Bahrain

Postfix configuration issue with fips on centos 7; mailgun relay