it-swarm-vi.com

Phát hiện hệ thống init bằng shell

Điều này có thể liên quan nhiều hơn đến việc phát hiện các hệ điều hành, nhưng tôi đặc biệt cần hệ thống init hiện đang sử dụng trên hệ thống.

Fedora 15 và Ubuntu hiện sử dụng systemd, Ubuntu đã từng sử dụng Upstart (mặc định thời gian dài cho đến 15.04), trong khi những người khác sử dụng các biến thể của System V.

Tôi có một ứng dụng mà tôi đang viết để trở thành một daemon đa nền tảng. Các tập lệnh init đang được tạo động dựa trên các tham số có thể được truyền vào cấu hình.

Những gì tôi muốn làm là chỉ tạo tập lệnh cho hệ thống init cụ thể mà họ đang sử dụng. Bằng cách này, tập lệnh cài đặt có thể được chạy một cách hợp lý mà không cần tham số là root và trình nền có thể được "cài đặt" tự động.

Đây là những gì tôi nghĩ ra:

  • Tìm kiếm systemd, upstart, v.v. trong/bin
  • So sánh/Proc/1/comm với systemd, upstart, v.v.
  • Hỏi người dùng

Điều gì sẽ là cách chéo/nền tảng tốt nhất để làm điều này?

Loại liên quan, Tôi có thể phụ thuộc vào bash để chiếm đa số * nix hay là phụ thuộc vào phân phối/HĐH?

Nền tảng mục tiêu:

  • Hệ điều hành Mac
  • Linux (tất cả các bản phân phối)
  • BSD (tất cả các phiên bản)
  • Solaris, Minix và * nix khác
96
beatgammit

Đối với câu hỏi thứ hai, câu trả lời là không và bạn nên xem Tài nguyên cho lập trình Shell di động .

Về phần đầu tiên - trước hết, bạn chắc chắn phải cẩn thận. Tôi muốn nói thực hiện một số thử nghiệm để đảm bảo - bởi vì thực tế là ai đó không có systemd (ví dụ: đã cài đặt), không có nghĩa là nó thực sự được sử dụng làm mặc định init. Ngoài ra, nhìn vào /proc/1/comm có thể gây hiểu nhầm, vì một số cài đặt của các chương trình init khác nhau có thể tự động thực hiện /sbin/init một liên kết cứng liên kết tượng trưng hoặc thậm chí là một phiên bản được đổi tên của chương trình chính của họ.

Có lẽ điều hữu ích nhất có thể là xem xét loại init script - bởi vì đó là những gì bạn thực sự sẽ tạo ra, bất kể điều gì chạy chúng.

Là một lưu ý phụ, bạn cũng có thể xem OpenRC nhằm mục đích cung cấp cấu trúc của các tập lệnh init tương thích với cả hệ thống Linux và BSD.

30
rozcietrzewiacz

Tôi đã tự mình bước vào vấn đề này và quyết định làm một số thử nghiệm. Tôi hoàn toàn đồng ý với câu trả lời rằng một người nên đóng gói riêng cho từng bản phân phối, nhưng đôi khi có những vấn đề thực tế ngăn cản điều đó (không phải ít nhất là nhân lực).

Vì vậy, đối với những người muốn "tự động phát hiện" đây là những gì tôi đã tìm ra trên một bộ phân phối giới hạn (chi tiết bên dưới):

  • Bạn có thể nói mới bắt đầu từ:

    [[ `/sbin/init --version` =~ upstart ]] && echo yes || echo no
    
  • Bạn có thể nói với systemd từ:

    [[ `systemctl` =~ -\.mount ]] && echo yes || echo no
    
  • Bạn có thể nói với sys-v init từ:

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

Dưới đây là các thử nghiệm của tôi với dòng lệnh sau:

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

trên các trường hợp ec2 (Tôi bao gồm id AMI phía đông):

  • ArchLinux: sử dụng systemd (kể từ 2012.10.06 )
  • CentOS6.4 AMI-52009e3b: sử dụng mới bắt đầu
  • CentOS7 AMI-96a818fe: sử dụng systemd
  • Debian 6 AMI-80e915e9: sử dụng sysv-init
  • Debian 7.5 AMI-2c886c44: sử dụng sysv-init
  • Debian 7.6 GCE container-vm: sử dụng sysv-init
  • RHEL 6.5 AMI-8d756fe4: sử dụng mới bắt đầu
  • SLES 11 AMI-e8084981: sử dụng sysv-init
  • Ubuntu 10.04 AMI-6b350a02: sử dụng mới nhất
  • Ubuntu 12.04 AMI-b08b6cd8: sử dụng mới bắt đầu
  • Ubuntu 14.04 AMI-a427efcc: sử dụng mới bắt đầu
  • Ubuntu 14.10 trở xuống: sử dụng systemd
  • AWS linux 2014.3.2 AMI-7c807d14: sử dụng mới nhất
  • Fedora 19 AMI-f525389c: sử dụng systemd
  • Fedora 20 AMI-21362b48: sử dụng systemd

