Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
As the others here with brains have had a chance to sleep on this, what's the current thinking? As I understand it, there are 2 decisions to make: 1) How to decide if a $daemon is a script as opposed to a binary (*) file(1) (*) dd(d) (*) sed(1) Could stat(1) be tasked to switch case on file attributes (e.g: size)? 2) Whether to check if a script's interpreter is valid http://openbsd.7691.n7.nabble.com/etc-rc-d-rc-subr-prefix-pexp-with-script-interpretor-path-td234439.html Yes/No/Other? -- Craig Skinner | http://twitter.com/Craig_Skinner | http://linkd.in/yGqkv7
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 2013/09/21 13:12, Craig R. Skinner wrote: As the others here with brains have had a chance to sleep on this, what's the current thinking? As I understand it, there are 2 decisions to make: 1) How to decide if a $daemon is a script as opposed to a binary (*) file(1) too big, too complex. file(1) has to parse a 500K /etc/magic each time it runs, which would be 15+ times for this, and uses about 8MB ram. definitely overkill for identifying the contents of the first two characters of a file. remember this has to run on a wide range of platforms. (*) dd(d) (*) sed(1) Could stat(1) be tasked to switch case on file attributes (e.g: size)? how would size help? 2) Whether to check if a script's interpreter is valid http://openbsd.7691.n7.nabble.com/etc-rc-d-rc-subr-prefix-pexp-with-script-interpretor-path-td234439.html Yes/No/Other? -- Craig Skinner | http://twitter.com/Craig_Skinner | http://linkd.in/yGqkv7 How much does this really help anyway? Porters still need to check the actual string used (for example, it's quite common for perl things to use perl: programnanme), and it doesn't take much extra typing to add a pexp line to the script in cases where it's needed. I am rather wary of adding complication to rc.subr, iirc one of the conditions when the subsystem was first added was that it remained simple..
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
Date: Sat, 21 Sep 2013 14:37:21 +0100 From: Stuart Henderson st...@openbsd.org How much does this really help anyway? Porters still need to check the actual string used (for example, it's quite common for perl things to use perl: programnanme), and it doesn't take much extra typing to add a pexp line to the script in cases where it's needed. I am rather wary of adding complication to rc.subr, iirc one of the conditions when the subsystem was first added was that it remained simple.. +1
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 2013-09-16 Mon 23:28 PM |, Alexander Hall wrote: sed can do it all. Really. This is getting beyond me Alexander. Is sed a mechanism to step away from using file(1) ? Notes: - I separate re_quote() cause I think it can be useful in other places. - I think re_quote() is (basic) regex complete. - I don't care if the interpreter is (or seems) nonexistant, as that shouldn't be a runtime error. - I'm sure sed may die horribly if you try to feed it a 9GB oneline file. However, if so, it should not produce any output anyway. ;) If this would ever be considered a real problem, dd(1) would help (as espie already mentioned). re_quote() { sed 's/\([]^$*.\\[]\)/\\\1/g'; } interpreter=$( sed -n 's/^#![[:space:]]*\(.*\)/\1 /p;q' ${daemon} | re_quote) pexp=$interpreter$pexp Moreover, - you probably want to unset $interpreter when done. - we might want to re_quote the entire $pexp later instead.
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 09/17/13 13:49, Craig R. Skinner wrote: On 2013-09-16 Mon 23:28 PM |, Alexander Hall wrote: sed can do it all. Really. This is getting beyond me Alexander. Is sed a mechanism to step away from using file(1) ? Heh, sorry about that. :) Nah, it's merely a way to combine `head | grep | sed | cut | ...` pipes since sed is often capable to cope with it all. Notes: - I separate re_quote() cause I think it can be useful in other places. - I think re_quote() is (basic) regex complete. - I don't care if the interpreter is (or seems) nonexistant, as that shouldn't be a runtime error. - I'm sure sed may die horribly if you try to feed it a 9GB oneline file. However, if so, it should not produce any output anyway. ;) If this would ever be considered a real problem, dd(1) would help (as espie already mentioned). re_quote() { sed 's/\([]^$*.\\[]\)/\\\1/g'; } interpreter=$( sed -n 's/^#![[:space:]]*\(.*\)/\1 /p;q' ${daemon} | In this case I make sure sed only looks at the first line (unconditional 'q'uit at the end), and prints it, followed by a space, but only if it was able to withdraw a shebang and optional following whitespace from the start of the line (-n, s/^...\(.*\)/\1 /p). What is known and discussed though, is that sed could potentially crash on a *really* long first line in that file. In this case, a pre-check with file(1), or input truncation with dd, would help. Anyway, my $.02 is running out, so I leave it up to the rc.d maintainer(s) to determine if they consider it a real problem or if it can go the way of the hash-collision discussion... /Alexander re_quote) pexp=$interpreter$pexp Moreover, - you probably want to unset $interpreter when done. - we might want to re_quote the entire $pexp later instead.
/etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
For scripts (perl, shell, whatever...), prefix ${pexp} with the script's interpretor path as defined by the script. No need to override ${pexp} in the daemon's rc file. Index: rc.subr === RCS file: /cvs/src/etc/rc.d/rc.subr,v retrieving revision 1.70 diff -u -r1.70 rc.subr --- rc.subr 11 Jul 2013 09:34:33 - 1.70 +++ rc.subr 16 Sep 2013 10:26:09 - @@ -221,4 +221,9 @@ unset _rcflags _rcuser pexp=${daemon}${daemon_flags:+ ${daemon_flags}} +file ${daemon} | fgrep -q script +{ + shebang=$(head -n 1 ${daemon} | cut -d! -f2) + pexp=${shebang} ${pexp} +} rcexec=su -l -c ${daemon_class} -s /bin/sh ${daemon_user} -c e.g. Remove pexp= from /etc/rc.d/greyscanner: --- greyscanner.pkg Mon Aug 19 14:46:01 2013 +++ greyscanner Mon Sep 16 11:30:33 2013 @@ -6,7 +6,6 @@ . /etc/rc.d/rc.subr -pexp=/usr/bin/perl ${daemon} rc_reload=NO rc_cmd $1 $ sudo /etc/rc.d/greyscanner restart greyscanner(ok) greyscanner(ok) $ cat /var/run/rc.d/greyscanner /usr/bin/perl /usr/local/sbin/greyscanner $ ps auxwww | fgrep greyscanner root 25280 0.0 0.6 4896 2920 ?? Is11:35AM0:00.04 /usr/bin/perl /usr/local/sbin/greyscanner Cheers, -- Craig Skinner | http://twitter.com/Craig_Skinner | http://linkd.in/yGqkv7
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On Mon, Sep 16, 2013 at 11:50:50AM +0100, Craig R. Skinner wrote: For scripts (perl, shell, whatever...), prefix ${pexp} with the script's interpretor path as defined by the script. No need to override ${pexp} in the daemon's rc file. Heh, very interesting trick ;-) But I don't think that is 100% full proof as is. e.g. $ head -n 1 /usr/local/bin/xml2-config | cut -d! -f2 /bin/sh You have a white space before the interpreter. If you can improve that and make sure it works with all similar rc scripts then I think it is definitely something that should be looked into. Thanks. -- Antoine
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 2013-09-16 Mon 13:00 PM |, Antoine Jacoutot wrote: Heh, very interesting trick ;-) But I don't think that is 100% full proof as is. e.g. $ head -n 1 /usr/local/bin/xml2-config | cut -d! -f2 /bin/sh You have a white space before the interpreter. If you can improve that and make sure it works with all similar rc scripts then I think it is definitely something that should be looked into. Thanks. Well spotted Antoine. I wrote a test script with various shebang lines of: #![space]/bin/ksh #![space][space]/bin/ksh #![space][tab]/bin/ksh -x #![tab]/bin/ksh -x #![space]/usr/bin/perl #![space][space]/usr/bin/perl #![space][tab]/usr/bin/perl -T #![tab][tab][tab]/usr/bin/perl -T This seems to work with these test scenarios (as seen in /var/run/rc.d/rcshebangtester): Index: rc.subr === RCS file: /cvs/src/etc/rc.d/rc.subr,v retrieving revision 1.70 diff -u -r1.70 rc.subr --- rc.subr 11 Jul 2013 09:34:33 - 1.70 +++ rc.subr 16 Sep 2013 12:09:42 - @@ -221,4 +221,9 @@ unset _rcflags _rcuser pexp=${daemon}${daemon_flags:+ ${daemon_flags}} +file ${daemon} | fgrep -q script +{ + shebang=$(head -n 1 ${daemon} | cut -d! -f2 | sed 's/^[[:blank:]]*//') + pexp=${shebang} ${pexp} +} rcexec=su -l -c ${daemon_class} -s /bin/sh ${daemon_user} -c Would it also be worthwhile verifying the 1st element of $shebang is executable before prefixing $pexp? Cheers, -- Craig Skinner | http://twitter.com/Craig_Skinner | http://linkd.in/yGqkv7
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On Mon, Sep 16, 2013 at 08:57:11PM +0200, Antoine Jacoutot wrote: Any other thoughts? Is there any way we could use something else than file(1) ? Well, you can look for a script using dd and matching it against the two possible signatures. e.g., dd 2/dev/null if=file bs=4 count=1|grep -qe '#!/./ -e '#! /' I'm not sure that's too much of a progress. There might be another way to grab the first 4 bytes of a file. Off-hand I don't see any.
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
Any other thoughts? Is there any way we could use something else than file(1) ? -- Antoine
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 2013-09-16 Mon 15:12 PM |, Paul de Weerd wrote: Hi Craig, --- cat bad_script.sh # This is a VERY BAD example of a script! This will break your # shebang thingambob echo Now what... -- I think you'd be better of making sure the first two characters in the file are actually #!: head -n1 ${FILE} | grep '^#!' | sed 's/^#![[:blank:]]*//' Good idea Paul. Implemented below, along with rudimentary testing for a valid interpreter: Index: rc.subr === RCS file: /cvs/src/etc/rc.d/rc.subr,v retrieving revision 1.70 diff -u -r1.70 rc.subr --- rc.subr 11 Jul 2013 09:34:33 - 1.70 +++ rc.subr 16 Sep 2013 18:19:14 - @@ -221,4 +221,15 @@ unset _rcflags _rcuser pexp=${daemon}${daemon_flags:+ ${daemon_flags}} +file ${daemon} | fgrep -q script +{ + shebang=$(head -n 1 ${daemon} | grep '^#!' | sed 's/^#![[:blank:]]*//') + interpreter=$(echo ${shebang} | cut -d' ' -f1) + if [[ -f ${interpreter} -x ${interpreter} ]] + then + pexp=${shebang} ${pexp} + else + rc_err $0: invalid interpreter: ${interpreter} + fi +} rcexec=su -l -c ${daemon_class} -s /bin/sh ${daemon_user} -c Test scripts: #-=-= /etc/rc.d/rcshebangtester -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #!/bin/sh #daemon=/home/me/bin/rcshebangtester.dud #daemon=/home/me/bin/rcshebangtester.ksh daemon=/home/me/bin/rcshebangtester.pl . /etc/rc.d/rc.subr rc_bg=YES #pexp=/bin/ksh ${daemon} #pexp=/usr/bin/perl -T ${daemon} #pexp=/usr/bin/perl ${daemon} rc_cmd $1 #-=-= /home/me/bin/rcshebangtester.dud -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #!/var/empty #! /dev/null #! /usr/lib/libc.a # swap about above echo 'Busted!' #-=-= /home/me/bin/rcshebangtester.ksh =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #! /bin/ksh -x #! /bin/ksh # swap about above while true do uptime sleep 1 done #-=-= /home/me/bin/rcshebangtester.pl =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #! /usr/bin/perl -T #!/usr/bin/perl # swap about above use strict; use warnings; for(;;) { print time(), \n; sleep 1; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- $ sudo /etc/rc.d/rcshebangtester -d -f start; \ cat /var/run/rc.d/rcshebangtester; echo; sleep 5; \ sudo /etc/rc.d/rcshebangtester -d -f stop doing rc_read_runfile doing rc_check rcshebangtester doing rc_start 1379357218 1379357219 doing rc_wait start doing rc_check doing rc_write_runfile (ok) /usr/bin/perl -T /home/me/bin/rcshebangtester.pl 1379357220 1379357221 1379357222 1379357223 1379357224 doing rc_read_runfile doing rc_check rcshebangtester doing rc_stop doing rc_wait stop doing rc_check doing rc_rm_runfile (ok) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Any other thoughts? -- Craig Skinner | http://twitter.com/Craig_Skinner | http://linkd.in/yGqkv7
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 09/16/13 20:48, Craig R. Skinner wrote: On 2013-09-16 Mon 15:12 PM |, Paul de Weerd wrote: Hi Craig, --- cat bad_script.sh # This is a VERY BAD example of a script! This will break your # shebang thingambob echo Now what... -- I think you'd be better of making sure the first two characters in the file are actually #!: head -n1 ${FILE} | grep '^#!' | sed 's/^#![[:blank:]]*//' Good idea Paul. Implemented below, along with rudimentary testing for a valid interpreter: Index: rc.subr === RCS file: /cvs/src/etc/rc.d/rc.subr,v retrieving revision 1.70 diff -u -r1.70 rc.subr --- rc.subr 11 Jul 2013 09:34:33 - 1.70 +++ rc.subr 16 Sep 2013 18:19:14 - @@ -221,4 +221,15 @@ unset _rcflags _rcuser pexp=${daemon}${daemon_flags:+ ${daemon_flags}} +file ${daemon} | fgrep -q script +{ + shebang=$(head -n 1 ${daemon} | grep '^#!' | sed 's/^#![[:blank:]]*//') + interpreter=$(echo ${shebang} | cut -d' ' -f1) sed can do it all. Really. Notes: - I separate re_quote() cause I think it can be useful in other places. - I think re_quote() is (basic) regex complete. - I don't care if the interpreter is (or seems) nonexistant, as that shouldn't be a runtime error. - I'm sure sed may die horribly if you try to feed it a 9GB oneline file. However, if so, it should not produce any output anyway. ;) If this would ever be considered a real problem, dd(1) would help (as espie already mentioned). re_quote() { sed 's/\([]^$*.\\[]\)/\\\1/g'; } interpreter=$( sed -n 's/^#![[:space:]]*\(.*\)/\1 /p;q' ${daemon} | re_quote) pexp=$interpreter$pexp Moreover, - you probably want to unset $interpreter when done. - we might want to re_quote the entire $pexp later instead. /Alexander + if [[ -f ${interpreter} -x ${interpreter} ]] + then + pexp=${shebang} ${pexp} + else + rc_err $0: invalid interpreter: ${interpreter} + fi +} rcexec=su -l -c ${daemon_class} -s /bin/sh ${daemon_user} -c Test scripts: #-=-= /etc/rc.d/rcshebangtester -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #!/bin/sh #daemon=/home/me/bin/rcshebangtester.dud #daemon=/home/me/bin/rcshebangtester.ksh daemon=/home/me/bin/rcshebangtester.pl . /etc/rc.d/rc.subr rc_bg=YES #pexp=/bin/ksh ${daemon} #pexp=/usr/bin/perl -T ${daemon} #pexp=/usr/bin/perl ${daemon} rc_cmd $1 #-=-= /home/me/bin/rcshebangtester.dud -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #!/var/empty #! /dev/null #! /usr/lib/libc.a # swap about above echo 'Busted!' #-=-= /home/me/bin/rcshebangtester.ksh =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= #! /bin/ksh -x #! /bin/ksh # swap about above while true do uptime sleep 1 done #-=-= /home/me/bin/rcshebangtester.pl =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- #! /usr/bin/perl -T #!/usr/bin/perl # swap about above use strict; use warnings; for(;;) { print time(), \n; sleep 1; } #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- $ sudo /etc/rc.d/rcshebangtester -d -f start; \ cat /var/run/rc.d/rcshebangtester; echo; sleep 5; \ sudo /etc/rc.d/rcshebangtester -d -f stop doing rc_read_runfile doing rc_check rcshebangtester doing rc_start 1379357218 1379357219 doing rc_wait start doing rc_check doing rc_write_runfile (ok) /usr/bin/perl -T /home/me/bin/rcshebangtester.pl 1379357220 1379357221 1379357222 1379357223 1379357224 doing rc_read_runfile doing rc_check rcshebangtester doing rc_stop doing rc_wait stop doing rc_check doing rc_rm_runfile (ok) #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- Any other thoughts?
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On 09/16/13 23:32, Marc Espie wrote: On Mon, Sep 16, 2013 at 11:28:06PM +0200, Alexander Hall wrote: sed can do it all. Really. Notes: - I separate re_quote() cause I think it can be useful in other places. - I think re_quote() is (basic) regex complete. - I don't care if the interpreter is (or seems) nonexistant, as that shouldn't be a runtime error. - I'm sure sed may die horribly if you try to feed it a 9GB oneline file. However, if so, it should not produce any output anyway. ;) If this would ever be considered a real problem, dd(1) would help (as espie already mentioned). ^ here (see below) re_quote() { sed 's/\([]^$*.\\[]\)/\\\1/g'; } interpreter=$( sed -n 's/^#![[:space:]]*\(.*\)/\1 /p;q' ${daemon} | re_quote) pexp=$interpreter$pexp Ah, but what happens when you run that thru a pure binary file that spans a single line ?... That is mentioned just above re_quote... :-) /Alexander
Re: /etc/rc.d/rc.subr; prefix ${pexp} with script interpretor path
On Mon, Sep 16, 2013 at 11:28:06PM +0200, Alexander Hall wrote: sed can do it all. Really. Notes: - I separate re_quote() cause I think it can be useful in other places. - I think re_quote() is (basic) regex complete. - I don't care if the interpreter is (or seems) nonexistant, as that shouldn't be a runtime error. - I'm sure sed may die horribly if you try to feed it a 9GB oneline file. However, if so, it should not produce any output anyway. ;) If this would ever be considered a real problem, dd(1) would help (as espie already mentioned). re_quote() { sed 's/\([]^$*.\\[]\)/\\\1/g'; } interpreter=$( sed -n 's/^#![[:space:]]*\(.*\)/\1 /p;q' ${daemon} | re_quote) pexp=$interpreter$pexp Ah, but what happens when you run that thru a pure binary file that spans a single line ?...