Menjalankan program arbitrer sebagai daemon dari skrip init

10

Saya perlu menginstal program sebagai layanan di Red Hat. Itu tidak latar belakang sendiri, mengelola file PID-nya, atau mengelola log sendiri. Ini hanya berjalan dan mencetak ke STDOUT dan STDERR.

Menggunakan skrip init standar sebagai panduan, saya telah mengembangkan yang berikut ini:

#!/bin/bash
#
#   /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf

# Source function library.
. /etc/rc.d/init.d/functions

prog="someprog"
exec="/usr/local/bin/$prog"
[ -e "/etc/sysconfig/$prog" ] && . "/etc/sysconfig/$prog"
lockfile="/var/lock/subsys/$prog"
RETVAL=0

check() {
    [ `id -u` = 0 ] || exit 4
    test -x "$exec" || exit 5
}

start() {
    check
    if [ ! -f "$lockfile" ]; then
        echo -n $"Starting $prog: " 
        daemon --user someproguser "$exec"
        RETVAL=$?
        [ $RETVAL -eq 0 ] && touch "$lockfile"
        echo
    fi
    return $RETVAL
}

stop() {
    check
    echo -n $"Stopping $prog: "
    killproc "exec"
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f "$lockfile"
    echo
    return $RETVAL
}

restart() {
    stop
    start
}   

case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    restart
    ;;
status)
    status "$prog"
    RETVAL=$?
    ;;
*)
    echo $"Usage: $0 {start|stop|restart|status}"
    RETVAL=2
esac

exit $RETVAL

Mungkin kesalahan saya adalah menyalin-menempel dan memodifikasi beberapa skrip yang ada di /etc/init.d. Bagaimanapun, layanan yang dihasilkan berperilaku aneh:

  • ketika saya memulainya dengan service someprog startprogram mencetak ke terminal dan perintah tidak selesai.
  • jika saya CTRL-C, ia mencetak "Sesi diakhiri, membunuh shell ... ... terbunuh. GAGAL". Saya harus melakukan ini untuk mendapatkan prompt shell saya kembali lagi.
  • sekarang ketika saya menjalankannya service someprog statusmengatakan itu berjalan dan daftar PID-nya. Saya bisa melihatnya di psjadi sedang berjalan.
  • sekarang ketika saya menjalankannya service someprog stopgagal berhenti. Saya dapat memverifikasi bahwa itu masih berjalan ps.

Apa yang perlu saya ubah agar someprogdikirim ke latar belakang dan dikelola sebagai layanan?

Sunting: Saya sekarang telah menemukan beberapa pertanyaan terkait, tidak satu pun dari mereka dengan jawaban aktual selain "melakukan sesuatu yang lain":

Sunting: jawaban tentang penjemputan-ganda ini mungkin telah memecahkan masalah saya, tetapi sekarang program saya sendiri bercabang dua dan berfungsi: https://stackoverflow.com/a/9646251/898699

Baron Schwartz
sumber
Apakah Anda memulai program dengan utilitas "daemon" yang disediakan oleh libslack. libslack.org/daemon/#documentation Dalam hal ini program dapat dihentikan sebagai daemon -n nama --stop. Juga, coba arahkan kembali output (saat memulai program) ke file atau / dev / null dan periksa.
Ankit
2
Bergantung pada versi redhat Anda, Anda bisa membuat pembungkus sederhana untuk itu di pemula dan menyebutnya langsung di pemula. Maka pemula akan mengelola layanan untuk Anda. Ini adalah hal EL6.
Matthew Ife

Jawaban:

1

Perintah "tidak selesai" karena daemonfungsi tidak menjalankan aplikasi Anda di latar belakang untuk Anda. Anda perlu menambahkan sebuah &di akhir daemonperintah Anda seperti:

daemon --user someproguser $exec &

Jika someprogtidak menangani SIGHUP, Anda harus menjalankan perintah dengan nohupuntuk memastikan bahwa proses Anda tidak akan menerima SIGHUPyang memberitahu proses Anda untuk keluar ketika shell induk keluar. Itu akan terlihat seperti ini:

