it-swarm-id.com

Mendeteksi sistem init menggunakan shell

Ini mungkin lebih berkaitan dengan mendeteksi sistem operasi, tetapi saya secara khusus membutuhkan sistem init yang saat ini digunakan pada sistem.

Fedora 15 dan Ubuntu sekarang menggunakan systemd, Ubuntu digunakan untuk menggunakan Pemula (standar lama hingga 15,04), sementara yang lain menggunakan variasi Sistem V.

Saya memiliki aplikasi yang saya tulis untuk menjadi daemon lintas-platform. Skrip init sedang dibuat secara dinamis berdasarkan parameter yang dapat diteruskan pada konfigurasi.

Yang ingin saya lakukan adalah hanya menghasilkan skrip untuk sistem init tertentu yang mereka gunakan. Dengan cara ini skrip instalasi dapat dijalankan secara wajar tanpa parameter sebagai root dan daemon dapat "dipasang" secara otomatis.

Inilah yang saya buat:

  • Cari systemd, pemula, dll di/bin
  • Bandingkan/proc/1/comm dengan systemd, pemula, dll
  • Tanyakan pada pengguna

Apa cara lintas/platform terbaik untuk melakukan ini?

Jenis terkait, Dapatkah saya bergantung pada bash untuk menjadi mayoritas * nix atau tergantung distribusi/OS?

Platform target:

  • OS Mac
  • Linux (semua distribusi)
  • BSD (semua versi)
  • Solaris, Minix, dan * nix lainnya
96
beatgammit

Untuk pertanyaan kedua, jawabannya adalah no dan Anda harus melihat Sumberdaya untuk pemrograman Shell portabel .

Adapun bagian pertama - pertama-tama, Anda tentu harus berhati-hati. Saya akan mengatakan melakukan beberapa tes untuk memastikan - karena fakta bahwa seseorang memang punya systemd (mis. Diinstal), tidak berarti itu sebenarnya digunakan sebagai _ init default. Juga, melihat /proc/1/comm dapat menyesatkan, karena beberapa instalasi dari berbagai program init dapat secara otomatis membuat /sbin/init hardlink symlink atau bahkan versi berganti nama dari program utama mereka.

Mungkin hal yang paling berguna adalah melihat tipe skrip init - karena itulah yang sebenarnya akan Anda buat, apa pun yang menjalankannya.

Sebagai catatan tambahan, Anda mungkin juga melihat OpenRC yang bertujuan untuk menyediakan struktur skrip init yang kompatibel dengan sistem Linux dan BSD.

30
rozcietrzewiacz

Saya sendiri sudah melangkah ke masalah ini dan memutuskan untuk melakukan beberapa tes. Saya sepenuhnya setuju dengan jawaban bahwa seseorang harus mengemas untuk setiap distro secara terpisah, tetapi kadang-kadang ada masalah praktis yang mencegahnya (tidak terkecuali tenaga kerja).

Jadi bagi yang ingin "deteksi otomatis" inilah yang saya temukan pada set distro yang terbatas (selengkapnya di bawah):

  • Anda dapat mengetahui mulai dari:

    [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no
    
  • Anda dapat memberi tahu systemd dari:

    [[ `systemctl` =~ -\.mount ]] && echo yes || echo no
    
  • Anda dapat memberi tahu sys-v init dari:

    [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]] && echo yes
    

Berikut ini eksperimen saya dengan baris perintah berikut:

if [[ `/sbin/init --version` =~ upstart ]]; then echo using upstart;
Elif [[ `systemctl` =~ -\.mount ]]; then echo using systemd;
Elif [[ -f /etc/init.d/cron && ! -h /etc/init.d/cron ]]; then echo using sysv-init;
else echo cannot tell; fi

