
Pekerjaan utama saya adalah, untuk sebagian besar, penyebaran sistem perangkat lunak, yaitu, saya menghabiskan banyak waktu untuk mencoba menjawab pertanyaan-pertanyaan ini:
- Perangkat lunak ini berfungsi untuk pengembang, tetapi tidak untuk saya. Mengapa
- Kemarin perangkat lunak ini bekerja untuk saya, tetapi tidak hari ini. Mengapa
Ini adalah jenis debugging yang sedikit berbeda dari debugging perangkat lunak biasa. Debugging normal adalah tentang logika kode, tetapi penyebaran debugging adalah tentang interaksi kode dan lingkungan. Sekalipun akar masalahnya adalah kesalahan logis, fakta bahwa segala sesuatu bekerja pada satu mesin dan bukan pada mesin lain berarti masalahnya ada di lingkungan.
Jadi, alih-alih alat debugging biasa seperti gdb , saya memiliki seperangkat alat yang berbeda untuk debugging penyebaran. Dan alat favorit saya untuk menangani masalah seperti "Mengapa tidak membajak perangkat lunak ini?" disebut strace .
Apa itu strace?
strace adalah alat untuk melacak panggilan sistem. Awalnya dibuat di Linux, tetapi chip debugging yang sama dapat diputar dengan alat untuk sistem lain ( DTrace atau ktrace ).
Aplikasi utama sangat sederhana. Anda hanya perlu menjalankan strace dengan perintah apa pun dan itu akan mengirim semua panggilan sistem ke dump (meskipun, pertama, Anda mungkin harus menginstal strace itu sendiri):
$ strace echo Hello ...Snip lots of stuff... write(1, "Hello\n", 6) = 6 close(1) = 0 close(2) = 0 exit_group(0) = ? +++ exited with 0 +++
Apa panggilan sistem ini? Ini adalah semacam API untuk kernel sistem operasi. Sekali waktu, perangkat lunak memiliki akses langsung ke perangkat keras tempat ia bekerja. Jika, misalnya, Anda perlu menampilkan sesuatu di layar, itu diputar dengan port dan / atau register memori untuk perangkat video. Ketika sistem komputer multitasking menjadi populer, kekacauan memerintah karena berbagai aplikasi berjuang untuk perangkat keras. Kesalahan dalam satu aplikasi dapat menurunkan pekerjaan orang lain, jika tidak seluruh sistem. Kemudian mode privilege (atau "perlindungan dering") muncul di CPU. Kernel menjadi yang paling istimewa: ia memperoleh akses penuh ke perangkat keras, membuat aplikasi yang kurang istimewa yang sudah harus meminta akses dari kernel untuk berinteraksi dengan perangkat keras - melalui panggilan sistem.
Pada tingkat biner, panggilan sistem sedikit berbeda dari panggilan fungsi sederhana, namun sebagian besar program menggunakan pembungkus di perpustakaan standar. Yaitu pustaka standar POSIX C berisi panggilan ke fungsi write () , yang berisi semua kode khusus arsitektur untuk panggilan sistem tulis .

