首页 > 编程开发 > C/C++ > 正文  
Unix编程/应用问答中文版 ---12.日志相关问题 13.进程相关问题
出自:http://www.nsfocus.com 小四 2001年12月01日 13:38
12. 日志相关问题
12.1
12.2
12.3 如何关闭cron的日志
12.4
--------------------------------------------------------------------------
13. 进程相关问题
13.1 如何根据进程名获得PID
13.2
13.3
13.4 Solaris 7/8下ps输出中的问号
13.5
13.6
13.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=YES

13. 进程相关问题

13.1 如何根据进程名获得PID

Q: 我知道ps、top等命令和grep相结合可以达到这个效果,但是我想在C程序中实现
这个功能,并且我不想用system()、popen()等方式。

D: Linux提供了一个命令,pidof(8)

A: Andrew Gierth <andrew@erlenstar.demon.co.uk>

第一种办法是读取/proc接口提供的信息

--------------------------------------------------------------------------
/* gcc -Wall -O3 -o getpid getpid.c */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/procfs.h>
#include <unistd.h>
#include <stropts.h>
#include <dirent.h>
#include <fcntl.h>

static 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 <proc_name> ", 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: <%u> ", argv[1], ( unsigned int )pid );
exit( EXIT_SUCCESS );
}
exit( EXIT_FAILURE );
} /* end of main */
--------------------------------------------------------------------------

这种技术要求运行者拥有root权限,否则无法有效获取非自己拥有的进程PID。注意
下面的演示

# ps -f -p 223

UID PID PPID C STIME TTY TIME CMD
root 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 <rotm@263.net>

在介绍第二种办法之前,先看一下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 -lkv
m
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <kvm.h>
#include <fcntl.h>

int 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 == 7
if ( kvm_kread( kd, ( uintptr_t )p->p_pidp, &pid, sizeof( pid ) ) < 0 )
#elif SOLARIS == 6
if ( 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 <andrew@erlenstar.demon.co.uk>

第二种办法是使用kvm_*()函数

--------------------------------------------------------------------------
#define _KMEMUSER /* 必须定义这个宏 */

#include <stdio.h>
#include <stdlib.h>
#include <regexpr.h>
#include <sys/proc.h>
#include <kvm.h>
#include <fcntl.h>

/*
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, "^.*%s501SINA>DOUBLE_QUOTATION, 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 == 7
if ( kvm_kread( kd, ( uintptr_t )cur_proc->p_pidp, &p, sizeof( p ) ) < 0
)
#elif SOLARIS == 6
if ( kvm_kread( kd, ( unsigned long )cur_proc->p_pidp, ( char * )&p, siz
eof( 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_u
ser ); */
error = kvm_getcmd( kd, cur_proc, cur_user, &argv, NULL );
/*
* fprintf( stderr, "[ %s ] is: <%u> ", cur_user->u_comm, ( unsigne
d int )pid );
*
* 比如in.telnetd、syslogd、bash、login
*/
if ( error == -1 ) /* 失败,比如argv[]已经被进程自己修改过 */
{
if ( cur_user->u_comm[0] != '