Nói rõ hơn: Tôi không khẳng định rằng điều này là hoàn hảo! , gần như chắc chắn là không. Cũng lưu ý rằng để thuận tiện, tôi sử dụng các kết hợp regash bash, không có sẵn ở mọi nơi. Trên đây là đủ tốt cho tôi ngay bây giờ. Tuy nhiên, nếu bạn tìm thấy một bản phân phối bị lỗi, vui lòng cho tôi biết và tôi sẽ cố gắng khắc phục nếu có EC2 AMI tái tạo sự cố ...

61
TvE

Sử dụng các quy trình

Nhìn vào đầu ra từ một vài lệnh ps có thể phát hiện các phiên bản khác nhau của systemd & upstart, có thể được tạo như vậy:

mới bắt đầu

$ 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

Chú ý đến tên của quy trình mà PID # 1 cũng có khả năng làm sáng tỏ hệ thống init nào đang được sử dụng. Trên Fedora 19 (sử dụng systemd, ví dụ:

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

Lưu ý rằng nó không phải là init. Trên Ubuntu với Upstart, nó vẫn /sbin/init.

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

LƯU Ý : Nhưng hãy cẩn thận khi sử dụng. Không có bất cứ điều gì được đặt trong đá nói rằng một hệ thống init cụ thể đang được sử dụng trên một bản phân phối cụ thể để có systemd làm PID # 1.

chung

