# SOME DESCRIPTIVE TITLE # Copyright (C) YEAR The FreeBSD Project # This file is distributed under the same license as the FreeBSD Documentation package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: FreeBSD Documentation VERSION\n" "POT-Creation-Date: 2024-09-14 15:00-0300\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. type: YAML Front Matter: description #: documentation/content/en/articles/rc-scripting/_index.adoc:1 #, no-wrap msgid "A guide to writing new rc.d scripts and understanding those already written" msgstr "" #. type: Title = #: documentation/content/en/articles/rc-scripting/_index.adoc:1 #: documentation/content/en/articles/rc-scripting/_index.adoc:12 #, no-wrap msgid "Practical rc.d scripting in BSD" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:45 msgid "Abstract" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:49 msgid "" "Beginners may find it difficult to relate the facts from the formal " "documentation on the BSD [.filename]#rc.d# framework with the practical " "tasks of [.filename]#rc.d# scripting. In this article, we consider a few " "typical cases of increasing complexity, show [.filename]#rc.d# features " "suited for each case, and discuss how they work. Such an examination should " "provide reference points for further study of the design and efficient " "application of [.filename]#rc.d#." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:51 msgid "'''" msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:55 #, no-wrap msgid "Introduction" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:61 msgid "" "The historical BSD had a monolithic startup script, [.filename]#/etc/rc#. " "It was invoked by man:init[8] at system boot time and performed all userland " "tasks required for multi-user operation: checking and mounting file systems, " "setting up the network, starting daemons, and so on. The precise list of " "tasks was not the same in every system; admins needed to customize it. With " "few exceptions, [.filename]#/etc/rc# had to be modified, and true hackers " "liked it." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:67 msgid "" "The real problem with the monolithic approach was that it provided no " "control over the individual components started from [.filename]#/etc/rc#. " "For instance, [.filename]#/etc/rc# could not restart a single daemon. The " "system admin had to find the daemon process by hand, kill it, wait until it " "actually exited, then browse through [.filename]#/etc/rc# for the flags, and " "finally type the full command line to start the daemon again. The task " "would become even more difficult and prone to errors if the service to " "restart consisted of more than one daemon or demanded additional actions. " "In a few words, the single script failed to fulfil what scripts are for: to " "make the system admin's life easier." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:74 msgid "" "Later there was an attempt to split out some parts of [.filename]#/etc/rc# " "for the sake of starting the most important subsystems separately. The " "notorious example was [.filename]#/etc/netstart# to bring up networking. It " "did allow for accessing the network from single-user mode, but it did not " "integrate well into the automatic startup process because parts of its code " "needed to interleave with actions essentially unrelated to networking. That " "was why [.filename]#/etc/netstart# mutated into [.filename]#/etc/rc." "network#. The latter was no longer an ordinary script; it comprised of " "large, tangled man:sh[1] functions called from [.filename]#/etc/rc# at " "different stages of system startup. However, as the startup tasks grew " "diverse and sophisticated, the \"quasi-modular\" approach became even more " "of a drag than the monolithic [.filename]#/etc/rc# had been." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:82 msgid "" "Without a clean and well-designed framework, the startup scripts had to bend " "over backwards to satisfy the needs of rapidly developing BSD-based " "operating systems. It became obvious at last that more steps are necessary " "on the way to a fine-grained and extensible [.filename]#rc# system. Thus " "BSD [.filename]#rc.d# was born. Its acknowledged fathers were Luke Mewburn " "and the NetBSD community. Later it was imported into FreeBSD. Its name " "refers to the location of system scripts for individual services, which is " "in [.filename]#/etc/rc.d#. Soon we will learn about more components of the " "[.filename]#rc.d# system and see how the individual scripts are invoked." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:93 msgid "" "The basic ideas behind BSD [.filename]#rc.d# are _fine modularity_ and " "__code reuse__. _Fine modularity_ means that each basic \"service\" such as " "a system daemon or primitive startup task gets its own man:sh[1] script able " "to start the service, stop it, reload it, check its status. A particular " "action is chosen by the command-line argument to the script. The [." "filename]#/etc/rc# script still drives system startup, but now it merely " "invokes the smaller scripts one by one with the `start` argument. It is " "easy to perform shutdown tasks as well by running the same set of scripts " "with the `stop` argument, which is done by [.filename]#/etc/rc.shutdown#. " "Note how closely this follows the Unix way of having a set of small " "specialized tools, each fulfilling its task as well as possible. _Code " "reuse_ means that common operations are implemented as man:sh[1] functions " "and collected in [.filename]#/etc/rc.subr#. Now a typical script can be " "just a few lines' worth of man:sh[1] code. Finally, an important part of " "the [.filename]#rc.d# framework is man:rcorder[8], which helps [.filename]#/" "etc/rc# to run the small scripts orderly with respect to dependencies " "between them. It can help [.filename]#/etc/rc.shutdown#, too, because the " "proper order for the shutdown sequence is opposite to that of startup." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:101 msgid "" "The BSD [.filename]#rc.d# design is described in crossref:rc-" "scripting[lukem, the original article by Luke Mewburn], and the [." "filename]#rc.d# components are documented in great detail in crossref:rc-" "scripting[manpages, the respective manual pages]. However, it might not " "appear obvious to an [.filename]#rc.d# newbie how to tie the numerous bits " "and pieces together to create a well-styled script for a particular task. " "Therefore this article will try a different approach to describe [." "filename]#rc.d#. It will show which features should be used in a number of " "typical cases, and why. Note that this is not a how-to document because our " "aim is not at giving ready-made recipes, but at showing a few easy entrances " "into the [.filename]#rc.d# realm. Neither is this article a replacement for " "the relevant manual pages. Do not hesitate to refer to them for more formal " "and complete documentation while reading this article." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:105 msgid "" "There are prerequisites to understanding this article. First of all, you " "should be familiar with the man:sh[1] scripting language to master [." "filename]#rc.d#. In addition, you should know how the system performs " "userland startup and shutdown tasks, which is described in man:rc[8]." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:108 msgid "" "This article focuses on the FreeBSD branch of [.filename]#rc.d#. " "Nevertheless, it may be useful to NetBSD developers, too, because the two " "branches of BSD [.filename]#rc.d# not only share the same design but also " "stay similar in their aspects visible to script authors." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:110 #, no-wrap msgid "Outlining the task" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:114 msgid "" "A little consideration before starting `$EDITOR` will not hurt. To write a " "well-tempered [.filename]#rc.d# script for a system service, we should be " "able to answer the following questions first:" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:116 msgid "Is the service mandatory or optional?" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:117 msgid "" "Will the script serve a single program, e.g., a daemon, or perform more " "complex actions?" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:118 msgid "Which other services will our service depend on, and vice versa?" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:120 msgid "" "From the examples that follow we will see why it is important to know the " "answers to these questions." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:122 #, no-wrap msgid "A dummy script" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:125 msgid "" "The following script just emits a message each time the system boots up:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:129 #, no-wrap msgid "#!/bin/sh <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:131 #, no-wrap msgid ". /etc/rc.subr <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:135 #, no-wrap msgid "" "name=\"dummy\" <.>\n" "start_cmd=\"${name}_start\" <.>\n" "stop_cmd=\":\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:140 #, no-wrap msgid "" "dummy_start() <.>\n" "{\n" "\techo \"Nothing started.\"\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:143 #, no-wrap msgid "" "load_rc_config $name <.>\n" "run_rc_command \"$1\" <.>\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:146 msgid "Things to note are:" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:152 msgid "" "➊ An interpreted script should begin with the magic \"shebang\" " "line. That line specifies the interpreter program for the script. Due to " "the shebang line, the script can be invoked exactly like a binary program " "provided that it has the execute bit set. (See man:chmod[1].) For example, " "a system admin can run our script manually, from the command line:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:156 #, no-wrap msgid "# /etc/rc.d/dummy start\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:162 msgid "" "To be properly managed by the [.filename]#rc.d# framework, its scripts need " "to be written in the man:sh[1] language. If you have a service or port that " "uses a binary control utility or a startup routine written in another " "language, install that element in [.filename]#/usr/sbin# (for the system) or " "[.filename]#/usr/local/sbin# (for ports) and call it from a man:sh[1] script " "in the appropriate [.filename]#rc.d# directory." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:167 msgid "" "If you would like to learn the details of why [.filename]#rc.d# scripts must " "be written in the man:sh[1] language, see how [.filename]#/etc/rc# invokes " "them by means of `run_rc_script`, then study the implementation of " "`run_rc_script` in [.filename]#/etc/rc.subr#." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:173 msgid "" "➋ In [.filename]#/etc/rc.subr#, a number of man:sh[1] functions are " "defined for an [.filename]#rc.d# script to use. The functions are " "documented in man:rc.subr[8]. While it is theoretically possible to write " "an [.filename]#rc.d# script without ever using man:rc.subr[8], its functions " "prove extremely handy and make the job an order of magnitude easier. So it " "is no surprise that everybody resorts to man:rc.subr[8] in [.filename]#rc.d# " "scripts. We are not going to be an exception." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:176 msgid "" "An [.filename]#rc.d# script must \"source\"[.filename]#/etc/rc.subr# " "(include it using \"`.`\") _before_ it calls man:rc.subr[8] functions so " "that man:sh[1] has an opportunity to learn the functions. The preferred " "style is to source [.filename]#/etc/rc.subr# first of all." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:180 msgid "" "Some useful functions related to networking are provided by another include " "file, [.filename]#/etc/network.subr#." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:185 msgid "" "➌ [[name-var]]The mandatory variable `name` specifies the name of our " "script. It is required by man:rc.subr[8]. That is, each [.filename]#rc.d# " "script _must_ set `name` before it calls man:rc.subr[8] functions." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:191 msgid "" "Now it is the right time to choose a unique name for our script once and for " "all. We will use it in a number of places while developing the script. The " "content of the name variable needs to match the script name, some parts of " "FreeBSD (e.g., crossref:rc-scripting[rcng-service-jails, service jails] and " "the cpuset feature of the rc framework) depend upon this. As such the " "filename shall also not contain characters which may be troublesome in " "scripting (e.g., do not use a hyphen \"-\" and others)." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:198 msgid "" "The current style of [.filename]#rc.d# scripting is to enclose values " "assigned to variables in double quotes. Keep in mind that it is just a " "style issue that may not always be applicable. You can safely omit quotes " "from around simple words without man:sh[1] metacharacters in them, while in " "certain cases you will need single quotes to prevent any interpretation of " "the value by man:sh[1]. A programmer should be able to tell the language " "syntax from style conventions and use both of them wisely." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:204 msgid "" "➍ The main idea behind man:rc.subr[8] is that an [.filename]#rc.d# " "script provides handlers, or methods, for man:rc.subr[8] to invoke. In " "particular, `start`, `stop`, and other arguments to an [.filename]#rc.d# " "script are handled this way. A method is a man:sh[1] expression stored in a " "variable named `argument_cmd`, where _argument_ corresponds to what can be " "specified on the script's command line. We will see later how man:rc." "subr[8] provides default methods for the standard arguments." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:209 msgid "" "To make the code in [.filename]#rc.d# more uniform, it is common to use " "`${name}` wherever appropriate. Thus a number of lines can be just copied " "from one script to another." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:213 msgid "" "➎ We should keep in mind that man:rc.subr[8] provides default methods " "for the standard arguments. Consequently, we must override a standard " "method with a no-op man:sh[1] expression if we want it to do nothing." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:216 msgid "" "➏ The body of a sophisticated method can be implemented as a " "function. It is a good idea to make the function name meaningful." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:220 msgid "" "It is strongly recommended to add the prefix `${name}` to the names of all " "functions defined in our script so they never clash with the functions from " "man:rc.subr[8] or another common include file." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:224 msgid "" "➐ This call to man:rc.subr[8] loads man:rc.conf[5] variables. Our " "script makes no use of them yet, but it still is recommended to load man:rc." "conf[5] because there can be man:rc.conf[5] variables controlling man:rc." "subr[8] itself." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:227 msgid "" "➑ Usually this is the last command in an [.filename]#rc.d# script. " "It invokes the man:rc.subr[8] machinery to perform the requested action " "using the variables and methods our script has provided." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:229 #, no-wrap msgid "A configurable dummy script" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:239 msgid "" "Now let us add some controls to our dummy script. As you may know, [." "filename]#rc.d# scripts are controlled with man:rc.conf[5]. Fortunately, " "man:rc.subr[8] hides all the complications from us. The following script " "uses man:rc.conf[5] via man:rc.subr[8] to see whether it is enabled in the " "first place, and to fetch a message to show at boot time. These two tasks " "in fact are independent. On the one hand, an [.filename]#rc.d# script can " "just support enabling and disabling its service. On the other hand, a " "mandatory [.filename]#rc.d# script can have configuration variables. We " "will do both things in the same script though:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:243 #: documentation/content/en/articles/rc-scripting/_index.adoc:334 #: documentation/content/en/articles/rc-scripting/_index.adoc:392 #: documentation/content/en/articles/rc-scripting/_index.adoc:624 #: documentation/content/en/articles/rc-scripting/_index.adoc:755 #: documentation/content/en/articles/rc-scripting/_index.adoc:860 #: documentation/content/en/articles/rc-scripting/_index.adoc:893 #: documentation/content/en/articles/rc-scripting/_index.adoc:927 #, no-wrap msgid "#!/bin/sh\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:245 #: documentation/content/en/articles/rc-scripting/_index.adoc:336 #: documentation/content/en/articles/rc-scripting/_index.adoc:394 #: documentation/content/en/articles/rc-scripting/_index.adoc:631 #: documentation/content/en/articles/rc-scripting/_index.adoc:757 #: documentation/content/en/articles/rc-scripting/_index.adoc:862 #: documentation/content/en/articles/rc-scripting/_index.adoc:895 #: documentation/content/en/articles/rc-scripting/_index.adoc:943 #, no-wrap msgid ". /etc/rc.subr\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:248 #, no-wrap msgid "" "name=dummy\n" "rcvar=dummy_enable <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:251 #, no-wrap msgid "" "start_cmd=\"${name}_start\"\n" "stop_cmd=\":\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:255 #, no-wrap msgid "" "load_rc_config $name <.>\n" ": ${dummy_enable:=no} <.>\n" ": ${dummy_msg=\"Nothing started.\"} <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:260 #, no-wrap msgid "" "dummy_start()\n" "{\n" "\techo \"$dummy_msg\" <.>\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:262 #: documentation/content/en/articles/rc-scripting/_index.adoc:972 #, no-wrap msgid "run_rc_command \"$1\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:265 msgid "What changed in this example?" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:267 msgid "" "➊ The variable `rcvar` specifies the name of the ON/OFF knob variable." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:269 msgid "" "➋ Now `load_rc_config` is invoked earlier in the script, before any " "man:rc.conf[5] variables are accessed." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:275 msgid "" "While examining [.filename]#rc.d# scripts, keep in mind that man:sh[1] " "defers the evaluation of expressions in a function until the latter is " "called. Therefore it is not an error to invoke `load_rc_config` as late as " "just before `run_rc_command` and still access man:rc.conf[5] variables from " "the method functions exported to `run_rc_command`. This is because the " "method functions are to be called by `run_rc_command`, which is invoked " "_after_ `load_rc_config`." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:281 msgid "" "➌ A warning will be emitted by `run_rc_command` if `rcvar` itself is " "set, but the indicated knob variable is unset. If your [.filename]#rc.d# " "script is for the base system, you should add a default setting for the knob " "to [.filename]#/etc/defaults/rc.conf# and document it in man:rc.conf[5]. " "Otherwise it is your script that should provide a default setting for the " "knob. The canonical approach to the latter case is shown in the example." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:288 msgid "" "You can make man:rc.subr[8] act as though the knob is set to `ON`, " "irrespective of its current setting, by prefixing the argument to the script " "with `one` or `force`, as in `onestart` or `forcestop`. Keep in mind though " "that `force` has other dangerous effects we will touch upon below, while " "`one` just overrides the ON/OFF knob. E.g., assume that `dummy_enable` is " "`OFF`. The following command will run the `start` method in spite of the " "setting:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:292 #, no-wrap msgid "# /etc/rc.d/dummy onestart\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:299 msgid "" "➍ Now the message to be shown at boot time is no longer hard-coded in " "the script. It is specified by an man:rc.conf[5] variable named " "`dummy_msg`. This is a trivial example of how man:rc.conf[5] variables can " "control an [.filename]#rc.d# script." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:304 msgid "" "The names of all man:rc.conf[5] variables used exclusively by our script " "_must_ have the same prefix: `${name}_`. For example: `dummy_mode`, " "`dummy_state_file`, and so on." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:309 msgid "" "While it is possible to use a shorter name internally, e.g., just `msg`, " "adding the unique prefix `${name}_` to all global names introduced by our " "script will save us from possible collisions with the man:rc.subr[8] " "namespace." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:312 msgid "" "As a rule, [.filename]#rc.d# scripts of the base system need not provide " "defaults for their man:rc.conf[5] variables because the defaults should be " "set in [.filename]#/etc/defaults/rc.conf# instead. On the other hand, [." "filename]#rc.d# scripts for ports should provide the defaults as shown in " "the example." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:316 msgid "" "➎ Here we use `dummy_msg` to actually control our script, i.e., to " "emit a variable message. Use of a shell function is overkill here, since it " "only runs a single command; an equally valid alternative is:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:320 #, no-wrap msgid "start_cmd=\"echo \\\"$dummy_msg\\\"\"\n" msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:323 #, no-wrap msgid "Startup and shutdown of a simple daemon" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:330 msgid "" "We said earlier that man:rc.subr[8] could provide default methods. " "Obviously, such defaults cannot be too general. They are suited for the " "common case of starting and shutting down a simple daemon program. Let us " "assume now that we need to write an [.filename]#rc.d# script for such a " "daemon called `mumbled`. Here it is:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:339 #: documentation/content/en/articles/rc-scripting/_index.adoc:397 #: documentation/content/en/articles/rc-scripting/_index.adoc:634 #, no-wrap msgid "" "name=mumbled\n" "rcvar=mumbled_enable\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:341 #, no-wrap msgid "command=\"/usr/sbin/${name}\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:344 #: documentation/content/en/articles/rc-scripting/_index.adoc:443 #: documentation/content/en/articles/rc-scripting/_index.adoc:649 #: documentation/content/en/articles/rc-scripting/_index.adoc:876 #, no-wrap msgid "" "load_rc_config $name\n" "run_rc_command \"$1\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:348 msgid "" "Pleasingly simple, isn't it? Let us examine our little script. The only new " "thing to note is as follows:" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:352 msgid "" "➊ The `command` variable is meaningful to man:rc.subr[8]. If it is " "set, man:rc.subr[8] will act according to the scenario of serving a " "conventional daemon. In particular, the default methods will be provided " "for such arguments: `start`, `stop`, `restart`, `poll`, and `status`." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:361 msgid "" "The daemon will be started by running `$command` with command-line flags " "specified by `$mumbled_flags`. Thus all the input data for the default " "`start` method are available in the variables set by our script. Unlike " "`start`, other methods may require additional information about the process " "started. For instance, `stop` must know the PID of the process to terminate " "it. In the present case, man:rc.subr[8] will scan through the list of all " "processes, looking for a process with its name equal to `procname`. The " "latter is another variable of meaning to man:rc.subr[8], and its value " "defaults to that of `command`. In other words, when we set `command`, " "`procname` is effectively set to the same value. This enables our script to " "kill the daemon and to check if it is running in the first place." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:368 msgid "" "Some programs are in fact executable scripts. The system runs such a script " "by starting its interpreter and passing the name of the script to it as a " "command-line argument. This is reflected in the list of processes, which " "can confuse man:rc.subr[8]. You should additionally set " "`command_interpreter` to let man:rc.subr[8] know the actual name of the " "process if `$command` is a script." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:374 msgid "" "For each [.filename]#rc.d# script, there is an optional man:rc.conf[5] " "variable that takes precedence over `command`. Its name is constructed as " "follows: `${name}_program`, where `name` is the mandatory variable we " "discussed crossref:rc-scripting[name-var, earlier]. E.g., in this case it " "will be `mumbled_program`. It is man:rc.subr[8] that arranges `${name}" "_program` to override `command`." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:378 msgid "" "Of course, man:sh[1] will permit you to set `${name}_program` from man:rc." "conf[5] or the script itself even if `command` is unset. In that case, the " "special properties of `${name}_program` are lost, and it becomes an ordinary " "variable your script can use for its own purposes. However, the sole use of " "`${name}_program` is discouraged because using it together with `command` " "became an idiom of [.filename]#rc.d# scripting." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:381 msgid "" "For more detailed information on default methods, refer to man:rc.subr[8]." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:383 #, no-wrap msgid "Startup and shutdown of an advanced daemon" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:388 msgid "" "Let us add some meat onto the bones of the previous script and make it more " "complex and featureful. The default methods can do a good job for us, but " "we may need some of their aspects tweaked. Now we will learn how to tune " "the default methods to our needs." msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:400 #, no-wrap msgid "" "command=\"/usr/sbin/${name}\"\n" "command_args=\"mock arguments > /dev/null 2>&1\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:402 #, no-wrap msgid "pidfile=\"/var/run/${name}.pid\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:404 #, no-wrap msgid "required_files=\"/etc/${name}.conf /usr/share/misc/${name}.rules\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:406 #, no-wrap msgid "sig_reload=\"USR1\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:409 #, no-wrap msgid "" "start_precmd=\"${name}_prestart\" <.>\n" "stop_postcmd=\"echo Bye-bye\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:411 #, no-wrap msgid "extra_commands=\"reload plugh xyzzy\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:414 #, no-wrap msgid "" "plugh_cmd=\"mumbled_plugh\" <.>\n" "xyzzy_cmd=\"echo 'Nothing happens.'\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:435 #, no-wrap msgid "" "mumbled_prestart()\n" "{\n" "\tif checkyesno mumbled_smart; then <.>\n" "\t\trc_flags=\"-o smart ${rc_flags}\" <.>\n" "\tfi\n" "\tcase \"$mumbled_mode\" in\n" "\tfoo)\n" "\t\trc_flags=\"-frotz ${rc_flags}\"\n" "\t\t;;\n" "\tbar)\n" "\t\trc_flags=\"-baz ${rc_flags}\"\n" "\t\t;;\n" "\t*)\n" "\t\twarn \"Invalid value for mumbled_mode\" <.>\n" "\t\treturn 1 <.>\n" "\t\t;;\n" "\tesac\n" "\trun_rc_command xyzzy <.>\n" "\treturn 0\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:440 #, no-wrap msgid "" "mumbled_plugh() <.>\n" "{\n" "\techo 'A hollow voice says \"plugh\".'\n" "}\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:448 msgid "" "➊ Additional arguments to `$command` can be passed in " "`command_args`. They will be added to the command line after " "`$mumbled_flags`. Since the final command line is passed to `eval` for its " "actual execution, input and output redirections can be specified in " "`command_args`." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:455 msgid "" "_Never_ include dashed options, like `-X` or `--foo`, in `command_args`. " "The contents of `command_args` will appear at the end of the final command " "line, hence they are likely to follow arguments present in `${name}_flags`; " "but most commands will not recognize dashed options after ordinary " "arguments. A better way of passing additional options to `$command` is to " "add them to the beginning of `${name}_flags`. Another way is to modify " "`rc_flags` crossref:rc-scripting[rc-flags, as shown later]." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:459 msgid "" "➋ A good-mannered daemon should create a _pidfile_ so that its " "process can be found more easily and reliably. The variable `pidfile`, if " "set, tells man:rc.subr[8] where it can find the pidfile for its default " "methods to use." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:464 msgid "" "In fact, man:rc.subr[8] will also use the pidfile to see if the daemon is " "already running before starting it. This check can be skipped by using the " "`faststart` argument." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:469 msgid "" "➌ If the daemon cannot run unless certain files exist, just list them " "in `required_files`, and man:rc.subr[8] will check that those files do exist " "before starting the daemon. There also are `required_dirs` and " "`required_vars` for directories and environment variables, respectively. " "They all are described in detail in man:rc.subr[8]." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:473 msgid "" "The default method from man:rc.subr[8] can be forced to skip the " "prerequisite checks by using `forcestart` as the argument to the script." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:479 msgid "" "➍ We can customize signals to send to the daemon in case they differ " "from the well-known ones. In particular, `sig_reload` specifies the signal " "that makes the daemon reload its configuration; it is SIGHUP by default. " "Another signal is sent to stop the daemon process; the default is SIGTERM, " "but this can be changed by setting `sig_stop` appropriately." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:484 msgid "" "The signal names should be specified to man:rc.subr[8] without the `SIG` " "prefix, as it is shown in the example. The FreeBSD version of man:kill[1] " "can recognize the `SIG` prefix, but the versions from other OS types may not." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:489 msgid "" "➎➏ Performing additional tasks before or after the default " "methods is easy. For each command-argument supported by our script, we can " "define `argument_precmd` and `argument_postcmd`. These man:sh[1] commands " "are invoked before and after the respective method, as it is evident from " "their names." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:495 msgid "" "Overriding a default method with a custom `argument_cmd` still does not " "prevent us from making use of `argument_precmd` or `argument_postcmd` if we " "need to. In particular, the former is good for checking custom, " "sophisticated conditions that should be met before performing the command " "itself. Using `argument_precmd` along with `argument_cmd` lets us logically " "separate the checks from the action." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:498 msgid "" "Do not forget that you can cram any valid man:sh[1] expressions into the " "methods, pre-, and post-commands you define. Just invoking a function that " "makes the real job is a good style in most cases, but never let style limit " "your understanding of what is going on behind the curtain." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:501 msgid "" "➐ If we would like to implement custom arguments, which can also be " "thought of as _commands_ to our script, we need to list them in " "`extra_commands` and provide methods to handle them." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:509 msgid "" "The `reload` command is special. On the one hand, it has a preset method in " "man:rc.subr[8]. On the other hand, `reload` is not offered by default. The " "reason is that not all daemons use the same reload mechanism and some have " "nothing to reload at all. So we need to ask explicitly that the builtin " "functionality be provided. We can do so via `extra_commands`." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:513 msgid "" "What do we get from the default method for `reload`? Quite often daemons " "reload their configuration upon reception of a signal - typically, SIGHUP. " "Therefore man:rc.subr[8] attempts to reload the daemon by sending a signal " "to it. The signal is preset to SIGHUP but can be customized via " "`sig_reload` if necessary." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:518 msgid "" "➑⓮ Our script supports two non-standard commands, `plugh` and " "`xyzzy`. We saw them listed in `extra_commands`, and now it is time to " "provide methods for them. The method for `xyzzy` is just inlined while that " "for `plugh` is implemented as the `mumbled_plugh` function." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:522 msgid "" "Non-standard commands are not invoked during startup or shutdown. Usually " "they are for the system admin's convenience. They can also be used from " "other subsystems, e.g., man:devd[8] if specified in man:devd.conf[5]." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:525 msgid "" "The full list of available commands can be found in the usage line printed " "by man:rc.subr[8] when the script is invoked without arguments. For " "example, here is the usage line from the script under study:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:530 #, no-wrap msgid "" "# /etc/rc.d/mumbled\n" "Usage: /etc/rc.d/mumbled [fast|force|one](start|stop|restart|rcvar|reload|plugh|xyzzy|status|poll)\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:537 msgid "" "⓭ A script can invoke its own standard or non-standard commands if " "needed. This may look similar to calling functions, but we know that " "commands and shell functions are not always the same thing. For instance, " "`xyzzy` is not implemented as a function here. In addition, there can be a " "pre-command and post-command, which should be invoked orderly. So the " "proper way for a script to run its own command is by means of man:rc." "subr[8], as shown in the example." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:543 msgid "" "➒ A handy function named `checkyesno` is provided by man:rc.subr[8]. " "It takes a variable name as its argument and returns a zero exit code if and " "only if the variable is set to `YES`, or `TRUE`, or `ON`, or `1`, case " "insensitive; a non-zero exit code is returned otherwise. In the latter " "case, the function tests the variable for being set to `NO`, `FALSE`, `OFF`, " "or `0`, case insensitive; it prints a warning message if the variable " "contains anything else, i.e., junk." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:545 msgid "" "Keep in mind that for man:sh[1] a zero exit code means true and a non-zero " "exit code means false." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:550 msgid "" "The `checkyesno` function takes a __variable name__. Do not pass the " "expanded _value_ of a variable to it; it will not work as expected." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:552 msgid "The following is the correct usage of `checkyesno`:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:558 #, no-wrap msgid "" "if checkyesno mumbled_enable; then\n" " foo\n" "fi\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:561 msgid "" "On the contrary, calling `checkyesno` as shown below will not work - at " "least not as expected:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:567 #, no-wrap msgid "" "if checkyesno \"${mumbled_enable}\"; then\n" " foo\n" "fi\n" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:572 msgid "" "➓ [[rc-flags]]We can affect the flags to be passed to `$command` by " "modifying `rc_flags` in `$start_precmd`." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:576 msgid "" "⓫ In certain cases we may need to emit an important message that " "should go to `syslog` as well. This can be done easily with the following " "man:rc.subr[8] functions: `debug`, `info`, `warn`, and `err`. The latter " "function then exits the script with the code specified." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:580 msgid "" "⓬ The exit codes from methods and their pre-commands are not just " "ignored by default. If `argument_precmd` returns a non-zero exit code, the " "main method will not be performed. In turn, `argument_postcmd` will not be " "invoked unless the main method returns a zero exit code." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:584 msgid "" "However, man:rc.subr[8] can be instructed from the command line to ignore " "those exit codes and invoke all commands anyway by prefixing an argument " "with `force`, as in `forcestart`." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:587 #, no-wrap msgid "Connecting a script to the rc.d framework" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:594 msgid "" "After a script has been written, it needs to be integrated into [." "filename]#rc.d#. The crucial step is to install the script in [.filename]#/" "etc/rc.d# (for the base system) or [.filename]#/usr/local/etc/rc.d# (for " "ports). Both [.filename]#bsd.prog.mk# and [.filename]#bsd.port.mk# provide " "convenient hooks for that, and usually you do not have to worry about the " "proper ownership and mode. System scripts should be installed from [." "filename]#src/libexec/rc/rc.d# through the [.filename]#Makefile# found " "there. Port scripts can be installed using `USE_RC_SUBR` as described " "extref:{porters-handbook}[in the Porter's Handbook, rc-scripts]." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:599 msgid "" "However, we should consider beforehand the place of our script in the system " "startup sequence. The service handled by our script is likely to depend on " "other services. For instance, a network daemon cannot function without the " "network interfaces and routing up and running. Even if a service seems to " "demand nothing, it can hardly start before the basic filesystems have been " "checked and mounted." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:605 msgid "" "We mentioned man:rcorder[8] already. Now it is time to have a close look at " "it. In a nutshell, man:rcorder[8] takes a set of files, examines their " "contents, and prints a dependency-ordered list of files from the set to " "`stdout`. The point is to keep dependency information _inside_ the files so " "that each file can speak for itself only. A file can specify the following " "information:" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:607 msgid "" "the names of the \"conditions\" (which means services to us) it __provides__;" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:608 msgid "the names of the \"conditions\" it __requires__;" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:609 msgid "the names of the \"conditions\" this file should run __before__;" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:610 msgid "" "additional _keywords_ that can be used to select a subset from the whole set " "of files (man:rcorder[8] can be instructed via options to include or omit " "the files having particular keywords listed.)" msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:615 msgid "" "It is no surprise that man:rcorder[8] can handle only text files with a " "syntax close to that of man:sh[1]. That is, special lines understood by man:" "rcorder[8] look like man:sh[1] comments. The syntax of such special lines " "is rather rigid to simplify their processing. See man:rcorder[8] for " "details." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:618 msgid "" "Besides using man:rcorder[8] special lines, a script can insist on its " "dependency upon another service by just starting it forcibly. This can be " "needed when the other service is optional and will not start by itself " "because the system admin has disabled it mistakenly in man:rc.conf[5]." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:620 msgid "" "With this general knowledge in mind, let us consider the simple daemon " "script enhanced with dependency stuff:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:629 #, no-wrap msgid "" "# PROVIDE: mumbled oldmumble <.>\n" "# REQUIRE: DAEMON cleanvar frotz <.>\n" "# BEFORE: LOGIN <.>\n" "# KEYWORD: nojail shutdown <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:637 #, no-wrap msgid "" "command=\"/usr/sbin/${name}\"\n" "start_precmd=\"${name}_prestart\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:646 #, no-wrap msgid "" "mumbled_prestart()\n" "{\n" "\tif ! checkyesno frotz_enable && \\\n" "\t ! /etc/rc.d/frotz forcestatus 1>/dev/null 2>&1; then\n" "\t\tforce_depend frotz || return 1 <.>\n" "\tfi\n" "\treturn 0\n" "}\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:652 msgid "As before, detailed analysis follows:" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:655 msgid "" "➊ That line declares the names of \"conditions\" our script " "provides. Now other scripts can record a dependency on our script by those " "names." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:660 msgid "" "Usually a script specifies a single condition provided. However, nothing " "prevents us from listing several conditions there, e.g., for compatibility " "reasons." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:662 msgid "" "In any case, the name of the main, or the only, `PROVIDE:` condition should " "be the same as `${name}`." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:666 msgid "" "➋➌ So our script indicates which \"conditions\" provided by " "other scripts it depends on. According to the lines, our script asks man:" "rcorder[8] to put it after the script(s) providing [.filename]#DAEMON# and [." "filename]#cleanvar#, but before that providing [.filename]#LOGIN#." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:672 msgid "" "The `BEFORE:` line should not be abused to work around an incomplete " "dependency list in the other script. The appropriate case for using `BEFORE:" "` is when the other script does not care about ours, but our script can do " "its task better if run before the other one. A typical real-life example is " "the network interfaces vs. the firewall: While the interfaces do not depend " "on the firewall in doing their job, the system security will benefit from " "the firewall being ready before there is any network traffic." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:676 msgid "" "Besides conditions corresponding to a single service each, there are meta-" "conditions and their \"placeholder\" scripts used to ensure that certain " "groups of operations are performed before others. These are denoted by [." "filename]#UPPERCASE# names. Their list and purposes can be found in man:" "rc[8]." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:682 msgid "" "Keep in mind that putting a service name in the `REQUIRE:` line does not " "guarantee that the service will actually be running by the time our script " "starts. The required service may fail to start or just be disabled in man:" "rc.conf[5]. Obviously, man:rcorder[8] cannot track such details, and man:" "rc[8] will not do that either. Consequently, the application started by our " "script should be able to cope with any required services being unavailable. " "In certain cases, we can help it as discussed crossref:rc-" "scripting[forcedep, below]" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:687 msgid "" "[[keywords]]➍ As we remember from the above text, man:rcorder[8] " "keywords can be used to select or leave out some scripts. Namely any man:" "rcorder[8] consumer can specify through `-k` and `-s` options which keywords " "are on the \"keep list\" and \"skip list\", respectively. From all the " "files to be dependency sorted, man:rcorder[8] will pick only those having a " "keyword from the keep list (unless empty) and not having a keyword from the " "skip list." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:690 msgid "" "In FreeBSD, man:rcorder[8] is used by [.filename]#/etc/rc# and [.filename]#/" "etc/rc.shutdown#. These two scripts define the standard list of FreeBSD [." "filename]#rc.d# keywords and their meanings as follows:" msgstr "" #. type: Labeled list #: documentation/content/en/articles/rc-scripting/_index.adoc:691 #, no-wrap msgid "nojail" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:693 msgid "" "The service is not for man:jail[8] environment. The automatic startup and " "shutdown procedures will ignore the script if inside a jail." msgstr "" #. type: Labeled list #: documentation/content/en/articles/rc-scripting/_index.adoc:694 #, no-wrap msgid "nostart" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:697 msgid "" "The service is to be started manually or not started at all. The automatic " "startup procedure will ignore the script. In conjunction with the [." "filename]#shutdown# keyword, this can be used to write scripts that do " "something only at system shutdown." msgstr "" #. type: Labeled list #: documentation/content/en/articles/rc-scripting/_index.adoc:698 #, no-wrap msgid "shutdown" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:699 msgid "" "This keyword is to be listed __explicitly__ if the service needs to be " "stopped before system shutdown." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:712 msgid "" "When the system is going to shut down, [.filename]#/etc/rc.shutdown# runs. " "It assumes that most [.filename]#rc.d# scripts have nothing to do at that " "time. Therefore [.filename]#/etc/rc.shutdown# selectively invokes [." "filename]#rc.d# scripts with the [.filename]#shutdown# keyword, effectively " "ignoring the rest of the scripts. For even faster shutdown, [.filename]#/" "etc/rc.shutdown# passes the [.filename]#faststop# command to the scripts it " "runs so that they skip preliminary checks, e.g., the pidfile check. As " "dependent services should be stopped before their prerequisites, [." "filename]#/etc/rc.shutdown# runs the scripts in reverse dependency order. " "If writing a real [.filename]#rc.d# script, you should consider whether it " "is relevant at system shutdown time. E.g., if your script does its work in " "response to the [.filename]#start# command only, then you need not to " "include this keyword. However, if your script manages a service, it is " "probably a good idea to stop it before the system proceeds to the final " "stage of its shutdown sequence described in man:halt[8]. In particular, a " "service should be stopped explicitly if it needs considerable time or " "special actions to shut down cleanly. A typical example of such a service " "is a database engine." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:716 msgid "" "[[forcedep]]➎ To begin with, `force_depend` should be used with much " "care. It is generally better to revise the hierarchy of configuration " "variables for your [.filename]#rc.d# scripts if they are interdependent." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:725 msgid "" "If you still cannot do without `force_depend`, the example offers an idiom " "of how to invoke it conditionally. In the example, our `mumbled` daemon " "requires that another one, `frotz`, be started in advance. However, `frotz` " "is optional, too; and man:rcorder[8] knows nothing about such details. " "Fortunately, our script has access to all man:rc.conf[5] variables. If " "`frotz_enable` is true, we hope for the best and rely on [.filename]#rc.d# " "to have started `frotz`. Otherwise we forcibly check the status of " "`frotz`. Finally, we enforce our dependency on `frotz` if it is found to be " "not running. A warning message will be emitted by `force_depend` because it " "should be invoked only if a misconfiguration has been detected." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:727 #, no-wrap msgid "Giving more flexibility to an rc.d script" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:736 msgid "" "When invoked during startup or shutdown, an [.filename]#rc.d# script is " "supposed to act on the entire subsystem it is responsible for. E.g., [." "filename]#/etc/rc.d/netif# should start or stop all network interfaces " "described by man:rc.conf[5]. Either task can be uniquely indicated by a " "single command argument such as `start` or `stop`. Between startup and " "shutdown, [.filename]#rc.d# scripts help the admin to control the running " "system, and it is when the need for more flexibility and precision arises. " "For instance, the admin may want to add the settings of a new network " "interface to man:rc.conf[5] and then to start it without interfering with " "the operation of the existing interfaces. Next time the admin may need to " "shut down a single network interface. In the spirit of the command line, " "the respective [.filename]#rc.d# script calls for an extra argument, the " "interface name." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:739 msgid "" "Fortunately, man:rc.subr[8] allows for passing any number of arguments to " "script's methods (within the system limits). Due to that, the changes in " "the script itself can be minimal." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:744 msgid "" "How can man:rc.subr[8] gain access to the extra command-line arguments. " "Should it just grab them directly? Not by any means. Firstly, an man:sh[1] " "function has no access to the positional parameters of its caller, but man:" "rc.subr[8] is just a sack of such functions. Secondly, the good manner of [." "filename]#rc.d# dictates that it is for the main script to decide which " "arguments are to be passed to its methods." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:748 msgid "" "So the approach adopted by man:rc.subr[8] is as follows: `run_rc_command` " "passes on all its arguments but the first one to the respective method " "verbatim. The first, omitted, argument is the name of the method itself: " "`start`, `stop`, etc. It will be shifted out by `run_rc_command`, so what " "is `$2` in the original command line will be presented as `$1` to the " "method, and so on." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:751 msgid "" "To illustrate this opportunity, let us modify the primitive dummy script so " "that its messages depend on the additional arguments supplied. Here we go:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:763 #, no-wrap msgid "" "name=\"dummy\"\n" "start_cmd=\"${name}_start\"\n" "stop_cmd=\":\"\n" "kiss_cmd=\"${name}_kiss\"\n" "extra_commands=\"kiss\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:772 #, no-wrap msgid "" "dummy_start()\n" "{\n" " if [ $# -gt 0 ]; then <.>\n" " echo \"Greeting message: $*\"\n" " else\n" " echo \"Nothing started.\"\n" " fi\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:788 #, no-wrap msgid "" "dummy_kiss()\n" "{\n" " echo -n \"A ghost gives you a kiss\"\n" " if [ $# -gt 0 ]; then <.>\n" " echo -n \" and whispers: $*\"\n" " fi\n" " case \"$*\" in\n" " *[.!?])\n" " echo\n" " ;;\n" " *)\n" " echo .\n" " ;;\n" " esac\n" "}\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:791 #, no-wrap msgid "" "load_rc_config $name\n" "run_rc_command \"$@\" <.>\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:794 msgid "What essential changes can we notice in the script?" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:799 msgid "" "➊ All arguments you type after `start` can end up as positional " "parameters to the respective method. We can use them in any way according " "to our task, skills, and fancy. In the current example, we just pass all of " "them to man:echo[1] as one string in the next line - note `$*` within the " "double quotes. Here is how the script can be invoked now:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:804 #, no-wrap msgid "" "# /etc/rc.d/dummy start\n" "Nothing started.\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:807 #, no-wrap msgid "" "# /etc/rc.d/dummy start Hello world!\n" "Greeting message: Hello world!\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:811 msgid "" "➋ The same applies to any method our script provides, not only to a " "standard one. We have added a custom method named `kiss`, and it can take " "advantage of the extra arguments not less than `start` does. E.g.:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:816 #, no-wrap msgid "" "# /etc/rc.d/dummy kiss\n" "A ghost gives you a kiss.\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:819 #, no-wrap msgid "" "# /etc/rc.d/dummy kiss Once I was Etaoin Shrdlu...\n" "A ghost gives you a kiss and whispers: Once I was Etaoin Shrdlu...\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:822 msgid "" "➌ If we want just to pass all extra arguments to any method, we can " "merely substitute `\"$@\"` for `\"$1\"` in the last line of our script, " "where we invoke `run_rc_command`." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:828 msgid "" "An man:sh[1] programmer ought to understand the subtle difference between " "`$*` and `$@` as the ways to designate all positional parameters. For its " "in-depth discussion, refer to a good handbook on man:sh[1] scripting. _Do " "not_ use the expressions until you fully understand them because their " "misuse will result in buggy and insecure scripts." msgstr "" #. type: delimited block = 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:835 msgid "" "Currently `run_rc_command` may have a bug that prevents it from keeping the " "original boundaries between arguments. That is, arguments with embedded " "whitespace may not be processed correctly. The bug stems from `$*` misuse." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:838 #, no-wrap msgid "Making a script ready for Service Jails" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:841 msgid "" "Scripts which start a long running service are suitable for service jails, " "and should come with a suitable service jail configuration." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:843 msgid "" "Some examples of scripts which are not suitable to run in a service jail:" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:845 msgid "" "any script which in the start command only changes a runtime setting for " "programs or the kernel," msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:846 msgid "or tries to mount something," msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:847 msgid "or finds and deletes files" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:849 msgid "" "Scripts not suitable to run in a service jail need to prevent the use within " "service jails." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:851 msgid "" "A script with a long running service which needs to do something listed " "above before the start or after the stop, can either be split-up into two " "scripts with dependencies, or use the precommand and postcommand parts of " "the script to perform this action." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:854 msgid "" "By default, only the start and stop parts of a script are run within a " "service jail, the rest is run outside the jail. As such any setting used in " "the start/stop parts of the script can not be set from e.g. a precommand." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:856 msgid "" "To make a script ready for use with extref:../../books/handbook/jails/" "#service-jails[Service Jails], only one more config line needs to be " "inserted:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:866 #: documentation/content/en/articles/rc-scripting/_index.adoc:899 #, no-wrap msgid "" "name=\"dummy\"\n" "start_cmd=\"${name}_start\"\n" "stop_cmd=\":\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:868 #, no-wrap msgid ": ${dummy_svcj_options:=\"\"} <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:873 #: documentation/content/en/articles/rc-scripting/_index.adoc:904 #, no-wrap msgid "" "dummy_start()\n" "{\n" " echo \"Nothing started.\"\n" "}\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:880 msgid "" "➊ If it makes sense that the script runs in a jail, it must have an " "overridable service jails configuration. If it does not need network access " "or access to any other resource which is restricted in jails, an empty " "config like displayed is enough." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:885 msgid "" "Strictly speaking an empty config is not needed, but it explicitly describes " "that the script is service jails ready, and that it does not need additional " "jail permissions. As such it is highly recommended to add such an empty " "config in such a case. The most common option to use is \"net_basic\", " "which enables the use of the hosts IPv4 and IPv6 addresses. All possible " "options are explained in man:rc.conf[5]." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:887 msgid "" "If a setting for the start/stop depends on variables from the rc-framework " "(e.g., set inside man:rc.conf[5]), this needs to be handled by " "``load_rc_config`` and ``run_rc_command`` instead of inside a precommand." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:889 msgid "" "If for some reason a script can not be run within a service jail, e.g., " "because it is not possible to run or it does not make sense to run it in a " "jail, use the following:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:908 #, no-wrap msgid "" "load_rc_config $name\n" "dummy_svcj=\"NO\"\t\t# does not make sense to run in a svcj <.>\n" "run_rc_command \"$1\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:911 msgid "" "➊ The disabling needs to happen after the ``load_rc_config`` call, " "else a man:rc.conf[5] setting may override it." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:913 #, no-wrap msgid "Advanced rc-scripting: Instancing" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:921 msgid "" "Sometimes it is useful to run several instances of a service. Typically you " "want to be able to start/stop such instances independently, and you want to " "have a separate config file for each instance. Each instance should be " "started at boot, survive updates, and benefit from updates." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:923 msgid "Here is an example of a rc script which supports this:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:941 #, no-wrap msgid "" "#\n" "# PROVIDE: dummy\n" "# REQUIRE: NETWORKING SERVERS\n" "# KEYWORD: shutdown\n" "#\n" "# Add these following line to /etc/rc.conf.local or /etc/rc.conf\n" "# to enable this service:\n" "#\n" "# dummy_enable (bool):\tSet it to YES to enable dummy on startup.\n" "#\t\t\tDefault: NO\n" "# dummy_user (string):\tUser account to run with.\n" "#\t\t\tDefault: www\n" "#\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:954 #, no-wrap msgid "" "case $0 in <.>\n" "/etc/rc*)\n" "\t# during boot (shutdown) $0 is /etc/rc (/etc/rc.shutdown),\n" "\t# so get the name of the script from $_file\n" "\tname=$_file\n" "\t;;\n" "*)\n" "\tname=$0\n" "\t;;\n" "esac\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:959 #, no-wrap msgid "" "name=${name##*/} <.>\n" "rcvar=\"${name}_enable\" <.>\n" "desc=\"Short description of this service\"\n" "command=\"/usr/local/sbin/dummy\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:961 #, no-wrap msgid "load_rc_config \"$name\"\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:965 #, no-wrap msgid "" "eval \"${rcvar}=\\${${rcvar}:-'NO'}\" <.>\n" "eval \"${name}_svcj_options=\\${${name}_svcj_options:-'net_basic'}\" <.>\n" "eval \"_dummy_user=\\${${name}_user:-'www'}\" <.>\n" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:970 #, no-wrap msgid "" "_dummy_configname=/usr/local/etc/${name}.cfg <.>\n" "pidfile=/var/run/dummy/${name}.pid\n" "required_files ${_dummy_configname}\n" "command_args=\"-u ${_dummy_user} -c ${_dummy_configfile} -p ${pidfile}\"\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:978 msgid "" "➊ and ➋ make sure to set the name variable to the man:" "basename[1] of the script name. If the filename is [.filename]#/usr/local/" "etc/rc.d/dummy#, name is set to [.filename]#dummy#. This way changing the " "filename of the rc script changes automatically the content of the name " "variable." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:981 msgid "" "➌ specifies the variable name which is used in [.filename]#rc.conf# " "to enable this service based upon the filename of this script. In this " "example this resolves to dummy_enable." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:983 msgid "➍ makes sure the default for the _enable variable is NO." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:986 msgid "" "➎ is an example of having some defaults for service specific " "framework variables, in this case the service jails options." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:988 msgid "" "➏ and ➐ set variables internal to the script (pay attention to " "the underscore in front of _dummy_user to make it different from dummy_user " "which can be set in [.filename]#rc.conf#)." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:991 msgid "" "The part in ➎ is for variables which are not used inside the script " "itself but in the rc framework. All the variables which are used as " "parameters somewhere in the script are assigned to a generic variable like " "in ➐ to make it more easy to reference them (no need to eval them at " "each place of use)." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:994 msgid "" "This script will now behave differently if the start script has a different " "name. This allows to create symlinks to it:" msgstr "" #. type: delimited block . 4 #: documentation/content/en/articles/rc-scripting/_index.adoc:1000 #, no-wrap msgid "" "# ln -s dummy /usr/local/etc/rc.d/dummy_foo\n" "# sysrc dummy_foo_enable=YES\n" "# service dummy_foo start\n" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:1005 msgid "" "The above creates an instance of the dummy service with the name dummy_foo. " "It does not use the config file [.filename]#/usr/local/etc/dummy.cfg# but " "the config file [.filename]#/usr/local/etc/dummy_foo.cfg# (➐), and it " "uses the PID file [.filename]#/var/run/dummy/dummy_foo.pid# instead of [." "filename]#/var/run/dummy/dummy.pid#." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:1012 msgid "" "The services dummy and dummy_foo can be managed independently of each other, " "while having the start script update itself on package update (due to the " "symlink). This does not update the REQUIRE line, as such there is no easy " "way of depending on a specific instance. To depend upon a specific instance " "in the startup order a copy needs to be made instead of using a symlink. " "This prevents the automatic pick-up of changes to the start script when an " "update is installed." msgstr "" #. type: Title == #: documentation/content/en/articles/rc-scripting/_index.adoc:1014 #, no-wrap msgid "Further reading" msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:1018 msgid "" "[[lukem]]http://www.mewburn.net/luke/papers/rc.d.pdf[The original article by " "Luke Mewburn] offers a general overview of [.filename]#rc.d# and detailed " "rationale for its design decisions. It provides insight on the whole [." "filename]#rc.d# framework and its place in a modern BSD operating system." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:1021 msgid "" "[[manpages]]The manual pages man:rc[8], man:rc.subr[8], and man:rcorder[8] " "document the [.filename]#rc.d# components in great detail. You cannot fully " "use the [.filename]#rc.d# power without studying the manual pages and " "referring to them while writing your own scripts." msgstr "" #. type: Plain text #: documentation/content/en/articles/rc-scripting/_index.adoc:1025 msgid "" "The major source of working, real-life examples is [.filename]#/etc/rc.d# in " "a live system. Its contents are easy and pleasant to read because most " "rough corners are hidden deep in man:rc.subr[8]. Keep in mind though that " "the [.filename]#/etc/rc.d# scripts were not written by angels, so they might " "suffer from bugs and suboptimal design decisions. Now you can improve them!" msgstr ""