How to use init-functions? [closed]
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Every Operating System has Librarys. Most of them gives you the opportunity to do more ore to write less code. inti-functions is one of these Librarys but. What is init-functions and how to use it?
init-functions is an artifact of SysV init, which is generally speaking an antiquated chunk of code that should never be used for new development. Modern best practice is to use a proper process supervision system (systemd, upstart, runit, launchd, etc) — not traditional «init scripts».
See the sample run scripts at smarden.org/runit/runscripts.html — you’ll note that they’re pretty much universally under five lines total, and thus don’t need any kind of library support at all. Other process supervision systems’ configuration may be less terse, but that they make init-functions outdated and irrelevant is universal.
1 Answer 1
In Linux you are able to use init-functions to manage deamons and protocol in a colored & uniform way. This is way easier to handle than recolor every answer.
It is stored in /lib/lsb/ under the name init-functions .
#!/bin/bash # Script by Amir Boudani ©Amir Boudani source /lib/lsb/init-functions # Importing init-functions - log messages # Use for importing other scripts ore else: "source" / "." # Use at the beginning of the path "/" to say that the path has to start from the root directory log_success_msg "Starting test.sh" || true echo log_action_msg "Info message" || true # Info message log_success_msg "Checking Files" || true # Success message log_warning_msg "Free storage is under 10%" || true # Warning message log_failure_msg "Starting unknown script files" || false # Failure message echo log_end_msg 0 || true # End message - success - resetting the line above -> log_daemon_msg log_end_msg 1 || true # End message - failure - resetting the line above -> log_daemon_msg log_end_msg 255 || true # End message - warning - resetting the line above -> log_daemon_msg echo log_progress_msg "copying file 2123" # One of the line resetting comands - progress echo echo log_daemon_msg "Integrate files" || true sleep 2 log_end_msg 0 || true log_daemon_msg "Checkt if the directory 4234 exist" || true sleep 2 log_end_msg 1 || true log_daemon_msg "Storage space checking " || true sleep 2 log_end_msg 255 || true echo echo log_daemon_msg "Checking Filestorage" || true sleep 1 log_progress_msg "Checking File 1" || true sleep 1 log_progress_msg "Checking File 2" || true sleep 1 log_progress_msg "Checking File 3" || true sleep 1 log_progress_msg "Checking File 4" || true sleep 1 log_end_msg 0 || true echo #---------------------------------------------------------------# Method 1 - not working for commands that are self responding $checker # A variable that doesn't exist. To trigger an error code log_daemon_msg "Check if the last command was an Error" || true if [ "$?" -eq "0" ] # "$?" is the errorcode number of the last command. | 0 = There was no Errors | 1 = Error code 1 then log_end_msg 0 || true else log_end_msg 1 || true echo " There went something wrong. see log" fi #---------------------------------------------------------------# A way to check if a directory exist #if [ -d "/opt/scripts" ] # Check if directory exist - example at this line: if directory /opt/scripts exist # -d = check if the following directory exitst # -a = check if the following file exsist #if [ ! -d "/opt/scripts" ] # ! is a negativ operator - example at this line: if directory /opt/scripts NOT exist # You can actually use the ! operator anywhere #---------------------------------------------------------------# Method 2 - working for self responding commands. but the log_daemon_msg ist not working so we take log_succes/warning/failure_msg echo echo "type in: false / true / (nothing)" read var1 case $var1 in # Check if variable var1 is true true) log_success_msg "Check if var1 is true" || true ;; false) log_warning_msg "Check if var1 is true" || true echo -e " \e[33mvar1 is false.\e[0m" ;; *) log_failure_msg "Check if var1 is true" || true echo -e " \e[31mthere was no input in the read statment.\e[0m" ;; esac
Пишем Init скрипт
Инициализация — важнейшая процедура, лежащая в основе любой операционной системы на основе Unix/Linux для управления работой каждого скрипта и службы.
Я описывал в своих статьях процесс создания скриптов для systemD/Upstart и сейчас я хотел бы написать о написании init скриптов. Тема не новая и используется давно, но я большую часть своих тем беру именно из черновиков, которые накопились за года 3-4. У меня не хватает времени на все публикации + наполнять контент максимально (по крайней мере, сразу) и по этому, имеет что имеем. Но не смотря на это, у меня уже довольно много читателей — и это хорошо, это радует!
По сути, инициализация следует за этим процессом:
- Загрузка сервера.
- Запуск init процесса (обычно как PID 1).
- Запуск предопределенного набора задач для запуска активируется последовательно.
Инициализация отвечает за то, чтобы сервер мог загрузиться и отключиться. В некоторых Unix/Linux дистрибутивах используется стандартный процесс инициализации init/systemD/Upstart.
Пишем Upstart скрипт
И так, хотелось бы рассказать как можно запускать томкат. Но для начала, нужно узнать какой механизм инициализации используется:
Т.к речь идет о sysv init/Upstart, то и продолжим тему.
PS: Вот еще полезное чтиво:
INIT скрипт может иметь следующие состояния:
- start — Служит командой для запуска службы.
- stop — Выполняет остановку службы.
- restart — Перезапуст службы, а по факту — остановка и затем запуск сервиса.
- reload — Перезагрузка службы, т.е команда для перечитывания конфигурации без перезапуска или остановки службы.
- force-reload — Перезагрузка конфигурации (перечитать конфиг), если служба поддерживает это. В противном случае — выполнит перезапуск службы.
- status — Покажет состояние службы.
Вот скилет скрипта для использования:
#!/bin/bash -x # # Source function library. . /etc/rc.d/init.d/functions case "$1" in start) echo -n "Starting services: " touch /var/lock/subsys/ ;; stop) echo -n "Shutting down services: " rm -f /var/lock/subsys/ ;; status) ;; restart) ;; reload) ;; probe) ;; *) echo "Usage:Данный каркас можно юзать для любых целей.
Примеры Init скрипта
Приведу наглядный пример запуска томката.
Запуск TOMCAT с init
Создадим init скрипт для запуска:
#!/bin/bash -x # # Provides: tomcat9 # Required-Start: $local_fs $remote_fs $network # Required-Stop: $local_fs $remote_fs $network # Should-Start: $named # Should-Stop: $named # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start Tomcat. # Description: Start the Tomcat servlet engine. ### END INIT INFO export CATALINA_HOME=/usr/local/tomcat9 export JAVA_HOME=/usr/local/jdk1.8.0_131 export PATH=$JAVA_HOME/bin:$PATH service_name="tomcat9" start() < echo "Starting Tomcat 9. " /bin/su -s /bin/bash tomcat -c $CATALINA_HOME/bin/startup.sh >stop() < echo "Stopping Tomcat 9. " /bin/su -s /bin/bash tomcat -c $CATALINA_HOME/bin/shutdown.sh >status() < if (( $(ps -ef | grep -v grep | grep $service_name | wc -l) >0 )); then echo "$service_name is running. " else echo "$service_name is down. " fi > case $1 in start|stop|status) $1;; restart) stop; start;; *) echo "Usage : $0"; exit 1;; esac exit 0 Даем права на запуск (на исполнение):
# chmod 755 /etc/init.d/tomcat9Открываем браузер и смотрим что вышло!
#!/bin/bash -x DAEMON_PATH="/home/wes/Development/projects/myapp" DAEMON=myapp DAEMONOPTS="-my opts" NAME=myapp DESC="My daemon description" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME case "$1" in start) printf "%-50s" "Starting $NAME. " cd $DAEMON_PATH PID=`$DAEMON $DAEMONOPTS > /dev/null 2>&1 & echo $!` #echo "Saving PID" $PID " to " $PIDFILE if [ -z $PID ]; then printf "%s\n" "Fail" else echo $PID > $PIDFILE printf "%s\n" "Ok" fi ;; status) printf "%-50s" "Checking $NAME. " if [ -f $PIDFILE ]; then PID=`cat $PIDFILE` if [ -z "`ps axf | grep $ | grep -v grep`" ]; then printf "%s\n" "Process dead but pidfile exists" else echo "Running" fi else printf "%s\n" "Service not running" fi ;; stop) printf "%-50s" "Stopping $NAME" PID=`cat $PIDFILE` cd $DAEMON_PATH if [ -f $PIDFILE ]; then kill -HUP $PID printf "%s\n" "Ok" rm -f $PIDFILE else printf "%s\n" "pidfile not found" fi ;; restart) $0 stop $0 start ;; *) echo "Usage: $0" exit 1 esac Подойдет к большинству скриптов, а для остальных — можно отредактировать немного.
И, вот еще полезный довольно вариант:
#!/bin/sh ### BEGIN INIT INFO # Provides: # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Start daemon at boot time # Description: Enable service provided by daemon. ### END INIT INFO dir="" cmd="" user="" name=`basename $0` pid_file="/var/run/$name.pid" stdout_log="/var/log/$name.log" stderr_log="/var/log/$name.err" get_pid() < cat "$pid_file" >is_running() < [ -f "$pid_file" ] && ps -p `get_pid` >/dev/null 2>&1 > case "$1" in start) if is_running; then echo "Already started" else echo "Starting $name" cd "$dir" if [ -z "$user" ]; then sudo $cmd >> "$stdout_log" 2>> "$stderr_log" & else sudo -u "$user" $cmd >> "$stdout_log" 2>> "$stderr_log" & fi echo $! > "$pid_file" if ! is_running; then echo "Unable to start, see $stdout_log and $stderr_log" exit 1 fi fi ;; stop) if is_running; then echo -n "Stopping $name.." kill `get_pid` for i in 1 2 3 4 5 6 7 8 9 10 # for i in `seq 10` do if ! is_running; then break fi echo -n "." sleep 1 done echo if is_running; then echo "Not stopped; may still be shutting down or shutdown may have failed" exit 1 else echo "Stopped" if [ -f "$pid_file" ]; then rm "$pid_file" fi fi else echo "Not running" fi ;; restart) $0 stop if is_running; then echo "Unable to stop, will not attempt to start" exit 1 fi $0 start ;; status) if is_running; then echo "Running" else echo "Stopped" exit 1 fi ;; *) echo "Usage: $0" exit 1 ;; esac exit 0 Вот и все, статья «Пишем Init скрипт» завершена.
No such file or directory /etc/init.d/functions
I created a startup script to start/restart/stop a group of applications. I used the lib /etc/init.d/functions in my script. It is working well on my system, but it not working for my client; he is getting the error:
Right now I don't know which linux distro my client uses. Is the init.d/functions file different for different Linux distros? If so, how can I find it?
6 Answers 6
It's specific to whatever distribution you're running. Debian and Ubuntu have /lib/lsb/init-functions ; SuSE has /etc/rc.status ; none of them are compatible with the others. In fact, some distributions don't use /etc/init.d at all, or use it in an incompatible way (Slackware and Arch occur to me off the top of my head; there are others).
Also, how can i find those file name and path? is there any way to do that or is it that we can only find it from the documentation?
I did it by looking, as I have both of those available; I don't have a Red Hat install. But you may have missed the importance of what I said in bold above: the functions in your /etc/init.d/functions don't exist on other distributions. Every distribution has its own rules for /etc/init.d , and its function library (if any) is oriented around those rules; for example, SuSE's rc_status -s . There are some LSB "standard" functions, which are supposed to be found in /lib/lsb/init-functions , but your client may not be running a distribution which has been updated to provide it.
In CentOS 7 Docker image I had to simply install the package initscripts in order for this script to be installed:
yum install -y initscripts
This fixed my issue using Jenkins on Fedora 24 in a Docker container. (just used dnf instead of yum of course). Thanks!
This also works when installing MarkLogic 9 into a Centos7 docker container. The installation docs only mention needing lib.so.6 and lsb-core-amd64, but I'm guessing since they're talking about installing on a full CentOS 7 install, they would overlook that you'd need the initscripts package.
That is absolutely distribution dependent. You're really going to need to find out the distro in order to write a properly-matching init script.
You can also follow the LSB (Linux Standard Base) specification and hope that the distro in question did too. The current specification dictates that the standard init script functions be available as /lib/lsb/init-functions (see docs here). On Fedora and other Red Hat related distros, that's provided by the redhat-lsb package, which is optional.
So, you really have to figure out what you're targeting. Sorry.
Adding a recent answer
As noted in another answer, Linux Standard Base (LSB) specs provide a way to write platform independent init.d based startup scripts, using the LSB defined init functions as listed here
All LSB compliant distributions (all the big ones) provide the file /lib/lsb/init-functions (which defines the listed functions) in the meta-package lsb-core-noarch which can be installed using the distribution's package manager $PKGMAN $INSTOPT lsb-core-noarch ( yum , dnf , apt . ).
An example of such an init script is this.
However, given how systemd is now the de-facto system and service manager for most distributions, it's better to write a systemd service unit instead of writing out an initscript .