pada contoh EC2 (saya termasuk id AMI us-east):

  • ArchLinux: using systemd (since 2012.10.06 )
  • CentOS6.4 AMI-52009e3b: menggunakan pemula
  • CentOS7 AMI-96a818fe: using systemd
  • Debian 6 AMI-80e915e9: menggunakan sysv-init
  • Debian 7.5 AMI-2c886c44: menggunakan sysv-init
  • Debian 7.6 GCE container-vm: using sysv-init
  • RHEL 6.5 AMI-8d756fe4: menggunakan pemula
  • SLES 11 AMI-e8084981: menggunakan sysv-init
  • Ubuntu 10,04 AMI-6b350a02: menggunakan pemula
  • Ubuntu 12,04 AMI-b08b6cd8: menggunakan pemula
  • Ubuntu 14.04 AMI-a427efcc: menggunakan pemula
  • Ubuntu 14.10 dan lebih muda: using systemd
  • AWS linux 2014.3.2 AMI-7c807d14: menggunakan pemula
  • Fedora 19 AMI-f525389c: using systemd
  • Fedora 20 AMI-21362b48: using systemd

Hanya untuk menjadi jelas: Saya tidak mengklaim bahwa ini sangat mudah! , hampir pasti tidak. Juga perhatikan bahwa untuk kenyamanan saya menggunakan pertandingan bash regexp, yang tidak tersedia di mana-mana. Di atas sudah cukup baik untuk saya sekarang. Namun, jika Anda menemukan distro yang gagal, beri tahu saya dan saya akan mencoba memperbaikinya jika ada AMI EC2 yang mereproduksi masalah ...

61
TvE

Menggunakan proses

Melihat output dari beberapa perintah ps yang dapat mendeteksi berbagai versi systemd & upstart, yang dapat dibuat seperti:

kaya baru

$ ps -eaf|grep '[u]pstart'
root       492     1  0 Jan02 ?        00:00:00 upstart-udev-bridge --daemon
root      1027     1  0 Jan02 ?        00:00:00 upstart-socket-bridge --daemon

systemd

$ ps -eaf|grep '[s]ystemd'
root         1     0  0 07:27 ?        00:00:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 20
root       343     1  0 07:28 ?        00:00:03 /usr/lib/systemd/systemd-journald
root       367     1  0 07:28 ?        00:00:00 /usr/lib/systemd/systemd-udevd
root       607     1  0 07:28 ?        00:00:00 /usr/lib/systemd/systemd-logind
dbus       615     1  0 07:28 ?        00:00:13 /bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation

Memperhatikan nama proses yang PID # 1 juga berpotensi menjelaskan sistem init yang sedang digunakan. Pada Fedora 19 (yang menggunakan systemd, misalnya:

UID        PID  PPID  C STIME TTY          TIME CMD
root         1     0  0 07:27 ?        00:00:03 /usr/lib/systemd/systemd --switched-root --system --deserialize 20

Perhatikan itu bukan init. Di Ubuntu dengan Upstart masih /sbin/init.

$ ps -efa|grep init
root         1     0  0 Jan02 ?        00:00:03 /sbin/init

CATATAN: Tapi gunakan ini dengan sedikit hati-hati. Tidak ada sesuatu yang diatur dalam batu yang mengatakan sistem init tertentu sedang digunakan pada distro yang diberikan telah memiliki systemd sebagai PID # 1.

generik

$ (ps -eo "ppid,args" 2>/dev/null || echo "ps call error") \
    | awk 'NR==1 || $1==1' | less
 PPID   COMMAND
    1   /lib/systemd/systemd-journald
    1   /lib/systemd/systemd-udevd
    1   /lib/systemd/systemd-timesyncd

Lihatlah proses dengan ppid 1 (anak-anak dari proses init). (Beberapa) nama proses anak mungkin menunjuk ke sistem init yang digunakan.

Sistem file

Jika Anda menginterogasi executable init, Anda bisa mendapatkan beberapa info darinya. Cukup parsing --version keluaran. Sebagai contoh:

kaya baru

$ Sudo /sbin/init --version
init (upstart 1.5)
Copyright (C) 2012 Scott James Remnant, Canonical Ltd.