$ (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

Nhìn vào các quy trình với ppid 1 (con của quá trình init). (Một số) tên quy trình con có thể trỏ đến hệ thống init đang sử dụng.

Hệ thống tập tin

Nếu bạn thẩm vấn init thực thi, bạn cũng có thể nhận được một số thông tin từ nó. Chỉ cần phân tích cú pháp --version đầu ra. Ví dụ:

mới bắt đầu

$ 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

LƯU Ý : Thực tế là init không ở vị trí tiêu chuẩn của nó là một chút gợi ý/nói. Nó luôn nằm trong /sbin/init trên các hệ thống sysvinit.

sysvinit

$ type init
init is /sbin/init

Ngoài ra này:

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

Kết luận

Vì vậy, dường như không có cách nào để làm điều đó, nhưng bạn có thể tạo ra một bộ kiểm tra để xác định chính xác hệ thống init nào bạn đang sử dụng với độ tin cậy khá cao.

19
slm

Không hiệu quả nhưng tôi dường như làm việc.

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

Nó sẽ in nhiều dòng hơn nếu nhiều hơn một chuỗi trùng khớp, có thể được dịch thành "Không thể đoán". Các chuỗi được sử dụng trong grep có thể được sửa đổi một chút nhưng khi được kiểm tra trong hệ điều hành sau tôi luôn có một dòng.

  • RHEL 6.4 [UPSTART]
  • RHEL ES 4 (Cập nhật Nahant 7) [SYSVINIT]
  • Ubuntu 16.04.1 LTS [HỆ THỐNG]
  • Ubuntu 14.04.2 LTS [UPSTART]
  • Fedora phát hành 23 (Shell trực tuyến) [HỆ THỐNG]
  • Debian GNU/Linux 7 (Shell trực tuyến) [HỆ THỐNG]
  • Centos 7.6 (VM) [HỆ THỐNG]

Một cách tiếp cận đơn giản hơn của cùng một giải pháp (nhưng nó dừng lại ở trận đấu đầu tiên)

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

Đôi khi nó dễ như sử dụng ls:

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

Tôi đoán nếu /sbin/init không phải là một liên kết tượng trưng, ​​bạn sẽ phải kiểm tra thêm các đề xuất sau trong các câu trả lời khác.

10

Tôi cũng gặp vấn đề tương tự và đã thực hiện rất nhiều thử nghiệm trong một số máy RedHat/CentOS/Debian/Ubuntu/Mint. Đây là những gì tôi đã kết thúc, với kết quả tốt.

  1. Tìm tên của tệp thực thi với PID 1:

    ps -p 1
    

    Nếu đó là systemd hoặc Upstart, vấn đề đã được giải quyết. Nếu là "init", nó có thể là một liên kết tượng trưng hoặc một cái gì đó không phải là một tên trả trước. Đi về phía trước.

  2. Tìm đường dẫn thực sự cho tệp thực thi (chỉ hoạt động như root):

    ls -l `which init`
    

    Nếu init là một liên kết tượng trưng để khởi động hoặc systemd, vấn đề đã được giải quyết. Mặt khác, nó gần như chắc chắn rằng bạn có SysV init. Nhưng nó có thể là một thực thi sai tên. Đi về phía trước.

  3. Tìm gói cung cấp thực thi. Thật không may, điều này phụ thuộc vào distro:

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

Sau đó, nếu bạn muốn viết kịch bản đó (phần hài hước nhất, IMHO), đây là những đoạn một của tôi (chạy dưới dạng 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. Đây là những gì các gói cụ thể dành cho. Có nhiều thứ để cài đặt phần mềm đúng cách hơn là chỉ phát hiện hệ thống init. Nhiều distro sử dụng SysVinit nhưng không phải tất cả chúng đều viết script init của chúng theo cùng một cách. Cách thích hợp để giải quyết vấn đề này là bao gồm tất cả các biến thể khác nhau và sau đó kết hợp nó bằng cách sử dụng các tệp spec với các tên phụ thuộc dành riêng cho phân phối vòng/phút, các tệp deb cho các hệ thống dựa trên apt, v.v. có thể viết bao gồm các phụ thuộc, tập lệnh, tập lệnh init, v.v. Đừng tái tạo bánh xe ở đây.

  2. Không. Điều này đưa chúng tôi trở lại 1. Nếu bạn cần bash thì đó phải là một sự phụ thuộc. Bạn có thể chỉ định kiểm tra này như một phần của tập lệnh cấu hình của mình, nhưng nó cũng phải có trong phần mô tả gói.

Chỉnh sửa : Sử dụng cờ trên tập lệnh cấu hình của bạn, chẳng hạn như --with upstart hoặc là --without sysvinit. Chọn một mặc định lành mạnh, sau đó các tập lệnh đóng gói phần mềm của bạn cho các bản phát hành khác có thể chọn để chạy phần mềm này với các tùy chọn khác.

3
Caleb

Ngoài ra kiểm tra mô tả tập tin có thể giúp đỡ. Và đó là từ thực tế đang chạy init (hiện tại Debian cho phép cài đặt thêm các hệ thống 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

Có lẽ cách an toàn hơn để kiểm tra busybox sẽ là check /proc/1/exe, vì busybox thường sử dụng symlink:

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

Vì vậy, kiểm tra có thể là:

{ 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

Chỉ cần tham gia vào quá trình với PID 1 sẽ cho bạn biết:

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

Không biết về các hệ thống khác sau đó là Debian (wheezy)/hoặc Ubuntu (14.10.) Nhưng tôi kiểm tra các vấn đề như vậy với lệnh file cũ.

file /sbin/init

cho này:

/sbin/init: symbolic link to 'upstart'

Các hệ thống Debian có systemd (ví dụ: sid) hiển thị điều này:

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

Trên debian/sbin/init là một liên kết tượng trưng đến init mặc định của bạn, vì vậy

ls -l /sbin/init

sẽ cung cấp cho bạn thông tin bạn đang tìm kiếm.

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

Trên Gentoo, hãy xem 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]

Nếu là init, thì hệ thống init là OpenRC. Nếu là systemd, thì hệ thống init là systemd.

Bạn có thể phát hiện Gentoo bằng [ -f /etc/gentoo-release ].

Một phương pháp khác trên Gentoo là sử dụng profile-config show, sẽ hiển thị cấu hình mặc định nào đang được sử dụng. Tất cả các cấu hình ngoại trừ hai kết thúc trong/systemd đều sử dụng init OpenRC. Hãy nhớ rằng, đây chỉ là đại diện của một mặc định và có thể người dùng đã thực hiện các bước để ghi đè mặc định đó và có thể không phải là dấu hiệu của trình quản lý init thực sự đang sử dụng.

2
casey

Điều này thực sự dễ dàng cho một số hệ thống init. Đối với hệ thống:

test -d /run/systemd/system

để bắt đầu:

initctl --version | grep -q upstart

đối với bất cứ điều gì khác, bạn chỉ có thể giả sử dựa trên bản phân phối (launchd trên OS X, sysvinit trên Debian, OpenRC trên Gentoo).

1
CameronNemo

Dành cho systemd:

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

Giải pháp của tôi: kiểm tra lệnh đang chạy như tiến trình với 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

Hiện tại tôi chỉ có quyền truy cập vào các máy init và SystemD, vì vậy tôi không thể biết Upstart hoặc macOS (OS X) sẽ được phát hiện như thế nào, nhưng tôi sẽ tiếp tục tìm kiếm.

1
t0r0X

Đây là một tập lệnh bash để thực hiện phát hiện. Nó chỉ kiểm tra khởi động và systemd tại thời điểm này, nhưng nên dễ dàng mở rộng. Tôi đã lấy cái này từ mã tôi đã đóng góp cho tập lệnh cài đặt trình điều khiển 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

Có rất nhiều cạm bẫy tương thích khi thử nghiệm systemd vs initd. Điều này thực sự hoạt động trên OpenSuSE 42.1: ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'init'

1
David Lakatos

Làm thế nào đây:

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

Chỉ được thử nghiệm trên các hệ thống tôi có: Ubuntu và 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