Unix程式設計/應用問答中文版 ---12.日誌相關問題 13.程式相關問題(轉)
Unix程式設計/應用問答中文版 ---12.日誌相關問題 13.程式相關問題(轉)[@more@]12. 日誌相關問題12.112.212.3 如何關閉cron的日誌12.4--------------------------------------------------------------------------13. 程式相關問題13.1 如何根據程式名獲得PID13.213.313.4 Solaris 7/8下ps輸出中的問號13.513.613.7 給定一個PID,如何知道它對應一個執行中的程式13.8 Unix/Linux程式設計中所謂"殭屍程式"指什麼13.9 x86/FreeBSD 4.3-RELEASE的ptrace(2)手冊頁13.10 Solaris下如何知道哪個程式使用了哪個埠13.11 x86/FreeBSD如何快速獲取指定使用者擁有的程式數--------------------------------------------------------------------------12.3 如何關閉cron的日誌Q: 有些時候cron的日誌檔案增長得如此之大,佔用了大量磁碟空間,有什麼辦法徹底關閉cron的日誌嗎A: Sun Microsystems 1998-03-30編輯/etc/default/cron,設定 CRONLOG 變數為 NO ,將關閉cron的日誌CRONLOG=NO預設是CRONLOG=YES13. 程式相關問題13.1 如何根據程式名獲得PIDQ: 我知道ps、top等命令和grep相結合可以達到這個效果,但是我想在C程式中實現這個功能,並且我不想用system()、popen()等方式。D: Linux提供了一個命令,pidof(8)A: Andrew Gierth第一種辦法是讀取/proc介面提供的資訊--------------------------------------------------------------------------/* gcc -Wall -O3 -o getpid getpid.c */#include#include#include#include#include#include#include#include#includestatic pid_t getpidbyname ( char * name, pid_t skipit ){DIR * dirHandle; /* 目錄控制程式碼 */struct dirent * dirEntry; /* 單個目錄項 */prpsinfo_t prp;int fd;pid_t pid = -1;if ( ( dirHandle = opendir( "/proc" ) ) == NULL ){return( -1 );}chdir( "/proc" ); /* 下面使用相對路徑開啟檔案,所以必須進入/proc */while ( ( dirEntry = readdir( dirHandle ) ) != NULL ){if ( dirEntry->d_name[0] != '.' ){/* fprintf( stderr, "%s
", dirEntry->d_name ); */if ( ( fd = open( dirEntry->d_name, O_RDONLY ) ) != -1 ){if ( ioctl( fd, PIOCPSINFO, &prp ) != -1 ){/* fprintf( stderr, "%s
", prp.pr_fname ); */if ( !strcmp( prp.pr_fname, name ) ) /* 這裡是相對路徑,而且不帶引數 */{pid = ( pid_t )atoi( dirEntry->d_name );if ( skipit != -1 && pid == skipit ) /* -1做為無效pid對待 */{pid = -1;}else /* 找到匹配 */{close( fd );break; /* 跳出while迴圈 */}}}close( fd );}}} /* end of while */closedir( dirHandle );return( pid );} /* end of getpidbyname */static void usage ( char * arg ){fprintf( stderr, " Usage: %s
", arg );exit( EXIT_FAILURE );} /* end of usage */int main ( int argc, char * argv[] ){pid_t pid;if ( argc != 2 ){usage( argv[0] );}pid = getpidbyname( argv[1], -1 );if ( pid != -1 ){fprintf( stderr, "[ %s ] is:
", argv[1], ( unsigned int )pid );exit( EXIT_SUCCESS );}exit( EXIT_FAILURE );} /* end of main */--------------------------------------------------------------------------這種技術要求執行者擁有root許可權,否則無法有效獲取非自己擁有的程式PID。注意下面的演示# ps -f -p 223UID PID PPID C STIME TTY TIME CMDroot 223 1 0 3月 09 ? 0:00 /usr/sbin/vold# ./getpid /usr/sbin/vold # ./getpid vold [ vold ] is: <223>當然你可以自己修改、增強程式,使之匹配各種命令列指定,我就不替你做了。上述程式在32-bit kernel的Solaris 2.6和64-bit kernel的Solaris 7上均測試透過。D: microcat在介紹第二種辦法之前,先看一下microcat提供的這個程式--------------------------------------------------------------------------/** gcc -Wall -DSOLARIS=6 -O3 -o listpid listpid.c -lkvm** /opt/SUNWspro/SC5.0/bin/cc -xarch=v9 -DSOLARIS=7 -O -o listpid listpid.c -lkvm*/#include#include#include#include#includeint main ( int argc, char * argv[] ){kvm_t * kd;struct proc * p;struct pid pid;if ( ( kd = kvm_open( NULL, NULL, NULL, O_RDONLY, NULL ) ) == NULL ){perror( "kvm_open" );exit( EXIT_FAILURE );}while ( ( p = kvm_nextproc( kd ) ) ) /* 遍歷P區 */{#if SOLARIS == 7if ( kvm_kread( kd, ( uintptr_t )p->p_pidp, &pid, sizeof( pid ) ) < 0 )#elif SOLARIS == 6if ( kvm_kread( kd, ( unsigned long )p->p_pidp, ( char * )&pid, sizeof(pid ) ) < 0 )#endif{perror( "kvm_kread" );}else{printf( "PID: %d
", ( int )pid.pid_id );}} /* end of while */kvm_close( kd );exit( EXIT_SUCCESS );} /* end of main */--------------------------------------------------------------------------A: Andrew Gierth第二種辦法是使用kvm_*()函式--------------------------------------------------------------------------#define _KMEMUSER /* 必須定義這個宏 */#include#include#include#include#include#include/*static void argv_free ( char ** argv ){size_t i;for ( i = 0; argv[i] != NULL; i++ ){free( argv[i] );argv[i] = NULL;}free( argv );}*/static pid_t getpidbyname ( char * name, pid_t skipit ){kvm_t * kd;int error;char ** argv = NULL;char * p_name = NULL;pid_t pid = -1;char expbuf[256];char regexp_str[256];struct user * cur_user;struct proc * cur_proc;struct pid p;sprintf( regexp_str, "^.*%s$", name );if ( compile( regexp_str, expbuf, expbuf + 256 ) == NULL ) /* 正規表示式 */{perror( "compile" );return( -1 );}if ( ( kd = kvm_open( NULL, NULL, NULL, O_RDONLY, NULL ) ) == NULL ){perror( "kvm_open" );return( -1 );}while ( ( cur_proc = kvm_nextproc( kd ) ) ) /* 遍歷P區 */{#if SOLARIS == 7if ( kvm_kread( kd, ( uintptr_t )cur_proc->p_pidp, &p, sizeof( p ) ) < 0)#elif SOLARIS == 6if ( kvm_kread( kd, ( unsigned long )cur_proc->p_pidp, ( char * )&p, sizeof( p ) ) < 0 )#endif{perror( "kvm_kread" );continue;}pid = p.pid_id;if ( ( cur_user = kvm_getu( kd, cur_proc ) ) != NULL ){/* fprintf( stderr, "cur_proc = %p cur_user = %p
", cur_proc, cur_user ); */error = kvm_getcmd( kd, cur_proc, cur_user, &argv, NULL );/** fprintf( stderr, "[ %s ] is:
", cur_user->u_comm, ( unsigned int )pid );** 比如in.telnetd、syslogd、bash、login*/if ( error == -1 ) /* 失敗,比如argv[]已經被程式自己修改過 */{if ( cur_user->u_comm[0] != '' ){p_name = cur_user->u_comm; /* 從另外一個地方獲取資訊 */}}else /* 成功 */{/** fprintf( stderr, "[ %s ] is:
", argv[0], ( unsigned int)pid );** 比如-bash、login、in.telnetd、/usr/sbin/syslogd*/p_name = argv[0];}}if ( p_name ){if ( ( strcmp( p_name, name ) == 0 ) || step( p_name, expbuf ) ){if ( skipit != -1 && pid == skipit ) /* -1做為無效pid對待 */{pid = -1;}else /* 找到匹配,返回pid */{break; /* 跳出while迴圈 */}}}if ( argv != NULL ){/* argv_free( argv ); */free( argv );argv = NULL;}p_name = NULL; /* 必須增加這條,否則流程有問題 */} /* end of while */if ( argv != NULL ){/* argv_free( argv ); */free( argv );argv = NULL;}kvm_close( kd );return( pid );} /* end of getpidbyname */static void usage ( char * arg ){fprintf( stderr, " Usage: %s
", arg );exit( EXIT_FAILURE );} /* end of usage */int main ( int argc, char * argv[] ){pid_t pid;if ( argc != 2 ){usage( argv[0] );}pid = getpidbyname( argv[1], -1 );if ( pid != -1 ){fprintf( stderr, "[ %s ] is:
", argv[1], ( unsigned int )pid );exit( EXIT_SUCCESS );}exit( EXIT_FAILURE );} /* end of main */--------------------------------------------------------------------------這個程式同樣必須以root身份執行,在SPARC/Solaris 2.6/7上測試透過13.4 Solaris 7/8下ps輸出中的問號Q: 比如ps -el的輸出中有很多問號,可我覺得它們應該有一個確定的值A: Michael Shapiro有些時候ps(1)輸出的單行過於長了,為了輸出美觀,某些列的值用問號代替,尤其64-bit核心下ADDR列。可以用-o引數指定要顯示的列,比如# ps -o pid,tty,addr,wchan,fname -p $$PID TT ADDR WCHAN COMMAND2602 pts/4 30000a154b8 30000a15578 bash# ps -e -o pid,tty,addr,wchan,fname13.7 給定一個PID,如何知道它對應一個執行中的程式A: Andrew Gierth這個回答來自著名的<>,由Andrew Gierth負責維護,其它細節請參看原文。kill( pid, 0 ),此時有四種可能的返回值1) kill()返回0意味著指定PID的確對應著一個執行中的程式,系統允許你向該程式傳送訊號。至於該程式能否是zombie process(殭屍程式),是系統相關的。2) kill()返回-1,errno == ESRCH指定PID並不對應一個執行中的程式,或者許可權不夠無法完成判斷。某些系統上,如果對應程式是殭屍程式時,也如此返回。3) kill()返回-1,errno == EPERM系統不允許你kill指定程式,程式存在(可能是zombie),許可權不夠。4) kill()返回-1,errno是其它值你麻煩來了(嘿嘿)最有用的技術,假設成功表示程式存在,EPERM失敗也表示程式存在,其它失敗表示指定PID不對應一個執行中的程式。此外如果系統支援proc偽檔案系統,檢查/proc/是否存在,存在表明指定PID對應執行中的程式。13.8 Unix/Linux程式設計中所謂"殭屍程式"指什麼Q: Unix/Linux程式設計中所謂"殭屍程式"指什麼,什麼情況下會產生殭屍程式,如何殺掉殭屍程式。A: 在fork()/execve()過程中,假設子程式結束時父程式仍存在,而父程式fork()之前既沒安裝SIGCHLD訊號處理函式呼叫waitpid()等待子程式結束,又沒有顯式忽略該訊號,則子程式成為殭屍程式,無法正常結束,此時即使是root身份kill -9也不能殺死殭屍程式。補救辦法是殺死殭屍程式的父程式(殭屍程式的父程式必然存在),殭屍程式成為"孤兒程式",過繼給1號程式init,init始終會負責清理僵屍程式。13.9 x86/FreeBSD 4.3-RELEASE的ptrace(2)手冊頁A: scz下面來看一個簡單的ptrace(2)演示,x86/FreeBSD 4.3-RELEASE--------------------------------------------------------------------------/** gcc -Wall -pipe -O3 -o target target.c*/#include#include#include#include#includeint main ( int argc, char * argv[] ){write( STDERR_FILENO, "Hello world
", 12 );return( EXIT_SUCCESS );} /* end of main */----------------------------------------------------------------------------------------------------------------------------------------------------/** gcc -Wall -pipe -O3 -o ptracetest ptracetest.c*/#include#include#include#include#include#include#include#include#includeint main ( int argc, char * argv[] ){pid_t p;p = fork();if ( p < 0 ){perror( "fork error" );exit( EXIT_FAILURE );}else if ( p == 0 ){/** 子程式*/errno = 0;ptrace( PT_TRACE_ME, 0, 0, 0 );if ( errno != 0 ){perror( "child process ptrace error" );exit( EXIT_FAILURE );}else{char * name[2];name[0] = "./target";name[1] = NULL;/** 切換程式映像時停止執行*/execve( name[0], name, NULL );perror( "child process execve error" );exit( EXIT_FAILURE );}}else{/** 父程式*/fprintf( stderr, "Having a child process
", ( int )p );/** 阻塞式waitpid()*/waitpid( p, NULL, 0 );fprintf( stderr, "Now in parent process, ""please enter [CR] to continue ... ...
" );getchar();errno = 0;ptrace( PT_CONTINUE, p, ( caddr_t )1, 0 );if ( errno != 0 ){perror( "parent process ptrace error" );exit( EXIT_FAILURE );}/** 作為ptrace(2)演示,這裡必須等待子程式先結束,否則由於父程式終止* 而殺死子程式*/fprintf( stderr, "Waiting the child process terminate ... ...
" );getchar();}return( EXIT_SUCCESS );} /* end of main */--------------------------------------------------------------------------13.10 Solaris下如何知道哪個程式使用了哪個埠Q: netstat -na -P tcp告訴我哪些埠是開啟的,但它沒有報告是哪個程式開啟的。lsof可以滿足我的需求,可我不想用lsof,它不是預設安裝的D: FreeBSD 4.3-RELEASE中netstat -s -p tcp 查香tcp協議的統計量netstat -na | grep tcp4 才能達到類似Solaris下netstat -na -P tcp的效果FreeBSD 4.4-RELEASE中netstat -na -p tcp效果類似於Solaris下netstat -na -P tcpA: Vitaly Filatov & scz對於Solaris 8,可以使用這個演示指令碼,如果不能滿足你的需要,請自行修改--------------------------------------------------------------------------#! /bin/sh# find_socket_proc.sh for x86/SPARC Solaris 8## File : find_socket_proc.sh# Author : Vitaly Filatov# Fix : scz# Platform : x86/SPARC Solaris 8# Version : 1.00 aleph# Usage :# Date : 2001-10-28 00:32# Modify :#PLATFORM="`uname -p`"if [ "${PLATFORM}" = "sparc" ] ; thenPREFIX=""elif [ "${PLATFORM}" = "i386" ] ; thenPREFIX="/usr"fiEGREP="${PREFIX}/bin/egrep"NAWK="${PREFIX}/bin/nawk"PFILES="/usr/proc/bin/pfiles"PS="${PREFIX}/bin/ps"SED="${PREFIX}/bin/sed"PROCLIST="`${PS} -ef | ${NAWK} 'NR > 1 {print $2}'`"for PID in ${PROCLIST} ; doif [ -n "`${PFILES} ${PID} 2>/dev/null | ${EGREP} S_IFSOCK`" ] ; thenLINE_1="`${PS} -o pid,args -p ${PID} | ${NAWK} 'NR > 1 {print $0}'`"PORTLIST="`${PFILES} ${PID} 2>/dev/null | ${EGREP} 'sockname:' | ${SED} -e 's/.*port: (.*)/1/g'`"for PORT in ${PORTLIST} ; doecho "${LINE_1} port-->${PORT}"donefidone--------------------------------------------------------------------------如果你以普通使用者身份執行,只能檢查自己的程式,如果以root身份執行,可以檢查所有使用者的程式。13.11 x86/FreeBSD如何快速獲取指定使用者擁有的程式數Q: 誰能給我一段C程式碼,快速統計出一個指定使用者所擁有的程式數。我想修改Apache以阻止它超過kern.maxprocperuid限制後繼續fork()產生新程式。如果Apache以sudo方式啟動,就可能出現這種情況。我該看ps(1)的原始碼嗎?A: Maxim Konovalov參看src/usr.bin/killall/killall.c,這裡用了sysctl()介面A: Andrew可以試試kvm_getprocs( KERN_PROC_UID
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-944702/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Unix程式設計/應用問答中文版 ---21.FreeBSD相關問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---4.系統資源相關問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---17.檔案檢視問題 18.補丁相關問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---19.終端相關問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---20.shell script問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---1.系統管理配置問題(轉)程式設計
- Unix程式設計/應用問答中文版 ---14.一些小工具的使用 15.32-bit/64-bit相關問題(轉)程式設計
- 小程式視訊旋轉的相關問題
- Docker 相關問題Docker
- Java相關問題整理Java
- PHP相關問題集合PHP
- Flutter-Android 應用打包相關問題FlutterAndroid
- Q&A:「微搭低程式碼」計費相關問題
- 自考畢業論文答辯相關問題解答
- mysql相關問題總結MySql
- 個人專案相關問題
- Sql Mode及相關問題SQL
- Oracle MTS的相關問題Oracle
- 瀏覽器相關問題瀏覽器
- 關於盒模型相關的問題模型
- 關於 go-micro 相關問題Go
- Unix程式設計/應用問答中文版 ---6./etc/system可調資源限制(轉)程式設計
- Unix(Linux) C程式設計問題精粹 (轉)LinuxC程式程式設計
- Unix(Linux) C程式設計問題精粹(轉)LinuxC程式程式設計
- Unix(Linux)C程式設計問題精粹(轉)LinuxC程式程式設計
- 好程式設計師web前端教程分享三大前端框架相關問題程式設計師Web前端框架
- 中介軟體相關問題整理
- java語言相關的問題Java
- Spring相關問題記錄Spring
- 面試遇到的redis相關問題面試Redis
- 資料庫事物相關問題資料庫
- SpringBoot-相關問題Spring Boot
- Oracle kill session相關問題(上)OracleSession
- Oracle kill session相關問題(下)OracleSession
- 多執行緒相關問題執行緒
- GoldenGate實施相關問題Go
- 關於程式猿的六個問答題
- 【Java面試題】如何回答GC相關問題Java面試題GC