This is free software; see the source for copying conditions.  There is NO warranty; not even for MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.

systemd

$ type init
init is /usr/sbin/init

CATATAN: Fakta bahwa init tidak berada di lokasi standarnya adalah sedikit petunjuk/petunjuk. Itu selalu berlokasi di /sbin/init pada sistem sysvinit.

sysvinit

$ type init
init is /sbin/init

Ini juga:

$ Sudo init --version
init: invalid option -- -
Usage: init 0123456SsQqAaBbCcUu

Kesimpulan

Jadi sepertinya tidak ada satu cara untuk melakukannya, tetapi Anda dapat merumuskan serangkaian cek yang akan menunjukkan sistem init mana yang Anda gunakan dengan tingkat kepercayaan yang cukup tinggi.

19
slm

Tidak seefisien itu, tetapi saya sepertinya berhasil.

strings /sbin/init | grep -q "/lib/systemd" && echo SYSTEMD
strings /sbin/init | grep -q "sysvinit" && echo SYSVINIT
strings /sbin/init | grep -q "upstart" && echo UPSTART

Ini akan mencetak lebih banyak baris jika lebih dari satu string cocok, yang dapat diterjemahkan ke "Tidak bisa menebak". String yang digunakan dalam grep bisa sedikit dimodifikasi tetapi ketika diuji di os berikut saya selalu mendapat satu baris.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Pembaruan Nahant 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [SYSTEMD]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora merilis 23 (Shell online) [SYSTEMD]
  • Debian GNU/Linux 7 (Shell online) [SYSTEMD]
  • Centos 7.6 (VM) [SYSTEMD]

Pendekatan yang lebih sederhana dari solusi yang sama (tetapi berhenti pada pertandingan pertama)

strings /sbin/init |
  awk 'match($0, /(upstart|systemd|sysvinit)/) { print toupper(substr($0, RSTART, RLENGTH));exit; }'
15
Marinos An

Terkadang semudah menggunakan ls:

$ ls -l /sbin/init
lrwxrwxrwx 1 root root 20 juin  25 12:04 /sbin/init -> /lib/systemd/systemd

Saya kira jika /sbin/init bukan tautan simbolis, Anda harus memeriksa saran lebih lanjut berikut dalam jawaban lain.

Saya juga memiliki masalah yang sama, dan melakukan banyak tes di beberapa mesin RedHat/CentOS/Debian/Ubuntu/Mint. Inilah yang akhirnya saya dapatkan, dengan hasil yang baik.

  1. Temukan nama yang dapat dieksekusi dengan PID 1:

    ps -p 1
    

    Jika itu systemd atau pemula, masalah terpecahkan. Jika "init", itu mungkin symlink atau sesuatu selain nama depan. Lanjutkan.

  2. Temukan jalur nyata untuk dieksekusi (hanya berfungsi sebagai root):

    ls -l `which init`
    

    Jika init adalah symlink ke Pemula atau systemd, masalah terpecahkan. Kalau tidak, itu hampir yakin bahwa Anda memiliki SysV init. Tapi itu bisa menjadi executable yang salah nama. Lanjutkan.

  3. Temukan paket yang menyediakan executable. Sayangnya, ini tergantung pada distro:

    dpkg-query -S (executable real path) # Debian  
    rpm -qf (executable real path) # RedHat  
    

Kemudian, jika Anda ingin membuat skrip itu (bagian yang paling lucu, IMHO), ini adalah one-liners saya (jalankan sebagai root):

ls -l $(which $(ps -p 1 o comm)) | awk '{ system("dpkg-query -S "$NF) }' # Debian  