Singkatnya, setiap interaksi antara aplikasi dan lingkungannya (sistem komputer) dilakukan melalui panggilan sistem. Oleh karena itu, ketika perangkat lunak bekerja pada satu mesin dan bukan pada yang lain, alangkah baiknya untuk melihat hasil penelusuran panggilan sistem. Untuk lebih spesifik, berikut adalah daftar titik-titik tipikal yang dapat dianalisis menggunakan pelacakan panggilan sistem:
- Konsol I / O
- Input / output jaringan
- Akses Sistem File dan File I / O
- Manajemen proses / utas seumur hidup
- Manajemen Memori Tingkat Rendah
- Akses ke driver perangkat tertentu
Kapan harus menggunakan strace?
Secara teori, strace digunakan dengan program apa pun di ruang pengguna, karena program apa pun di ruang pengguna harus melakukan panggilan sistem. Ia bekerja lebih efisien dengan mengkompilasi, program tingkat rendah, tetapi juga bekerja dengan bahasa tingkat tinggi seperti Python jika Anda dapat melewati kebisingan tambahan dari runtime dan interpreter.
Dalam semua kemegahannya, strace memanifestasikan dirinya selama debugging perangkat lunak yang bekerja dengan baik pada satu mesin, tetapi tiba-tiba berhenti bekerja pada yang lain, memberikan pesan yang tidak jelas tentang file, izin atau upaya gagal untuk menjalankan beberapa perintah atau sesuatu ... Sayang sekali, tapi tidak begitu baik itu dikombinasikan dengan masalah tingkat tinggi seperti kesalahan verifikasi sertifikat. Ini biasanya memerlukan kombinasi alat strace , kadang ltrace, dan tingkat yang lebih tinggi (seperti alat baris perintah openssl untuk debugging sertifikat).
Misalnya, kami bekerja di server yang berdiri sendiri, tetapi melacak panggilan sistem sering dapat dilakukan pada platform penyebaran yang lebih kompleks. Anda hanya perlu memilih toolkit yang tepat.
Contoh Debugging Sederhana
Katakanlah Anda ingin menjalankan aplikasi server foo yang luar biasa, tetapi ternyata ini:
$ foo Error opening configuration file: No such file or directory
Jelas, dia tidak dapat menemukan file konfigurasi yang Anda tulis. Ini terjadi karena kadang-kadang, ketika manajer paket mengkompilasi aplikasi, mereka mengesampingkan lokasi file yang diharapkan. Dan jika Anda mengikuti panduan instalasi untuk satu distribusi, di yang lain Anda menemukan file sepenuhnya tidak seperti yang saya harapkan. Mungkin untuk menyelesaikan masalah dalam beberapa detik jika pesan kesalahan mengatakan di mana harus mencari file konfigurasi, tetapi tidak dikatakan. Jadi ke mana harus mencari?
Jika Anda memiliki akses ke kode sumber, Anda dapat membacanya dan mengetahuinya. Paket cadangan yang bagus, tetapi bukan solusi tercepat. Anda dapat menggunakan debugger langkah-demi-langkah seperti gdb dan melihat apa yang dilakukan program, tetapi jauh lebih efisien untuk menggunakan alat yang dirancang khusus untuk menunjukkan interaksi dengan lingkungan: strace .
Kesimpulan dari strace mungkin tampak berlebihan, tetapi kabar baiknya adalah sebagian besar dapat diabaikan dengan aman. Seringkali berguna untuk menggunakan operator -o untuk menyimpan hasil penelusuran ke file terpisah:
$ strace -o /tmp/trace foo Error opening configuration file: No such file or directory $ cat /tmp/trace execve("foo", ["foo"], 0x7ffce98dc010 /* 16 vars */) = 0 brk(NULL) = 0x56363b3fb000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) openat(AT_FDCWD, "/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=25186, ...}) = 0 mmap(NULL, 25186, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f2f12cf1000 close(3) = 0 openat(AT_FDCWD, "/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\260A\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=1824496, ...}) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f2f12cef000 mmap(NULL, 1837056, PROT_READ, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f2f12b2e000 mprotect(0x7f2f12b50000, 1658880, PROT_NONE) = 0 mmap(0x7f2f12b50000, 1343488, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x22000) = 0x7f2f12b50000 mmap(0x7f2f12c98000, 311296, PROT_READ, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x16a000) = 0x7f2f12c98000 mmap(0x7f2f12ce5000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1b6000) = 0x7f2f12ce5000 mmap(0x7f2f12ceb000, 14336, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f2f12ceb000 close(3) = 0 arch_prctl(ARCH_SET_FS, 0x7f2f12cf0500) = 0 mprotect(0x7f2f12ce5000, 16384, PROT_READ) = 0 mprotect(0x56363b08b000, 4096, PROT_READ) = 0 mprotect(0x7f2f12d1f000, 4096, PROT_READ) = 0 munmap(0x7f2f12cf1000, 25186) = 0 openat(AT_FDCWD, "/etc/foo/config.json", O_RDONLY) = -1 ENOENT (No such file or directory) dup(2) = 3 fcntl(3, F_GETFL) = 0x2 (flags O_RDWR) brk(NULL) = 0x56363b3fb000 brk(0x56363b41c000) = 0x56363b41c000 fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(0x88, 0x8), ...}) = 0 write(3, "Error opening configuration file"..., 60) = 60 close(3) = 0 exit_group(1) = ? +++ exited with 1 +++
Tentang seluruh halaman pertama dari output strace biasanya merupakan persiapan tingkat rendah untuk diluncurkan. (Ada banyak mmap , mprotect , panggilan brk untuk hal-hal seperti mendeteksi memori tingkat rendah dan menampilkan pustaka dinamis.) Faktanya, selama debugging, output strace paling baik dibaca dari awal. Di bagian bawah adalah panggilan untuk menulis , yang menampilkan pesan kesalahan. Kami melihat di atas dan melihat panggilan sistem yang salah pertama - panggilan openat yang melempar kesalahan ENOENT ("file atau direktori tidak ditemukan"), mencoba membuka /etc/foo/config.json . Di sini, di sini file konfigurasi seharusnya terletak.
Itu hanya sebuah contoh, tetapi saya akan mengatakan bahwa 90% dari waktu saya menggunakan strace , tidak ada yang lebih sulit untuk dilakukan dan tidak harus. Di bawah ini adalah panduan debugging langkah-demi-langkah lengkap:
- Frustrasi oleh pesan kesalahan sistem-y cadel dari suatu program
- Mulai ulang program dengan strace
- Temukan pesan kesalahan dalam hasil penelusuran
- Pergi lebih tinggi sampai Anda bertemu dengan panggilan sistem gagal pertama
Sangat mungkin bahwa panggilan sistem pada langkah 4 akan menunjukkan apa yang salah.
Kiat
Sebelum menunjukkan contoh debugging yang lebih kompleks, saya akan memberi tahu Anda beberapa trik untuk menggunakan strace secara efektif:
pria adalah temanmu
Pada banyak sistem * nix, daftar lengkap panggilan sistem kernel dapat diperoleh dengan menjalankan syscalls . Anda akan melihat hal-hal seperti brk (2) , yang berarti Anda bisa mendapatkan informasi lebih lanjut dengan menjalankan man 2 brk .
Garpu kecil rake: man 2 menunjukkan kepada saya sebuah halaman untuk shell fork () di GNU libc , yang ternyata diimplementasikan menggunakan panggilan clone () . Semantik panggilan fork tetap sama jika Anda menulis program yang menggunakan fork () dan mulai melacak - saya tidak akan menemukan panggilan fork , alih-alih mereka akan ada klon () . Rake semacam itu hanya membingungkan jika Anda mulai membandingkan sumber dengan output dari strace .
Gunakan -o untuk menyimpan output ke file
strace dapat menghasilkan keluaran yang luas, sehingga seringkali berguna untuk menyimpan hasil penelusuran dalam file yang terpisah (seperti dalam contoh di atas). Dan itu membantu untuk tidak membingungkan output program dengan output strace di konsol.
Gunakan -s untuk melihat lebih banyak data argumen
Anda mungkin memperhatikan bahwa bagian kedua dari pesan kesalahan tidak ditampilkan dalam contoh jejak di atas. Ini karena strace hanya menampilkan 32 byte pertama dari argumen string secara default. Jika Anda ingin melihat lebih banyak, tambahkan sesuatu seperti -s 128 ke panggilan strace .
-Y Memfasilitasi pelacakan file \ soket \ dan sebagainya.
βEverything is a fileβ berarti sistem * nix melakukan semua I / O menggunakan deskriptor file, apakah itu berlaku untuk file atau jaringan, atau ke saluran antarproses. Ini nyaman untuk pemrograman, tetapi membuatnya sulit untuk melacak apa yang sebenarnya terjadi ketika Anda melihat umum membaca dan menulis dalam jejak hasil panggilan sistem.
Dengan menambahkan operator -u, Anda memaksa strace untuk membubuhi keterangan setiap deskriptor file dalam output dengan catatan apa yang ditunjukkannya.
Lampirkan ke proses yang sudah berjalan dengan -p **
Seperti yang akan dilihat dari contoh di bawah ini, kadang-kadang Anda perlu melacak program yang sudah berjalan. Jika Anda tahu itu berjalan sebagai proses 1337 (katakanlah, dari kesimpulan ps ), maka Anda dapat melacaknya seperti ini:
$ strace -p 1337 ...system call trace output...
Mungkin Anda membutuhkan root privilege.
Gunakan -f untuk memantau proses anak
strace secara default hanya melacak satu proses. Jika proses ini memunculkan proses anak, maka Anda dapat melihat panggilan sistem untuk menelurkan proses anak, tetapi panggilan sistem proses anak tidak akan ditampilkan.
Jika Anda berpikir bahwa kesalahan ada dalam proses turunan , gunakan operator -f , ini akan memungkinkan penelusurannya. Kelemahan dari ini adalah bahwa kesimpulannya akan membuat Anda lebih bingung. Ketika strace melacak satu proses atau satu utas, itu menunjukkan aliran peristiwa panggilan tunggal. Ketika melacak beberapa proses sekaligus, maka Anda mungkin akan melihat awal panggilan terputus oleh pesan <unfinished ...> , lalu sekelompok panggilan untuk cabang eksekusi lainnya, dan hanya kemudian akhir dari yang pertama dengan <... foocall dilanjutkan> . Atau, pisahkan semua hasil penelusuran ke dalam file yang berbeda, menggunakan operator -ff juga ( lihat manual strace untuk perincian).
Saring jejaknya dengan -e
Seperti yang Anda lihat, hasil penelusuran adalah kumpulan nyata dari semua panggilan sistem yang mungkin. Dengan flag -e , Anda dapat memfilter jejak (lihat manual strace ). Keuntungan utama adalah menjalankan jejak dengan pemfilteran lebih cepat daripada melakukan jejak penuh, dan kemudian grep . Sejujurnya, saya hampir selalu tidak peduli.
Tidak semua kesalahan itu buruk
Contoh sederhana dan umum adalah program mencari file di beberapa tempat sekaligus, seperti shell mencari, di mana keranjang / direktori berisi file yang dapat dieksekusi:
$ strace sh -c uname ... stat("/home/user/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory) stat("/usr/local/bin/uname", 0x7ffceb817820) = -1 ENOENT (No such file or directory) stat("/usr/bin/uname", {st_mode=S_IFREG|0755, st_size=39584, ...}) = 0 ...
Heuristik "permintaan gagal terakhir sebelum pesan kesalahan" bagus untuk menemukan kesalahan yang relevan. Bagaimanapun, adalah logis untuk memulai dari awal.
C Panduan Pemrograman Bantuan Memahami Panggilan Sistem
Panggilan standar ke pustaka C bukan panggilan sistem, tetapi hanya lapisan permukaan yang tipis. Jadi, jika Anda memahami setidaknya sedikit bagaimana dan apa yang harus dilakukan dalam C, akan lebih mudah bagi Anda untuk memahami hasil penelusuran panggilan sistem. Misalnya, jika Anda mengalami masalah debugging panggilan ke sistem jaringan, lihat "Panduan Pemrograman Jaringan" Bija yang sama.
Contoh debugging yang lebih rumit
Saya sudah mengatakan bahwa contoh debugging sederhana adalah contoh dari sesuatu yang, sebagian besar, saya harus berurusan dengan strace . Namun, terkadang diperlukan investigasi nyata, jadi inilah contoh nyata debugging yang lebih rumit.
bcron adalah penjadwal pemrosesan tugas, implementasi lain dari daemon cron * nix. Itu diinstal di server, tetapi ketika seseorang mencoba mengedit jadwal, inilah yang terjadi:
# crontab -e -u logs bcrontab: Fatal: Could not create temporary file
Oke, jadi bcron mencoba menulis file tertentu, tetapi tidak berhasil dan dia tidak mengakui alasannya. Temukan strace :
# strace -o /tmp/trace crontab -e -u logs bcrontab: Fatal: Could not create temporary file # cat /tmp/trace ... openat(AT_FDCWD, "bcrontab.14779.1573691864.847933", O_RDONLY) = 3 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000 read(3, "#Ansible: logsagg\n20 14 * * * lo"..., 8192) = 150 read(3, "", 8192) = 0 munmap(0x7f82049b4000, 8192) = 0 close(3) = 0 socket(AF_UNIX, SOCK_STREAM, 0) = 3 connect(3, {sa_family=AF_UNIX, sun_path="/var/run/bcron-spool"}, 110) = 0 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f82049b4000 write(3, "156:Slogs\0#Ansible: logsagg\n20 1"..., 161) = 161 read(3, "32:ZCould not create temporary f"..., 8192) = 36 munmap(0x7f82049b4000, 8192) = 0 close(3) = 0 write(2, "bcrontab: Fatal: Could not creat"..., 49) = 49 unlink("bcrontab.14779.1573691864.847933") = 0 exit_group(111) = ? +++ exited with 111 +++
Pada akhirnya, ada pesan kesalahan tulis , tetapi kali ini ada sesuatu yang berbeda. Pertama, tidak ada kesalahan panggilan sistem yang relevan yang biasanya terjadi sebelum ini. Kedua, jelas bahwa di suatu tempat seseorang telah membaca pesan kesalahan. Sepertinya masalah sebenarnya ada di tempat lain, dan bcrontab hanya memutar pesannya.
Jika Anda melihat man 2 read , Anda dapat melihat bahwa argumen pertama (3) adalah deskriptor file yang * nix gunakan untuk semua pemrosesan I / O. Bagaimana cara mencari tahu apa file deskriptor 3 mewakili? Dalam kasus khusus ini, Anda dapat menjalankan strace dengan operator -u (lihat di atas), dan itu akan secara otomatis memberi tahu Anda, namun, untuk menghitung hal-hal seperti itu, berguna untuk mengetahui cara membaca dan menganalisis hasil penelusuran.
Sumber deskriptor file dapat menjadi salah satu dari banyak panggilan sistem (semuanya tergantung pada apa deskriptor untuk konsol, soket jaringan, file itu sendiri, atau sesuatu yang lain), tetapi karena mungkin, kami mencari panggilan yang mengembalikan 3 (t .e mencari "= 3" di hasil penelusuran). Akibatnya, ada 2 di antaranya: openat di bagian paling atas dan soket di tengah. openat membuka file, tetapi tutup (3) setelah itu akan menunjukkan bahwa itu ditutup lagi. (Rake: deskriptor file dapat digunakan kembali ketika dibuka dan ditutup). Panggilan soket () cocok, karena ini adalah yang terakhir sebelum dibaca () , dan ternyata bcrontab berfungsi dengan sesuatu melalui soket. Baris berikutnya menunjukkan bahwa deskriptor file dikaitkan dengan soket domain unix di sepanjang path / var / run / bcron-spool .
Jadi, Anda perlu menemukan proses yang terpasang pada soket unix di sisi lain. Ada beberapa trik bagus untuk tujuan ini, dan keduanya berguna untuk debugging penyebaran server. Yang pertama adalah menggunakan netstat atau yang lebih baru ss (status soket). Kedua perintah menunjukkan koneksi jaringan aktif dari sistem dan mengambil operator -l untuk menggambarkan soket mendengarkan, dan operator -p untuk menampilkan program yang terhubung ke soket sebagai klien. (Ada banyak opsi yang lebih berguna, tetapi keduanya cukup untuk tugas ini.)
# ss -pl | grep /var/run/bcron-spool u_str LISTEN 0 128 /var/run/bcron-spool 1466637 * 0 users:(("unixserver",pid=20629,fd=3))
Ini menunjukkan bahwa pendengar adalah perintah inixserver yang bekerja dengan proses ID 20629. (Dan, secara kebetulan, menggunakan pendeskripsi file 3 sebagai soket.)
Alat kedua yang sangat berguna untuk menemukan informasi yang sama disebut lsof . Ini mencantumkan semua file yang terbuka (atau deskriptor file) dalam sistem. Atau Anda dapat memperoleh informasi tentang satu file tertentu:
# lsof /var/run/bcron-spool COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME unixserve 20629 cron 3u unix 0x000000005ac4bd83 0t0 1466637 /var/run/bcron-spool type=STREAM
Proses 20629 adalah server yang berumur panjang, jadi Anda dapat melampirkan strace padanya menggunakan sesuatu seperti strace -o / tmp / trace -p 20629 . Jika kita mengedit tugas cron di terminal lain, kita mendapatkan output dari hasil penelusuran dengan kesalahan. Dan inilah hasilnya:
accept(3, NULL, NULL) = 4 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21181 close(4) = 0 accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21181, si_uid=998, si_status=0, si_utime=0, si_stime=0} --- wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED, NULL) = 21181 wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes) rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0 rt_sigreturn({mask=[]}) = 43 accept(3, NULL, NULL) = 4 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21200 close(4) = 0 accept(3, NULL, NULL) = ? ERESTARTSYS (To be restarted if SA_RESTART is set) --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=21200, si_uid=998, si_status=111, si_utime=0, si_stime=0} --- wait4(0, [{WIFEXITED(s) && WEXITSTATUS(s) == 111}], WNOHANG|WSTOPPED, NULL) = 21200 wait4(0, 0x7ffe6bc36764, WNOHANG|WSTOPPED, NULL) = -1 ECHILD (No child processes) rt_sigaction(SIGCHLD, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, {sa_handler=0x55d244bdb690, sa_mask=[CHLD], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7faa47ab9840}, 8) = 0 rt_sigreturn({mask=[]}) = 43 accept(3, NULL, NULL
(Penerimaan terakhir () tidak akan lengkap saat melacak.) Dan lagi, sayangnya, hasil ini tidak mengandung kesalahan yang kita cari. Kami tidak melihat pesan apa pun yang akan dikirimkan atau diterima bcrontag dari soket. Alih-alih, kontrol penuh proses ( clone , wait4 , SIGCHLD , dll.) Proses ini memunculkan proses anak, yang, seperti yang Anda duga, melakukan pekerjaan yang sebenarnya. Dan jika Anda perlu menangkap jejaknya, tambahkan strace -f ke panggilan. Inilah yang kami temukan dengan mencari pesan kesalahan di hasil baru dengan strace -f -o / tmp / trace -p 20629 :
21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 21470 write(1, "32:ZCould not create temporary f"..., 36) = 36 21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84 21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory) 21470 exit_group(111) = ? 21470 +++ exited with 111 +++
Sekarang, ini sesuatu. Proses 21470 menerima kesalahan "akses ditolak" ketika mencoba membuat file di jalur tmp / spool.21470.1573692319.854640 (merujuk ke direktori kerja saat ini). Jika kita hanya tahu direktori kerja saat ini, kita akan tahu path lengkap dan bisa mencari tahu mengapa prosesnya tidak dapat membuat file sementara sendiri di dalamnya. Sayangnya, prosesnya sudah keluar, jadi Anda tidak bisa hanya menggunakan lsof -p 21470 untuk menemukan direktori saat ini, tetapi Anda dapat bekerja di arah yang berlawanan - cari panggilan sistem PID 21470 yang mengubah direktori. (Jika tidak ada, PID 21470 harus mewarisinya dari induknya, dan ini tidak dapat dipecahkan melalui lsof -p .) Panggilan sistem ini adalah chdir (yang mudah ditemukan dengan bantuan mesin pencari jaringan modern). Dan di sini adalah hasil pencarian terbalik berdasarkan hasil penelusuran, hingga server PID 20629 itu sendiri:
20629 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7faa47c44810) = 21470 ... 21470 execve("/usr/sbin/bcron-spool", ["bcron-spool"], 0x55d2460807e0 /* 27 vars */) = 0 ... 21470 chdir("/var/spool/cron") = 0 ... 21470 openat(AT_FDCWD, "tmp/spool.21470.1573692319.854640", O_RDWR|O_CREAT|O_EXCL, 0600) = -1 EACCES (Permission denied) 21470 write(1, "32:ZCould not create temporary f"..., 36) = 36 21470 write(2, "bcron-spool[21470]: Fatal: logs:"..., 84) = 84 21470 unlink("tmp/spool.21470.1573692319.854640") = -1 ENOENT (No such file or directory) 21470 exit_group(111) = ? 21470 +++ exited with 111 +++
(Jika Anda tersesat, Anda mungkin perlu membaca posting saya sebelumnya pada * nix process control and shells .) Jadi, server PID 20629 tidak mendapatkan izin untuk membuat file di sepanjang jalur /var/spool/cron/tmp/spool.21470.1573692319.854640 . , β . :
# ls -ld /var/spool/cron/tmp/ drwxr-xr-x 2 root root 4096 Nov 6 05:33 /var/spool/cron/tmp/ # ps u -p 20629 USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND cron 20629 0.0 0.0 2276 752 ? Ss Nov14 0:00 unixserver -U /var/run/bcron-spool -- bcron-spool
! cron, root /var/spool/cron/tmp/ . chown cron /var/spool/cron/tmp/ bcron . ( , β SELinux AppArmor, dmesg .)
Total
, , , , β . , bcron , .
, , , strace , , . , strace . , .