daemon --user someproguser "nohup $exec" &

Dalam stopfungsi Anda , killproc "exec"tidak melakukan apa pun untuk menghentikan program Anda. Seharusnya berbunyi seperti ini:

killproc $exec

killprocmembutuhkan jalur lengkap ke aplikasi Anda untuk menghentikannya dengan benar. Saya pernah mengalami masalah dengan killprocdi masa lalu, jadi Anda juga dapat membunuh PID di PIDFILE yang seharusnya Anda tuliskan someprogPID dengan sesuatu seperti ini:

cat $pidfile | xargs kill

Anda dapat menulis PIDFILE seperti ini:

ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile

di mana $pidfilemenunjuk ke /var/run/someprog.pid.

Jika Anda ingin [OK] atau [GAGAL] pada stopfungsi Anda, Anda harus menggunakan successdan failurefungsi dari /etc/rc.d/init.d/functions. Anda tidak memerlukan ini dalam startfungsi karena daemonmemanggil yang sesuai untuk Anda.

Anda juga hanya perlu kutipan di sekitar string dengan spasi. Ini pilihan gaya, jadi terserah Anda.

Semua perubahan ini terlihat seperti ini:

#!/bin/bash
#
#   /etc/rc.d/init.d/someprog
#
# Starts the someprog daemon
#
# chkconfig: 345 80 20
# description: the someprog daemon
# processname: someprog
# config: /etc/someprog.conf

# Source function library.
. /etc/rc.d/init.d/functions

prog=someprog
exec=/usr/local/bin/$prog
[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
lockfile=/var/lock/subsys/$prog
pidfile=/var/run/$prog
RETVAL=0

check() {
    [ `id -u` = 0 ] || exit 4
    test -x $exec || exit 5
}

start() {
    check
    if [ ! -f $lockfile ]; then
        echo -n $"Starting $prog: " 
        daemon --user someproguser "nohup $exec" &
        RETVAL=$?
        if [ $RETVAL -eq 0 ]; then
          touch $lockfile
          ps aux | grep $exec | grep -v grep | tr -s " " | cut -d " " -f2 > $pidfile
        fi
        echo
    fi
    return $RETVAL
}

stop() {
    check
    echo -n $"Stopping $prog: "
    killproc $exec && cat $pidfile | kill
    RETVAL=$?
    if [ $RETVAL -eq 0 ]; then
      rm -f $lockfile
      rm -f $pidfile
      success; echo
    else
      failure; echo
    fi
    echo
    return $RETVAL
}

restart() {
    stop
    start
}   

case "$1" in
start)
    start
    ;;
stop)
    stop
    ;;
restart)
    restart
    ;;
status)
    status $prog
    RETVAL=$?
    ;;
*)
    echo $"Usage: $0 {start|stop|restart|status}"
    RETVAL=2
esac

exit $RETVAL
Stuporman
sumber
Maaf butuh hampir 4,5 tahun bagi Anda untuk mendapatkan jawaban yang tepat.
Stuporman
-1

Jika ini adalah program Anda, silakan tulis sebagai dasmon yang tepat. Terutama jika untuk redistribusi. :)

Anda dapat mencoba monit . Atau mungkin sesuatu seperti runit atau daemontools. Paket-paket besar itu mungkin belum tersedia. Daemontools berasal dari DJB, jika itu memengaruhi keputusan Anda (ke arah mana pun.)

terguling
sumber
-1

Saya telah melakukan penelitian lebih lanjut dan tampaknya jawabannya adalah "Anda tidak bisa melakukan itu." Program yang akan dijalankan harus benar-benar daemonisasi sendiri dengan benar: garpu dan lepaskan filehandles standarnya, lepaskan dari terminal, dan mulai sesi baru.

Sunting: rupanya saya salah - forking ganda akan berhasil. https://stackoverflow.com/a/9646251/898699

Baron Schwartz
sumber
Anda dapat melakukannya menggunakan pemula seperti yang dinyatakan dalam komentar.