ls -l $(which $(ps -p 1 o comm)) | awk '{ system("rpm -qf "$NF) }' # RedHat  
5
Emerson Prado
  1. Ini adalah paket khusus untuk distro. Ada jauh lebih banyak untuk menginstal perangkat lunak dengan benar daripada hanya mendeteksi sistem init. Banyak distro menggunakan SysVinit tetapi tidak semua dari mereka menulis skrip init mereka dengan cara yang sama. Cara yang tepat untuk menyelesaikan ini adalah dengan memasukkan semua varian yang berbeda dan kemudian bundel menggunakan file spesifikasi dengan nama dependensi distro-spesifik untuk distro rpm, file deb untuk sistem berbasis apt, dll. Hampir semua distro memiliki semacam spesifikasi paket yang Anda dapat menulis yang menyertakan dependensi, skrip, skrip init, dll. Jangan menciptakan kembali roda di sini.

  2. Tidak. Yang membawa kita kembali ke 1. Jika kamu butuh bash, itu harusnya ketergantungan. Anda dapat menentukan pemeriksaan ini sebagai bagian dari skrip konfigurasi Anda, tetapi harus juga dalam deskripsi paket.

Edit: Gunakan flag pada skrip configure Anda seperti --with upstart atau --without sysvinit. Pilih default waras, maka skrip yang mengemas perangkat lunak Anda untuk distro lain dapat memilih untuk menjalankan ini dengan opsi lain.

3
Caleb

Juga memeriksa deskriptor file dapat membantu. Dan itu dari benar-benar menjalankan init (Debian stretch saat ini memungkinkan untuk menginstal lebih banyak sistem init) :-)

$ ls -l /proc/1/fd |grep systemd
lrwx------ 1 root root 64 srp 14 13:56 25 -> /run/systemd/initctl/fifo
lr-x------ 1 root root 64 srp 14 13:56 6 -> /sys/fs/cgroup/systemd

$ ls -l /proc/1/fd |grep /run/initctl # sysvinit
lrwx------ 1 root root 64 srp 14 14:04 10 -> /run/initctl

$ ls -l /proc/1/fd |grep upstart
l-wx------ 1 root root 64 srp 13 16:09 13 -> /var/log/upstart/mysql.log.1 (delete
l-wx------ 1 root root 64 srp 13 16:09 9 -> /var/log/upstart/dbus.log.1 (deleted)

$ ls -l /proc/1/fd # busybox
total 0
lrwx------    1 root     root          64 Jan  1 00:00 0 -> /dev/console
lrwx------    1 root     root          64 Jan  1 00:00 1 -> /dev/console
lrwx------    1 root     root          64 Jan  1 00:00 2 -> /dev/console

Mungkin cara yang lebih aman untuk memeriksa busybox adalah dengan check /proc/1/exe, karena busybox biasanya menggunakan symlink:

$ ls -l /proc/1/exe 
lrwxrwxrwx    1 root     root          0 Jan  1 00:00 /proc/1/exe -> /bin/busybox

Jadi cek bisa:

{ ls -l /proc/1/fd |grep -q systemd && echo "init: systemd"; } || \
{ ls -l /proc/1/fd |grep -q /run/initctl && echo "init: sysvinit"; } || \
{ ls -l /proc/1/fd |grep -q upstart && echo "init: upstart"; } || \
{ ls -l /proc/1/exe |grep -q busybox && echo "init: busybox"; } || \
echo "unknown init"
3
pevik

Cukup dengan memasuki proses dengan PID 1 akan memberi tahu Anda:

strings /proc/1/exe |grep -q sysvinit
strings /proc/1/exe |grep -q systemd
2

Tidak tahu tentang sistem lain maka Debian (wheezy)/atau Ubuntu (14.10.) Tapi saya menguji masalah seperti itu dengan perintah file biasa.

file /sbin/init

berikan ini:

/sbin/init: symbolic link to 'upstart'

Sistem Debian dengan systemd (mis. Sisi) menunjukkan ini:

# file /sbin/init 
/sbin/init: symbolic link to /lib/systemd/systemd
2
zzeroo

Pada debian/sbin/init adalah symlink ke init default Anda

ls -l /sbin/init

akan memberi Anda info yang Anda cari.

$ ls -l /sbin/init 
lrwxrwxrwx 1 root root 20 nov 18 13:15 /sbin/init -> /lib/systemd/systemd
2
rmorelli74

Di Gentoo, lihat pid 1:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0   4216   340 ?        Ss    2013   0:57 init [3]

Jika ini init, maka sistem init adalah OpenRC. Jika ini systemd, maka sistem init adalah systemd.

Anda dapat mendeteksi Gentoo dengan [ -f /etc/gentoo-release ].

Metode lain di Gentoo adalah menggunakan profile-config show, yang akan menunjukkan profil default apa yang digunakan. Semua profil kecuali dua yang berakhiran/systemd menggunakan init OpenRC. Perlu diingat, ini hanya mewakili standar dan ada kemungkinan bahwa pengguna telah mengambil langkah-langkah untuk mengesampingkan default itu dan mungkin bukan indikasi palungan init yang sebenarnya sedang digunakan.

2
casey

Ini sangat mudah untuk beberapa sistem init. Untuk systemd:

test -d /run/systemd/system

untuk pemula:

initctl --version | grep -q upstart

untuk hal lain, Anda dapat mengasumsikan berdasarkan distro (launchd di OS X, sysvinit di Debian, OpenRC di Gentoo).

1
CameronNemo

Untuk systemd:

if [[ `systemctl is-system-running` =~ running ]]; then echo using systemd; fi
1
guilhermebr

Solusi saya: periksa perintah yang berjalan sebagai proses dengan ID 1.

case `cat /proc/1/comm` in
    init)    echo Init ;;
    systemd) echo SystemD ;;
    # add here other patterns
    *)       echo "unknown: '`cat /proc/1/comm`'" ;;
