Index: ossp-pkg/rc/00TODO RCS File: /v/ossp/cvs/ossp-pkg/rc/00TODO,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/rc/00TODO,v' 2>/dev/null --- 00TODO 2002/01/31 10:11:43 1.14 +++ 00TODO 2002/01/31 21:14:10 1.15 @@ -1,18 +1,12 @@ 00TODO: Tasks left to accomplish before rc is complete -Spec fehlt - Command interpreter (probably goes in rc.usecase.pod) - Beispiel - Default - Error +Unfinished business + What when multiple command interpreters and one --print or --eval given? + File rc.func totally undocumented, but logic should be clear. Control flow - Errors during execution - Multiple sections given - Wildcard 'all' given - Both wildcard and multiple sections - Avoid a silent failure when giving non-existent run commands (Marcus.) - Use case - give 'restart' command in place of 'start' to stopped prog - User assumes stop implicitly dropped if program not running + Explain logical ordering of multiple section spanning multiple rcfiles. + Give example semantics of a common scenario. + No error semantics in pseudocode. Consider Removing the OSSP_RC_DEACT deactivation feature (thl.) @@ -20,17 +14,50 @@ Offer include directive in config file. Dynamic handling of command interpreter option. Environment of manpage has redundant text. + Interpreter option irgendwo dass hat global scope. + Als variable in %config Section? Must do - Strip local popt code, and move in OSSP popt library. + Strip local getopt and popt code, and use OSSP popt library. Translate rc bourne shell script to ANSI C. Finish man page. Start latex or Docbook guide. If a variable is defined for which no default exists, warn user (Scholli.) +Detailed ;-) project plan +------------------------- +Release v0.8 + Milestone 1, Drop in replacement for OpenPKG. +Release v0.9 + Milestone 2, Additional features in build. +Release v1.0 + Milestone 3, Cleanup and bugfix. +Release v1.2 + Milestone 4, Krasse L2 Logging und eigene Sprache + +Dreams + Log to an L2 channel + Channel specification could go in rc.conf + Processing language + !if !else (conditional processing can cross-reference local config vars) + !print (print something to stdout) + !logit (log something, mstone1-3 to syslog, mstone4 to L2) + !lineno [LAST] (the current line number or last successful command) + !rcfile [EXISTS|ABSOLUTE] (info about an rcfile) + + # Is there a way to merge rcfile and rc processor contexts? + !envarpush (push an environment variable on the rc stack) + !envarpop (pop an environment variable from the rc stack) + + !throw [var] (returns var to rc processor and ask rc to return -1) + !exit [var] (returns var to the rc processor and asks rc to abort execution) + !return (signals end of section and returns var to rc processor) + ... + + /-------------------OSSP rc Inhalt------------------\ | Manpage | | rc.1 Section 1 oder 8-Konflict? | - | rc-sample.5 Vielleicht umnennen rc.usecases.5 | + | rc-sample.5 Vielleicht umnennen rc.samples.5 | | rc.conf.5 Beschreibung aber kein Beispiel | | | | Geliefert | @@ -38,7 +65,7 @@ | rc.conf Ausgekommentet Beispiel | | | | Beispiele | - | rc.example Soll rc.fooboar umgenannt werden | + | rc.example Soll rc.foo umgenannt werden | \---------------------------------------------------/ Pseudocode @@ -46,64 +73,80 @@ * psoudocode implementation of rc * *********************************** -parse options -read and merge all "rc.conf" files - -parse "Locate" - - Locate /cw/etc/rc.d/rc.%{RCFILE:s/^all$/*/} - Locate /cw/local/etc/rc.d/rc.%{RCFILE:s/^all$/*/} - Locate %{RCFILE}/.duerc - Locate ${HOME}/.duerc:m/^(.*)<\/dir>/i - Locate ${HOME}/.duerc.%{RCFILE:s/^\///:s/[\/]/-/g} - Locate path/file/regex:regex_inside_file - -foreach locate { - for each (locate all possible rcfiles after variable expansion and shell globbing) { - continue if (absolute path seen previously) //avoid duplicates - if (filename matches given rcfile && securitycheck(RequireUmask, RequireOwner, RequireGroup)) - load file and grab only a part of the file according to info after colon given in "locate" +parse command line +merge all 'rc.conf' files +read environment variables +build option table + +parse 'Locate' + Locate /cw/etc/rc.d/rc.%{RCFILE:s/^all$/*/} + Locate /cw/local/etc/rc.d/rc.%{RCFILE:s/^all$/*/} + Locate %{RCFILE}/.duerc + Locate ${HOME}/.duerc:m/^(.*)<\/dir>/i + Locate ${HOME}/.duerc.%{RCFILE:s/^\///:s/[\/]/-/g} + Locate path/file/regex:regex_inside_file + +for each 'Locate' { + for each (all rcfiles after variable expansion and shell globbing) { + apply path conversion to rcfilename + continue if (absolute path seen previously) // avoid duplicates + if (filename matches given rcfile) + if (securitycheck(RequireUmask, RequireOwner, RequireGroup)) + read and strip file ('Locate' regex, after colon) } } -foreach located_rcfile_fraction { - parse rcfile into blocks according to --ParseSectionDef - take out %config section according to --NameConfig - take out %common section according to --NameCommon - take out any sections given on command line +for each rcfile_fraction { + parse into blocks according to --ParseSectionDef + take out %config section according to --NameConfig + take out %common section according to --NameCommon + take out %error section according to --NameError + take out %default section according to --NameDefault + app.mapSections; // create the section map } -foreach section { +mapSections () // Map nonexisting %sections to %default +{ // from now on, 'section' implies 'section->lookupMapval' + while (tempSection := ParsedCLI->nextSection) // CLI = command line iface + if (rcfile_fraction->has(tempSection)) + rcfile_fraction->sectionNames += tempSection; + else if (rcfile_fraction->has(%default)) + rcfile_fraction->sectionNames += %default; + else handle error +} + +for each section on command line { if (multiple rcfiles, i.e. all) - sort rcfiles by section priority. - foreach rcfile { + sort rcfiles by section priority (%defaults are last) + for each rcfile { script = ""; script += %config from rcfile - script += rc.env and override it - create_script_for_rcfile(script, section, parent=no) - expand our internal variables - execute, print or printeval script with user & group priveleges + script += rc.env (overriding any duplicate values) + create_rcfile_script(script, section, recurse=no) + expand internal variables + execute, print, or printeval script with user & group priveleges and command interpreter according to options or section header } } EXIT - -create_script_for_rcfile(script, section, parent) +create_rcfile_script(script, section, recurse) { - script += "${body}" //start with a pseudo value + script += "${body}" // start with a pseudo value - if (!parent) { //only one rc.func!? - replace ${body} with %common from rc.func - if no ${body} assume prepend + if (!recurse) { // only one rc.func is possible + if no ${body} in rc.func->%common prepend ${body} to rc.func->%common + replace script->${body} with rc.func->%common } - replace ${body} with %common from rcfile - if no ${body} assume prepend - if (!parent) { //only one rc.func!? - replace ${body} with %section from rc.func - if no ${body} assume prepend + + if no ${body} in rcfile->%common prepend ${body} to rcfile->%common + replace script->${body} with rcfile->%common + if (!recurse) { // only one rc.func is possible + if no ${body} in rc.func->%section prepend ${body} to rc.func->%section + replace script->${body} with rc.func->%section } - replace ${body} with %section from rcfile + replace script->${body} with rcfile->%section - expand references using --ParseSectionRef and calling create_script_for_rcfile(section, parent=yes); + while (ref := ParseSectionRef(script)) + ref->create_rcfile_script(recurse=yes); } Index: ossp-pkg/rc/AUTHORS RCS File: /v/ossp/cvs/ossp-pkg/rc/AUTHORS,v rcsdiff -q -kk '-r1.1' '-r1.2' -u '/v/ossp/cvs/ossp-pkg/rc/AUTHORS,v' 2>/dev/null --- AUTHORS 2002/01/08 15:47:11 1.1 +++ AUTHORS 2002/01/31 21:14:10 1.2 @@ -2,7 +2,7 @@ ======= This is a list of the authors who have written -or edited major parts of the OSSP RC source code. +or edited major parts of the OSSP rc source code. -Ralf S. Engelschall -Michael Schloh +Ralf S. Engelschall +Michael Schloh von Bennewitz Index: ossp-pkg/rc/rc.pod RCS File: /v/ossp/cvs/ossp-pkg/rc/rc.pod,v rcsdiff -q -kk '-r1.25' '-r1.26' -u '/v/ossp/cvs/ossp-pkg/rc/rc.pod,v' 2>/dev/null --- rc.pod 2002/01/31 10:11:43 1.25 +++ rc.pod 2002/01/31 21:14:10 1.26 @@ -52,10 +52,15 @@ [B<--RequireUmask umask>] [B<--RequireOwner uid|name>] [B<--RequireGroup gid|name>] +[B<--ParseEnvAss regex>] [B<--ParseSectionDef regex>] [B<--ParseSectionRef regex>] +[B<--ParseSectionParam regex>] +[B<--ParseTerminal regex>] [B<--NameConfig> name] [B<--NameCommon> name] +[B<--NameDefault> name] +[B<--NameError> name] I I
@@ -176,13 +181,25 @@ group of the F must match gid|name, otherwise it's ignored. +=item B<--ParseConfigAss regex> + +regex matching the variable assignments in a F. + =item B<--ParseSectionDef regex> -regex matching a section within a F. +regex matching a section label in a F. =item B<--ParseSectionRef regex> -regex matching a reference within a F. +regex matching a reference in a F. + +=item B<--ParseSectionParam regex> + +regex matching a section parameter in a F. + +=item B<--ParseTerminal regex> + +regex matching a terminal symbol in a F. See LANGUAGE. =item B<--NameConfig> name @@ -192,6 +209,14 @@ name of the common section, defaults to %common. +=item B<--NameDefault> name + +name of the default section, defaults to %default. + +=item B<--NameError> name + +name of the error section, defaults to %error. + Every command line longoption corresponds to a keyword in the F file. When prefixed with 'OSSP_RC_' and its name in upper case, an option can be set as an environment variable. First, options from the F file are read. @@ -206,17 +231,54 @@ 'OSSP_RC_' and be all upper case. As a security measure, one environment variable exists that is not found as an option elsewhere. This variable deactivates B, and each subsequent usage will return success and -print a 'No commands run: OSSP_RC_DEACT set to yes' error message to the -standard output. +write 'No commands run: OSSP_RC_DEACT set to yes' to the console and syslog +with LOG_USER and LOG_ERR (see syslog(3)). B - Set to 'yes' or 'true' to totally deactivate B +=head1 COMMAND INTERPRETER + +As long as a valid interpreter path is specified in the section labels of a +F, the runcommands resulting from a --eval, --exec, or --print +operation can be written in any runtime-interpreted language. This means that +a perl programmer can write runcommands in perl, and specify the perl +interpreter path in the corresponding section label of the F. A +different programming language can be used for each section, even though this +would complicate inclusion of script from the B<%common> section and +F sections (because each section is associated with only one +interpreter). If the command interpreter in a section label is not specified, +then the Bourne shell will be used by default. See FILES/rc.foo for details. + =head1 RETURN VALUE -1 Error in rc 0 Success 1 Error in command executed by rc +=head1 ERROR HANDLING + +Rich and fine-tuned error handling is possible by writing one or both of the +following sections into F(s). These sections typically reference the +local F's variables ${rc_errcode} and ${rc_errstring} for more +information about which error was encountered and its text. + +=item B<%error> + +If an error condition arises during an F's processing, control will +pass to the B<%error> section whose commands will begin to run. Should no such +B<%error> section exist, rc will stop any rcfile processing and write error +strings to the console and syslog using LOG_USER and LOG_ERR (see syslog(3)). +An empty B<%error> section in each F is synonymous to a +C option (which doesn't exist). + +=item B<%default> + +The commands in the B<%default> section are run when the corresponding +F contains no section label matching the one(s) specified on the +command line. If the appropriate section label doesn't exist and neither does +B<%default>, then an error is assumed and control flows to the B<%error> +section. + =head1 EXAMPLES A runcommand consists of a single program name and one or more sections. The @@ -227,16 +289,22 @@ /usr/local/bin/rc --info /sbin/rc --query lmtp2nntp /cw/etc/rc --conf /etc/rc.conf --debug smtpd stop - /sfw/etc/rc --silent ntpd start sync stop start + /sfw/etc/rc.d/rc.ntpd --silent start sync stop start /usr/local/bin/rc httpd reload # sends a HUP signal -Arguments may also be passed in to B, which will forward them to each -section as it is called. - - /mybin/rc sshd start LOG_USER # calls logger(1) and passes LOG_USER - /etc/rc lmtp2nntp start 2 # sleep for 2 seconds before returning - /etc/rc.d/rc.rsyncd restart 4 # leave a 4 second pause between start and stop - /cw/etc/rc.d/rc.ftpd start 32 # a maximum of 32 users can connect +Arguments in the form of name=value pairs may be passed to the section(s) +given on the command line. In the F, such arguments will appear as +normal configuration variables. They can be referenced as such (by default as +${myarg}). On the command line, the arguments following a section will be +local to the section and unusable by the others. If a argument is needed by +more than one section, then repeat its definition after each section given on +the command line. + + /mybin/rc all start sFac="LOG_USER" # pass LOG_USER as an argument to 'start' + /etc/rc lmtp2nntp start nSleep=2 # sleep for 2 seconds before returning + /etc/rc.d/rc.rsyncd restart nSleep=4 # pause 4 seconds between start and stop + /cw/etc/rc.d/rc.ftpd start nMax=32 # a maximum of 32 users can connect + rc -rdv all stop nSleep=2 start nSleep=4 sLevel="LOG_INFO" bQuiet=1 To evaluate a runcommand for all programs with an identical section name, a short expression can be written into a F<.profile> file. When the shell @@ -259,7 +327,7 @@ more information, inspect the /etc/rc structures provided by the FreeBSD, Solaris, and Red Hat distributions. -rc-sample(5), rc.conf(1), and rcfile(1). +rc-sample(5). =head1 AUTHORS