esac

Saat ini saya hanya memiliki akses ke mesin Init dan SystemD, jadi saya tidak tahu bagaimana Upstart atau macOS (OS X) akan terdeteksi, tetapi saya akan terus mencari.

1
t0r0X

Berikut skrip bash untuk melakukan deteksi. Hanya memeriksa untuk pemula dan systemd saat ini, tetapi harus mudah diperluas. Saya telah mengambil ini dari kode saya berkontribusi pada skrip instalasi driver DisplayLink .

detect_distro()
{
  # init process is pid 1
  INIT=`ls -l /proc/1/exe`
  if [[ $INIT == *"upstart"* ]]; then
    SYSTEMINITDAEMON=upstart
  Elif [[ $INIT == *"systemd"* ]]; then
    SYSTEMINITDAEMON=systemd
  Elif [[ $INIT == *"/sbin/init"* ]]; then
    INIT=`/sbin/init --version`
    if [[ $INIT == *"upstart"* ]]; then
      SYSTEMINITDAEMON=upstart
    Elif [[ $INIT == *"systemd"* ]]; then
      SYSTEMINITDAEMON=systemd
    fi
  fi

  if [ -z "$SYSTEMINITDAEMON" ]; then
    echo "WARNING: Unknown distribution, assuming defaults - this may fail." >&2
  else
    echo "Init system discovered: $SYSTEMINITDAEMON"
  fi
}
1
Ben McCann

Ada banyak jebakan kompatibilitas saat menguji systemd vs initd. Ini sebenarnya berfungsi pada OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1
David Lakatos

Bagaimana kalau yang ini:

strings $(\ps -p 1 o cmd= | cut -d" " -f1) | egrep -o "upstart|sysvinit|systemd" | head -1

Hanya diuji pada sistem yang saya miliki: Ubuntu dan SailfishOS.

0
SebMa
check(){
    if hash systemctl 2>/dev/null;
    then
        echo "there is systemd"
    fi

    if hash initctl 2>/dev/null;
    then
        echo "there is upStart"
    fi

    if [ -f "/etc/inittab"];
    then
        echo "there is systemV"
    fi
}
0
hxysayhi