Unix编程/应用问答中文版

时间:2007-04-18 08:33:35   来源:  作者:  点击:次  出处:技术无忧
关键字:unix FAQ 编程 应用 问答

2.5 如何得到一个运行中进程的内存映像

A: Sun Microsystems 1998-03-30

有些时候必须得到一个运行中进程的内存映像而不能停止该进程,Solaris系统了这
样的工具,gcore为运行中进程创建一个core文件。假设我的bash进程号是5347

# gcore 5347
gcore: core.5347 dumped
# file core.5347
core.5347:      ELF 32-位 MSB core文件 SPARC 版本 1,来自'bash'
#

注意,只能获取属主是你自己的进程的内存映像,除非你是root。

2.6 调试器如何工作的

Q: 我想在一个自己编写的程序中单步运行另外一个程序,换句话说,那是一个调试
  器,该如何做?

A: Erik de Castro Lopo <nospam@mega-nerd.com>

  这是一个操作系统相关的问题。最一般的回答是使用ptrace()系统调用,尽管我
  不确认究竟这有多么普遍。Linux man手册上说SVr4、SVID EXT、AT&T、X/OPEN
  和BSD 4.3都支持它。

  为了使用ptrace(),你的程序应该调用fork(),然后在子进程中做如下调用:

  ptrace( PTRACE_TRACEME, 0, 0, 0 );

  接下来调用exec()家族的函数执行你最终企图跟踪的程序。

  为了单步进入子进程,在父进程中调用:

  ptrace( PTRACE_SINGLESTEP, 0, 0, 0 );

  还有一些其他函数做恢复/设置寄存器、内存变量一类的工作。

  GDB的源代码足以回答这个问题。

2.7 x86/Linux上如何处理SIGFPE信号

Q: 参看如下程序

--------------------------------------------------------------------------
/*
* gcc -Wall -pipe -O3 -o sigfpe_test_0 sigfpe_test_0.c
*
* 注意与下面的编译效果进行对比,去掉优化开关-O3
*
* gcc -Wall -pipe -o sigfpe_test_0 sigfpe_test_0.c
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>

/*
* for signal handlers
*/
typedef void Sigfunc ( int );

      Sigfunc * signal ( int signo, Sigfunc *func );
static Sigfunc * Signal ( int signo, Sigfunc *func );
static void      on_fpe ( int signo );

Sigfunc * signal ( int signo, Sigfunc *func )
{
   struct sigaction act, oact;

   act.sa_handler = func;
   sigemptyset( &act.sa_mask );
   act.sa_flags   = 0;
   if ( signo == SIGALRM )
   {
#ifdef  SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */
#endif
   }
   else
   {
#ifdef  SA_RESTART
       act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */
#endif
   }
   if ( sigaction( signo, &act, &oact ) < 0 )
   {
       return( SIG_ERR );
   }
   return( oact.sa_handler );
}  /* end of signal */

static Sigfunc * Signal ( int signo, Sigfunc *func )
{
   Sigfunc *sigfunc;

   if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR )
   {
       perror( "signal" );
       exit( EXIT_FAILURE );
   }
   return( sigfunc );
}  /* end of Signal */

static void on_fpe ( int signo )
{
   fprintf( stderr, "here is on_fpe\n" );
   return;
}  /* end of on_fpe */

int main ( int argc, char * argv[] )
{
   unsigned int i;

   Signal( SIGFPE, on_fpe );
   i = 51211314 / 0;
   /*
    * 另外,增加这行后,再次对比有-O3和无-O3的效果
    *
    * fprintf( stderr, "i = %#X\n", i );
    */
   return( EXIT_SUCCESS );
}  /* end of main */
--------------------------------------------------------------------------

有-O3、无-O3,以及有无最后那条fprintf()语句,效果上有差别,自行对比。如果
输出"here is on_fpe",则会发现永不停止。

D: 小四 <scz@nsfocus.com> 2001-12-14 18:25

为了便于讨论,约定两个名词,中断和异常。这里中断指最常规的中断,比如int指
令带来的软中断。异常的典型代表有除0错。区别在于,发生异常时,x86架构上CPU
将当前EIP(指向引发异常的指令)压栈,发生中断时,x86架构上CPU将当前EIP的后一
个地址(指向引发中断的指令的后一条指令)压栈。在异常处理代码中,如果认为能够
从灾难中恢复,可以不修改被压栈的EIP,从而返回到引发异常的指令处。更多细节
请查看Intel手册。

这些是从前DOS下残留的汇编知识,不过也快忘光了,刚才又找元宝宝确认了一下。

在上述代码中,on_fpe()直接返回了,导致再次触发异常,所以无休止输出。事实上
在所有的计算器处理程序中,都会对SIGFPE信号做相应处理,前些日子看yacc/lex的
时候又碰上过。正确的做法是,利用远跳转转移,让开引发异常的指令。

代码修改如下

--------------------------------------------------------------------------
/*
* gcc -Wall -pipe -O3 -o sigfpe_test_1 sigfpe_test_1.c
*
* 注意与下面的编译效果进行对比,去掉优化开关-O3
*
* gcc -Wall -pipe -o sigfpe_test_1 sigfpe_test_1.c
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>

/*
* for signal handlers
*/
typedef void Sigfunc ( int );

      Sigfunc * signal ( int signo, Sigfunc *func );
static Sigfunc * Signal ( int signo, Sigfunc *func );
static void      on_fpe ( int signo );

static sigjmp_buf             jmpbuf;
static volatile sig_atomic_t  canjump = 0;

Sigfunc * signal ( int signo, Sigfunc *func )
{
   struct sigaction act, oact;

   act.sa_handler = func;
   sigemptyset( &act.sa_mask );
   act.sa_flags   = 0;
   if ( signo == SIGALRM )
   {
#ifdef  SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */
#endif
   }
   else
   {
#ifdef  SA_RESTART
       act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */
#endif
   }
   if ( sigaction( signo, &act, &oact ) < 0 )
   {
       return( SIG_ERR );
   }
   return( oact.sa_handler );
}  /* end of signal */

static Sigfunc * Signal ( int signo, Sigfunc *func )
{
   Sigfunc *sigfunc;

   if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR )
   {
       perror( "signal" );
       exit( EXIT_FAILURE );
   }
   return( sigfunc );
}  /* end of Signal */

static void on_fpe ( int signo )
{
   if ( canjump == 0 )
   {
       return;  /* unexpected signal, ignore */
   }
   canjump = 0;
   fprintf( stderr, "here is on_fpe\n" );
   siglongjmp( jmpbuf, signo );  /* jump back to main, don't return */
   return;
}  /* end of on_fpe */

int main ( int argc, char * argv[] )
{
   unsigned int i;

   if ( sigsetjmp( jmpbuf, 1 ) != 0 )
   {
       fprintf( stderr, "c u later\n" );
       return( EXIT_SUCCESS );
   }
   /*
    * now sigsetjump() is OK
    */
   canjump = 1;
   Signal( SIGFPE, on_fpe );
   i = 51211314 / 0;
   /*
    * 另外,增加这行后,再次对比有-O3和无-O3的效果
    *
    * fprintf( stderr, "i = %#X\n", i );
    */
   return( EXIT_SUCCESS );
}  /* end of main */
--------------------------------------------------------------------------

关于-O3的讨论,对gcc编译器熟悉的朋友请继续,呵,我对Linux下的这此东西,实
在缺乏兴趣。

3. -lelf、-lkvm、-lkstat相关问题

3.1 如何判断可执行文件是否携带了调试信息

Q: 某些时候需要知道编译可执行文件时是否携带了调试信息(比如是否指定了-g编译
  选项)。检查可执行文件中是否包含".stab" elf section,".stab" section用于
  保存相关调试信息。

A: Sun Microsystems 2000-05-15

下面这个脚本演示如何判断可执行文件是否携带调试信息

--------------------------------------------------------------------------
#! /bin/sh
#
# Script that test whether or not a given file has been built for
# debug (-g option specified in the compilation)

if [ $# -le 0 ]
then
   echo "Usage: $1 filename"
   exit 1
fi

if [ ! -f $1 ]
then
   echo "File $1 does not exist"
   exit 1
fi

/usr/ccs/bin/dump -hv $1 | /bin/egrep -s '.stab$'
if [ $? -eq 0 ]
then
   echo "File '$1' has been built for debug"
   exit 0
else
   echo "File '$1' has not been built for debug"
   exit 1
fi
--------------------------------------------------------------------------

如果对ELF文件格式不熟悉,理解上述代码可能有点困难,参看
http://www.digibel.org/~tompy/hacking/elf.txt,这是1.1版的ELF文件格式规范。

3.2 mprotect如何用

A: 小四 <cloudsky@263.net>

# truss prtconf 2>&1 | grep sysconf
sysconfig(_CONFIG_PAGESIZE)                     = 8192
sysconfig(_CONFIG_PHYS_PAGES)                   = 16384
#

由此可知当前系统页尺寸是8192字节。

--------------------------------------------------------------------------
/*
* gcc -Wall -g -ggdb -static -o mtest mtest.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>

int main ( int argc, char * argv[] )
{
   char *buf;
   char  c;

   /*
    * 分配一块内存,拥有缺省的rw-保护
    */
   buf = ( char * )malloc( 1024 + 8191 );
   if ( !buf )
   {
       perror( "malloc" );
       exit( errno );
   }
   /*
    * Align to a multiple of PAGESIZE, assumed to be a power of two
    */
   buf     = ( char * )( ( ( unsigned int )buf + 8191 ) & ~8191 );
   c       = buf[77];
   buf[77] = c;
   printf( "ok\n" );
   /*
    * Mark the buffer read-only.
    *
    * 必须保证这里buf位于页边界上,否则mprotect()失败,报告无效参数
    */
   if ( mprotect( buf, 1024, PROT_READ ) )
   {
       perror( "\nmprotect" );
       exit( errno );
   }
   c       = buf[77];
   /*
    * Write error, program dies on SIGSEGV
    */
   buf[77] = c;

   exit( 0 );
}  /* end of main */
--------------------------------------------------------------------------

$ ./mtest
ok
段错误 (core dumped)  <-- 内存保护起作用了
$

3.3 mmap如何用

A: 小四 <cloudsky@263.net>

下面写一个完成文件复制功能的小程序,利用mmap(2),而不是标准文件I/O接口。

--------------------------------------------------------------------------
/*
* gcc -Wall -O3 -o copy_mmap copy_mmap.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>  /* for memcpy */
#include <strings.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define PERMS 0600

int main ( int argc, char * argv[] )
{
   int          src, dst;
   void        *sm, *dm;
   struct stat  statbuf;

   if ( argc != 3 )
   {
       fprintf( stderr, " Usage: %s <source> <target>\n", argv[0] );
       exit( EXIT_FAILURE );
   }
   if ( ( src = open( argv[1], O_RDONLY ) ) < 0 )
   {
       perror( "open source" );
       exit( EXIT_FAILURE );
   }
   /* 为了完成复制,必须包含读打开,否则mmap()失败 */
   if ( ( dst = open( argv[2], O_RDWR | O_CREAT | O_TRUNC, PERMS ) ) < 0 )
   {
       perror( "open target" );
       exit( EXIT_FAILURE );
   }
   if ( fstat( src, &statbuf ) < 0 )
   {
       perror( "fstat source" );
       exit( EXIT_FAILURE );
   }
   /*
    * 参看前面man手册中的说明,mmap()不能用于扩展文件长度。所以这里必须事
    * 先扩大目标文件长度,准备一个空架子等待复制。
    */
   if ( lseek( dst, statbuf.st_size - 1, SEEK_SET ) < 0 )
   {
       perror( "lseek target" );
       exit( EXIT_FAILURE );
   }
   if ( write( dst, &statbuf, 1 ) != 1 )
   {
       perror( "write target" );
       exit( EXIT_FAILURE );
   }
   /* 读的时候指定 MAP_PRIVATE 即可 */
   sm = mmap( 0, ( size_t )statbuf.st_size, PROT_READ,
              MAP_PRIVATE | MAP_NORESERVE, src, 0 );
   if ( MAP_FAILED == sm )
   {
       perror( "mmap source" );
       exit( EXIT_FAILURE );
   }
   /* 这里必须指定 MAP_SHARED 才可能真正改变静态文件 */
   dm = mmap( 0, ( size_t )statbuf.st_size, PROT_WRITE,
              MAP_SHARED, dst, 0 );
   if ( MAP_FAILED == dm )
   {
       perror( "mmap target" );
       exit( EXIT_FAILURE );
   }
   memcpy( dm, sm, ( size_t )statbuf.st_size );
   /*
    * 可以不要这行代码
    *
    * msync( dm, ( size_t )statbuf.st_size, MS_SYNC );
    */
   return( EXIT_SUCCESS );
}  /* end of main */
--------------------------------------------------------------------------

mmap()好处是处理大文件时速度明显快于标准文件I/O,无论读写,都少了一次用户
空间与内核空间之间的复制过程。操作内存还便于设计、优化算法。

文件I/O操作/proc/self/mem不存在页边界对齐的问题。至少Linux的mmap()的最后一
个形参offset并未强制要求页边界对齐,如果提供的值未对齐,系统自动向上舍入到
页边界上。

malloc()分配得到的地址不见得对齐在页边界上

/proc/self/mem和/dev/kmem不同。root用户打开/dev/kmem就可以在用户空间访问到
内核空间的数据,包括偏移0处的数据,系统提供了这样的支持。

显然代码段经过/proc/self/mem可写映射后已经可写,无须mprotect()介入。

D: scz <scz@nsfocus.com>

Solaris 2.6下参看getpagesize(3C)手册页,关于如何获取页大小,一般是8192。
Linux下参看getpagesize(2)手册页,一般是4096。

3.4 getrusage如何用

A: 小四 <cloudsky@263.net>

在SPARC/Solaris 2.6/7下结论一致,只支持了ru_utime和ru_stime成员,其他成员
被设置成0。修改头文件后在FreeBSD 4.3-RELEASE上测试,则不只支持ru_utime和
ru_stime成员。从FreeBSD的getrusage(2)手册页可以看到,这个函数源自4.2 BSD。

如此来说,至少对于SPARC/Solaris 2.6/7,getrusage(3C)并无多大意义。

3.5 setitimer如何用

D: scz <scz@nsfocus.com>

为什么要学习使用setitimer(2),因为alarm(3)属于被淘汰的定时器技术。

A: 小四 <cloudsky@263.net>

下面是个x86/FreeBSD 4.3-RELEASE下的例子

--------------------------------------------------------------------------
/*
* File     : timer_sample.c
* Author   : Unknown (Don't ask me anything about this program)
* Complie  : gcc -Wall -pipe -O3 -o timer_sample timer_sample.c
* Platform : x86/FreeBSD 4.3-RELEASE
* Date     : 2001-09-18 15:18
*/

/************************************************************************
*                                                                      *
*                               Head File                              *
*                                                                      *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <signal.h>

/************************************************************************
*                                                                      *
*                               Macro                                  *
*                                                                      *
************************************************************************/

typedef void Sigfunc ( int );  /* for signal handlers */

/************************************************************************
*                                                                      *
*                            Function Prototype                        *
*                                                                      *
************************************************************************/

static void      Atexit       ( void ( *func ) ( void ) );
static void      init_signal  ( void );
static void      init_timer   ( void );
static void      on_alarm     ( int signo );
static void      on_terminate ( int signo );
static int       Setitimer    ( int which, const struct itimerval *value,
                               struct itimerval *ovalue );
      Sigfunc * signal       ( int signo, Sigfunc *func );
static Sigfunc * Signal       ( int signo, Sigfunc *func );
static void      terminate    ( void );

/************************************************************************
*                                                                      *
*                            Static Global Var                         *
*                                                                      *
************************************************************************/

/************************************************************************/

static void Atexit ( void ( *func ) ( void ) )
{
   if ( atexit( func ) != 0 )
   {
       perror( "atexit" );
       exit( EXIT_FAILURE );
   }
   return;
}  /* end of Atexit */

/*
* 初始化信号句柄
*/
static void init_signal ( void )
{
   int i;

   Atexit( terminate );
   for ( i = 1; i < 9; i++ )
   {
       Signal( i, on_terminate );
   }
   Signal( SIGTERM, on_terminate );
   Signal( SIGALRM, on_alarm );
   return;
}  /* end of init_signal */

static void init_timer ( void )
{
   struct itimerval value;

   value.it_value.tv_sec  = 1;
   value.it_value.tv_usec = 0;
   value.it_interval      = value.it_value;
   Setitimer( ITIMER_REAL, &value, NULL );
}  /* end of init_timer */

static void on_alarm ( int signo )
{
   static int count = 0;

   /*
    * 演示用,这很危险
    */
   fprintf( stderr, "count = %u\n", count++ );
   return;
}

static void on_terminate ( int signo )
{
   /*
    * 这次我们使用atexit()函数
    */
   exit( EXIT_SUCCESS );
}  /* end of on_terminate */

static int Setitimer ( int which, const struct itimerval *value,
                      struct itimerval *ovalue )
{
   int ret;

   if ( ( ret = setitimer( which, value, ovalue ) ) < 0 )
   {
       perror( "setitimer" );
       exit( EXIT_FAILURE );
   }
   return( ret );
}  /* end of Setitimer */

Sigfunc * signal ( int signo, Sigfunc *func )
{
   struct sigaction act, oact;

   act.sa_handler = func;
   sigemptyset( &act.sa_mask );
   act.sa_flags   = 0;
   if ( signo == SIGALRM )
   {
#ifdef  SA_INTERRUPT
       act.sa_flags |= SA_INTERRUPT;  /* SunOS 4.x */
#endif
   }
   else
   {
#ifdef  SA_RESTART
       act.sa_flags |= SA_RESTART;  /* SVR4, 44BSD */
#endif
   }
   if ( sigaction( signo, &act, &oact ) < 0 )
   {
       return( SIG_ERR );
   }
   return( oact.sa_handler );
}  /* end of signal */

static Sigfunc * Signal ( int signo, Sigfunc *func )
{
   Sigfunc *sigfunc;

   if ( ( sigfunc = signal( signo, func ) ) == SIG_ERR )
   {
       perror( "signal" );
       exit( EXIT_FAILURE );
   }
   return( sigfunc );
}  /* end of Signal */

static void terminate ( void )
{
   fprintf( stderr, "\n" );
   return;
}  /* end of terminate */

int main ( int arg, char * argv[] )
{
   init_signal();
   init_timer();
   while ( 1 )
   {
       /*
        * 形成阻塞,降低CPU占用率
        */
       getchar();
   }
   return( EXIT_SUCCESS );
}  /* end of main */

/************************************************************************/

--------------------------------------------------------------------------

D: scz <scz@nsfocus.com>

讨论一个问题。getchar()的作用是降低CPU占用率,可用top命令查看。

timer_sample.c中换用ITIMER_PROF/SIGPROF后,你会发现上述程序无输出,我据此
认为getchar()形成的阻塞不计算在进程虚拟时钟中,也不认为系统正在为进程利益
而运行。

如果进一步将getchar()去掉,直接一个while()无限循环,即使换用
ITIMER_PROF/SIGPROF,程序还是有输出。不过top命令查看的结果让你吐血,CPU几
乎无空闲。

D: scz <scz@nsfocus.com>

setitimer( ITIMER_REAL, &value, NULL )导致分发SIGALRM信号,如果同时使用
alarm(),势毕造成冲突。此外注意sleep()、pause()等函数带来的冲突。

4. 系统资源相关问题

4.1 主流Unix操作系统上如何编程获取进程的内存、CPU利用状况

Q: Solaris下如何编程获知CPU占用率和内存占用信息呢,可移植吗?

Q: 我想写个程序遍历当前运行中的活动进程,Solaris提供相应系统调用了吗

A: Nicholas Dronen <ndronen@io.frii.com>

  不可移植。man -s 4 proc,man -s 3k kstat

  如果不是编程,可以用top、mpstat、vmstat、sar(1)等等,还有
  /usr/ucb/ps -aux,对于Solaris来说,后者更直接精炼,top不是标准配置。

  # /usr/bin/prstat (Solaris 8 prstat(1M)手册页)
  # /usr/ucb/ps -aux | head (Solaris 2.x)

Q: 主流Unix操作系统上如何编程获取进程的内存、CPU利用状况,AIX、HP、SUN
  process memory usage
  process cpu time usage

A: Nate Eldredge <neldredge@hmc.edu>
  man -s 3C getrusage

D: 小四 <cloudsky@263.net>

在SPARC/Solaris 2.6/7下结论一致,只支持了ru_utime和ru_stime成员,其他成员
被设置成0。FreeBSD 4.3-RELEASE上测试,则不只支持ru_utime和ru_stime成员。从
FreeBSD的getrusage(2)手册页可以看到,这个函数源自4.2 BSD。

至少对于SPARC/Solaris 2.6/7,getrusage(3C)并无多大意义。

A: Robert Owen Thomas <robt@cymru.com>

对于Solaris,可以利用procfs接口,下面的例子获取指定进程的内存占用情况

--------------------------------------------------------------------------
/*
* @(#)memlook.c 1.0 10 Nov 1997
* Robert Owen Thomas robt@cymru.com
* memlook.c -- A process memory utilization reporting tool.
*
* gcc -Wall -O3 -o memlook memlook.c
*/
#pragma ident "@(#)memlook.c 1.0 10 Nov 1997 Robert Owen Thomas robt@cymru.com"

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <sys/procfs.h>
#include <sys/param.h>
#include <unistd.h>
#include <fcntl.h>

int counter = 10;

int  showUsage ( const char * );
void getInfo   ( int, int );

int main ( int argc, char * argv[] )
{
   int  fd, pid, timeloop = 0;
   char pidpath[BUFSIZ];  /* /usr/include/stdio.h: #define BUFSIZ 1024 */

   switch ( argc )
   {
   case 2:
       break;
   case 3:
       timeloop = atoi( argv[2] );
       break;
   default:
       showUsage( argv[0] );
       break;
   }  /* end of switch */
   pid = atoi( argv[1] );
   sprintf( pidpath, "/proc/%-d", pid );  /* -表示向左靠 */
   /*
    * /proc/1/是目录,但在这种用法中,就是直接打开目录,不是打开文件
    */
   if ( ( fd = open( pidpath, O_RDONLY ) ) < 0 )
   {
       perror( pidpath );
       exit( 1 );
   }
   if ( 0 < timeloop )
   {
       for ( ; ; )
       {
           getInfo( fd, pid );
           sleep( timeloop );
       }
   }
   getInfo( fd, pid );
   close( fd );
   exit( 0 );
}  /* end of main */

int showUsage ( const char * progname )
{
   fprintf( stderr, "%s: usage: %s < PID > [time delay]\n", progname, progname
);
   exit( 3 );
}  /* end of showUsage */

void getInfo ( int fd, int pid )
{
   prpsinfo_t prp;
   prstatus_t prs;

   if ( ioctl( fd, PIOCPSINFO, &prp ) < 0 )
   {
       perror( "ioctl" );
       exit( 5 );
   }
   if ( ioctl( fd, PIOCSTATUS, &prs ) < 0 )
   {
       perror( "ioctl" );
       exit( 7 );
   }
   if ( counter > 9 )
   {
       fprintf( stdout, "PID\tIMAGE\t\tRSS\t\tHEAP\t\tSTACK\n" );
       counter = 0;
   }
   fprintf( stdout, "%u\t%-9u\t%-9u\t%-15u\t%-15u\n", pid,
            ( unsigned int )prp.pr_bysize, ( unsigned int )prp.pr_byrssize,
            ( unsigned int )prs.pr_brksize, ( unsigned int )prs.pr_stksize );
   counter++;
}  /* end of getInfo */
--------------------------------------------------------------------------

4.2 Solaris下如何获知CPU速率

A: Philip Brown <phil+s3@bolthole.no-bots.com>

  psrinfo -v

  psrinfo | grep on-line | wc -l 简单给出CPU数目

A: scz <scz@nsfocus.com>

# /usr/platform/`uname -i`/sbin/prtdiag -v
# /usr/platform/`uname -m`/sbin/prtdiag -v
# /usr/bin/netstat -k cpu_info0

A: Tony Walton <tony.walton@uk.sun.com>

如果你装了Sun Workshop,还可以尝试fpversion命令

# /opt/SUNWspro/bin/fpversion
A SPARC-based CPU is available.
CPU's clock rate appears to be approximately 266.1 MHz.
Kernel says CPU's clock rate is 270.0 MHz.
Kernel says main memory's clock rate is 90.0 MHz.

Sun-4 floating-point controller version 0 found.
An UltraSPARC chip is available.
FPU's frequency appears to be approximately 277.1 MHz.

Use "-xtarget=ultra2i -xcache=16/32/1:256/64/1" code-generation option.

Hostid = 0x80BC3CB3.
#

4.3 如何编程获取Solaris系统当前内存大小

Q: 如何编程(或者有什么现成命令)获取Solaris系统当前内存大小?

A: Nithyanandham <m.nithyanandham@blr.spcnl.co.in>

几个现成命令

/usr/platform/`uname -m`/sbin/prtdiag -v | grep Memory

prtconf -v | grep Memory

如果装了GNU top,也可以直接用top命令看到。

D: scz <scz@nsfocus.com>

truss prtconf的输出中有如下内容

sysconfig(_CONFIG_PAGESIZE)                     = 8192
sysconfig(_CONFIG_PHYS_PAGES)                   = 16384
Memory size: 128 Megabytes

# /usr/ccs/bin/nm -nx /dev/ksyms | grep "|sysconfig$"
10626] |0x0000100ec110|0x0000000001bc|FUNC |GLOB |0    |ABS    |sysconfig
# find /usr/include -type f -name "*.h" | xargs grep -l _CONFIG_PAGESIZE
/usr/include/sys/sysconfig.h
# vi -R /usr/include/sys/sysconfig.h

/*
* cmd values for _sysconfig system call.
* WARNING: This is an undocumented system call,
* therefore future compatibility can not
* guaranteed.
*/

#define _CONFIG_PAGESIZE   6  /* system page size */
#define _CONFIG_PHYS_PAGES 26 /* phys mem installed in pages */

参看sysconf(3C)手册页。

_SC_PAGESIZE
_SC_PAGE_SIZE
_SC_PHYS_PAGES

A: Casper Dik <Casper.Dik@Holland.Sun.COM>

--------------------------------------------------------------------------
/*
* Program to determine the size installed physical memory on Suns.
*
* Casper Dik.
*/

#define MEGABYTE 0x00100000
#define MAXMEM   0x7ff00000
#define THEMEM   "/dev/mem"

#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

int main ( int argc, char * argv[] )
{
   int           fd = open( THEMEM, O_RDONLY );
   char          c;
   unsigned long pos, mapstart = 0;
   int           totmb = 0;

   if ( fd == -1 )
   {
       perror( THEMEM );
       exit( 1 );
   }
   for ( pos = 0; pos < MAXMEM; pos += MEGABYTE )
   {
       if (lseek( fd, pos, 0 ) == -1 )
       {
           perror( "lseek" );
           exit( 1 );
       }
       if ( read( fd, &c, 1 ) == -1 )
       {
           int size = ( pos - mapstart ) / MEGABYTE;

           if ( size != 0 )
           {
               printf( "found %3d MB starting at 0x%p\n", size, ( void * )mapst
art );
               totmb += size;
           }
           mapstart = pos + MEGABYTE;  /* start of next possible mapping */
       }
   }
   printf( "Total memory size: %d MB\n", totmb );
   exit( 0 );
}
--------------------------------------------------------------------------

由于需要读访问/dev/mem,普通用户用户无法使用该程序。

5. 块设备相关问题

5.1 CDROM设备究竟在哪里

Q: 为了mount光驱,需要哪些包

A: SUNWvolr SUNWcstl SUNWcstlx

D: Dennis Clarke <dclarke@blastwave.com>

1) su - root
2) /etc/init.d/volmgt stop
3) ls -1 /dev/dsk/c*s2
4) mount -F hsfs -o ro /dev/dsk/c0t6d0s2 /cdrom

或者

1) /etc/init.d/volmgt stop
2) /etc/init.d/volmgt start
3) volcheck
4) eject

观察/etc/vold.conf

Q: 如何才能知道哪个设备文件对应CDROM(c0t2d0s0?)。如果有一张光盘在CDROM里,
  可以用df命令看到对应的设备文件,但是没有光盘在光驱里的时候呢?

A: /dev/sr0 是一个指向最终设备文件的符号链接,仅对SPARC有效,不包括x86

A: Logan Shaw <logan@cs.utexas.edu>

  $ uname -sri
  SunOS 5.8 i86pc
  $ ls -l /dev/sr*
  lrwxrwxrwx /dev/sr0 -> dsk/c1t0d0s2
  $

  我想x86下是一样的

Q: E420R,Solaris 7 11/99,我从http://sunsolve.sun.com获得一些补丁并安装了,
  结果现在我的光驱出问题了。似乎mount成功了,但是找不到文件,/etc/mnttab
  中没有任何有关光驱的信息,插入一张光盘会弹出一个文件管理器窗口,但是没
  有文件。

A: Danny Mann <dma@wwa.com>

  检查是否打了如下Solaris 7内核补丁106541-13和 -14。这两个补丁有问题。解
  决办法是禁止vold,手工mount光驱。

A: rschicht@my-deja.com <rschicht@my-deja.com>

  试试volrmmount -d命令。用patchadd -p检查是否安装了补丁106541-14,访问如
  下链接

  http://sunsolve.Sun.COM/pub-cgi/show.pl?target=patches/patch-access

  获取补丁106541-14的说明,阅读NOTE 15。

A: 补丁106541-14的说明,NOTE 15

  1. 首先禁止掉vold守护进程
     # /etc/init.d/volmgt stop

  2. 手工mount光驱(设备文件名可能不同)
     # /etc/mount -F hsfs -o ro /dev/dsk/c0t2d0s0 /cdrom

  查看/etc/vfstab、/dev/dsk确认光驱所在设备文件名。

5.2 如何弹出光驱

Q: 在安装Oracle 8i时,系统提示插入第二张光盘,但是此时无法成功eject第一张
  光盘,终端挂起,杀掉Oracle 8i的安装进程也无济于事。唯一的办法是reset。

A: Sergey Kurganov <mmerfi@home.com>

下面的操作或许有所帮助

1) 终止卷管理器
  # /etc/init.d/volmgt stop

2) unmount光驱,手动eject

3) 重启卷管理器
  # /etc/init.d/volmgt start

D: plane@smth.org 2002-02-26 01:03

装Oracle 9的时候,安装文档特意提醒要用绝对路径才能换盘。

5.3 如何利用超级块进行恢复工作

Q: Sun工作站在reboot时掉电了,用安装光盘启动进入单用户模式,执行fsck命令时
  报错

  Stop-A
  ok boot cdrom -s

  INIT: SINGLE USER MODE
  # fsck -o b=32 /dev/rdsk/c0t5d0s*
  Alternate super block location: 32.
  ** /dev/rdsk/c0t5d0s0
  BAD SUPER BLOCK: MAGIC NUMBER WRONG
  USE AN ALTERNATE SUPER-BLOCK TO SUPPLY NEEDED INFORMATION;
  eg. fsck [-F ufs] -o b=# [special ...]
  where # is the alternate super block. SEE fsck_ufs(1M).
  Alternate super block location: 32.
  ** /dev/rdsk/c0t5d0s1
  BAD SUPER BLOCK: MAGIC NUMBER WRONG
  USE AN ALTERNATE SUPER-BLOCK TO SUPPLY NEEDED INFORMATION;
  eg. fsck [-F ufs] -o b=# [special ...]
  where # is the alternate super block. SEE fsck_ufs(1M).
  Alternate super block location: 32.
  ** /dev/rdsk/c0t5d0s2
  BAD SUPER BLOCK: MAGIC NUMBER WRONG
  USE AN ALTERNATE SUPER-BLOCK TO SUPPLY NEEDED INFORMATION;
  eg. fsck [-F ufs] -o b=# [special ...]
  where # is the alternate super block. SEE fsck_ufs(1M).
  Alternate super block location: 32.

A: Sree Mokkapati <sree@broadcom.com>

  正确的用法就在错误提示信息里,你应该使用另外的超级块进行恢复工作,32仅
  仅是常用备份超级块之一。

  fsck -F ufs -o b=32 device_name

  此外如果想知道还有哪些备份超级块可用,执行

  newfs -Nv device_name

  先用df等命令确认原始device_name。

D: scz <scz@nsfocus.com> 2001-10-12 17:01 修订

  SPARC/Solaris的硬盘损坏多半是文件系统根区被破坏,并不需要拆卸硬盘到其他
  机器上mount后fsck,找一张Solaris安装光盘

  Stop-A进入OBP状态,在ok提示符下输入

  ok> boot cdrom -s

  进入单用户模式。此时原有根文件系统并未mount上来,也不需要mount原有根文
  件系统,直接

  newfs -Nv /dev/rdsk/c0t0d0s0

  找出原根文件系统所有备份超级块号

  fsck -y -F ufs -o b=<任一备份超级块号> /dev/rdsk/c0t0d0s0

  这里假设原根文件系统的原始设备名是/dev/rdsk/c0t0d0s0。其他文件系统的原
  始设备名可以在系统完好时 df -k 获取,或者从/etc/vfstab中获取信息。比如

  /dev/rdsk/c0t0d0s0    /
  /dev/rdsk/c0t0d0s6    /usr
  /dev/rdsk/c0t0d0s7    /export/home

  vfstab(4)解释得很模糊,回头我上www.google.com去找找其他资料。

  The fsck pass value of 2 means that the file system will be checked,
  but not sequentially

5.4 Solaris Root口令忘记了

Q: 忘记了root口令,怎么办

A: Steve Menard <opsmaster@yahoo.com>

  启动时按Stop-A进入ok提示符
  ok boot cdrom -s (放入启动安装光盘)
  mount /dev/dsk/c0t0d0s0 /mnt (这里指定原根区对应的原始设备名)
  TERM=vt100;export TERM
  vi /mnt/etc/shadow
  删除root口令加密串,比如
  root:WxzL460hohWsU:10724::::::
  删除WxzL460hohWsU,确认你还有8个冒号,重启动

  或者 /usr/sbin/reboot -- "cdrom -s"

A: Philip Brown <phil+s3@bolthole.no-bots.com>

  使用vi有很多麻烦的地方,可以考虑sed
  mount /dev/dsk/c0t0d0s0 /mnt
  sed 's/:WxzL460hohWsU:/::/' /mnt/etc/shadow > s
  mv s /mnt/etc/shadow

  或者使用ed
  mount /dev/dsk/c0t0d0s0 /mnt
  ed /mnt/etc/shadow
  1s/root:[^:]*:/root::/ (注意,前面是1,不是l)
  w
  q

5.5 如何使用fmthard

A: Seán Boran <sean@boran.com>

如果希望对第二块物理硬盘的分区与第一块物理硬盘一样,考虑fmthard和prtvtoc的
结合使用,要比手工format快得多。比如,第一块物理硬盘是target 3,第二块物理
硬盘是target 1,我们希望第二块物理硬盘磁盘卷标是"mirror",做如下操作:

/usr/sbin/prtvtoc /dev/rdsk/c0t3d0s2 | /usr/sbin/fmthard -n mirror -s - /dev/rds
k/c0t1d0s2

man -s 1M fmthard了解更多细节。

5.6 如何从光盘恢复Solaris 7的引导扇区

A: paranoid@bbs.tsinghua.edu.cn

  在安装盘里有一个tools目录,进去后有一个命令叫做installboot

A: melonm@bbs.tsinghua.edu.cn

  比如
  installboot /usr/platform/`uname -i`/lib/fs/ufs/bootblk /dev/rdsk/c0t1d0s0

5.7 Solaris支持类似微软autorun.inf文件的功能吗

Q: 我自己制作了一张光盘,同时用于Solaris和Windows。在Windows环境下,可以利
  用autorun功能,当插入光盘的时候自动调用喜爱的浏览器打开一个文件。不知道
  Solaris 7/8下是否存在类似功能。

A: hakteng

是的,从Solaris 8(CDE version 1.4)开始支持类似功能了

o  创建一个名为"volstart"的脚本文件,比如

--------------------------------------------------------------------------
#! /bin/ksh
#
# This is a CD volume start script.  This start script is designed
# to be automatically run when the CD is inserted into a Solaris
# system's CDrom drive.
#
# Note: not all Solaris systems have an auto volstart ability.  If this
# CD is inserted into a CDrom drive of a Solaris system without the
# volstart ability, volstart can also be run manually by executing it
# from either the desktop's file manager or from a Unix command line.
full_name=$0
dir_name=`/usr/bin/dirname $full_name`
if [[ -x /usr/dt/bin/dtaction ]]; then
  # Run the CDrom's installer program
  /usr/dt/bin/dtaction Run $dir_name/installer
fi
--------------------------------------------------------------------------

o  将"volstart"文件放在光盘根目录下

o  /usr/dt/bin/sdtvolcheck脚本中存在如下语句
  if [[ -x $mountPt/volstart ]];then exec $mountPt/volstart;
  于是,当插入光盘的时候volstart脚本被执行,对于上例,最终导致installer被
  执行

5.8 如何修改/dev/null的属性

Q: /devices/pseudo/mm@0:null的属性是0620 root tty,我想
  chmod 666 /devices/pseudo/mm@0:null ,但是几分钟后,属性被修改回
  0620 root tty,怎么办

A: Markus Mayer <mmayer@iname.com>

查看/etc/minor_perm文件,

# grep -s null /etc/minor_perm
mm:null 0620 root tty

修改该文件中的这一行成"mm:null 0666 root sys"即可。

5.10 如何自己制作Solaris启动软盘

Q: 我知道可以去
  http://soldc.sun.com/support/drivers/dca_diskettes/
  下载启动软盘的映象文件,可我还想知道它最初是如何制作出来的

A: 小四 <cloudsky@263.net>

1) 用fdformt格式化软盘

2) 用newfs在软盘上创建新的文件系统

3) 将软盘mount上来

4) 用cp命令复制the second-level disk booter(boot或者ufsboot)到软盘,比如
  /platform/sun4u/ufsboot。参看installboot(1M)、boot(1M)手册页

5) 用installboot命令安装boot block到软盘,比如
  installboot /usr/platform/`uname -i`/lib/fs/ufs/bootblk /dev/rdsk/c1t0d0s0

6) 用cp命令复制必要的工具文件到软盘

7) unmount软盘

8) 用eject命令弹出软盘

5.11 x86/Solaris如何访问FAT32分区

A: Dan Anderson <dan@drydog.com>

mount -F pcfs /dev/dsk/c0t0d0p0:1 /mnt/<...> # SCSI
mount -F pcfs /dev/dsk/c0d0p0:1   /mnt/<...> # ATAPI

c0 控制器ID
t0 SCSI ID (对于ATAPI省略)
d0 对于SCSI总是0,对于ATAPI是硬盘
p0 p0对应第一个主分区表项
:1 对应逻辑驱动器(c - z 或 1 - 24)

有些报告说如果FAT32分区不对应第一个主分区表项,mount失败,感觉x86/Solaris
对pcfs支持混乱。

A: spp(低音炮)

在SPARC/Solaris 7上df -k

# df -k
/dev/dsk/c0t0d0s0 /
/dev/dsk/c0t0d0s6 /usr
/dev/dsk/c0t0d0s7 /export/home

在x86/Solaris 8上df -k

# df -k
/dev/dsk/c0d0s0 /
/dev/dsk/c0d0s7 /export/home

c 硬盘控制器的位置,比如主板第二个IDE接口上的第一个硬盘(主盘)对应c1d0
t 只SPARC有,SCSI ID
d 某一确定硬盘控制器(c参数决定)上硬盘位置
p 只x86有,对应MS系统的Partition概念
s slice号,Solaris系统的概念,不太好解释,如果和p一起出现,可以理解成类似
 MS逻辑驱动器的概念

假设x86架构上某硬盘在主引导扇区有两个主分区表项,第一个为FAT32分区,第二个
为Solaris分区,Solaris分区上划分了两个slice,一个为根文件系统/、一个为swap
区,则分别表示为/dev/dsk/c1d0p0:1(FAT32)、/dev/dsk/c1d0p1s0(/)、
/dev/dsk/c1d0p1s1(swap)

在mount FAT32分区时应该用

mount -F pcfs /dev/dsk/c1d0p0:1 /mnt/<mount_point>

D: 小四 <scz@nsfocus.com>

注意,Solaris的slice概念和FreeBSD的slice概念不同,FreeBSD的slice概念就是MS
的partition概念,而Solaris的slice概念类似于MS扩展分区上的逻辑驱动器概念。

6. /etc/system可调资源限制

6.1 Solaris下如何限制每个用户可拥有的最大进程数

A: Casper Dik <Casper.Dik@Holland.Sun.Com>

  在/etc/system设置
  set maxuprc = <num>

Q: maxusers参数究竟影响了什么

A: Casper Dik <Casper.Dik@Holland.Sun.Com>

  下面以/etc/system语法格式举例说明:

  *
  set maxusers = <以MB为单位计的可用物理内存数量>

  * 系统所允许的最大进程数,通常最多30000
  set max_nprocs = 10 + 16 * maxusers

  * 每个用户可以拥有的最大进程数(为超级用户保留5个)
  set maxuprc = max_nprocs - 5;

  # sysdef | sed -n '/System Configuration/,$p'

6.2 如何配置系统使之支持更多的伪终端

A: Argoth

不要试图通过'/usr/bin/adb -k'到达目的。

a. 如果Solaris版本小于7,修改/etc/system,增加如下行

  set pt_cnt=<num>

  执行/usr/sbin/reboot -- -r,或者Stop-A,执行boot -r

b. 对于Solaris 8,支持的伪终端数目根据需要动态改变,系统依然有一个内部限制,
  但是这个值非常大。如果"pt_cnt"变量小于这个内部限制,将被忽略。一般情况
  下,不再需要指定"pt_cnt"变量。但还是有某些罕见的情形,需要设置"pt_cnt"
  变量大于内部限制。

6.3 如何增加每个进程可打开文件句柄数

A: Casper Dik <Casper.Dik@Holland.Sun.COM>

从Solaris 2.4开始,可以通过修改/etc/system实现

   * set hard limit on file descriptors
   set rlim_fd_max = 4096
   * set soft limit on file descriptors
   set rlim_fd_cur = 1024

软限制超过256时,某些应用程序会出问题,尤其BCP程序。软限制超过1024时,那些
使用select()的应用程序可能会出问题。Solaris 7之前,select()使用的文件句柄
数不能超过1024。Solaris 2.6的RPC代码被重写过了,使用poll()代替select(),可
以使用超过1024的文件句柄。Solaris 2.6之前,如果软限制超过1024,所有RPC服务
很可能崩溃。

Solaris 7下select()可以使用最多达65536的文件句柄,64-bit应用程序缺省情况如
此。如果是32-bit应用程序,需要指定给FD_SETSIZE一个更大的值,重新编译。

如果程序使用标准输入/输出(stdio),或者调用那些使用stdio的库函数,当打开的
文件超过256时,程序可能会出问题,这个限制是stdio的限制。当程序需要大量文件
句柄时,应该想办法保留一些小数字的文件句柄,让stdio使用它们。

Solaris 7下64-bit应用程序不再受这个stdio限制的影响。如果你的确需要超过256
个FILE *,而又不能使用Solaris 7,或者需要运行32-bit代码,考虑使用来自AT&T
的SFIO(http://www.research.att.com/sw/tools/sfio/)。

A: qaz@smth.org

检查当前设置

# ulimit -H -n
1024
# ulimit -S -n
64
#

对于Solaris,建议修改/etc/system后重启

* set hard limit on file descriptors
set rlim_fd_max=0x8000
* set soft limit on file descriptors
set rlim_fd_cur=0x8000

然后 ulimit -S -n 8192

对于Linux

echo 65536 > /proc/sys/fs/file-max

然后 ulimit -S -n 8192

对于FreeBSD

编辑/etc/sysctl.conf文件(或者sysctl -w,参看SYSCTL.CONF(5))
kern.maxfiles=65536
kern.maxfilesperproc=32768

Q: Linux下如何加大系统可以打开的文件数

A: planck.bbs@bbs.nju.edu.cn

echo <num> > /proc/sys/fs/file-max

6.5 做了setuid()这类调用的程序如何产生core dump

Q: 做了setuid()这类调用的程序不会产生core文件,可我需要调试这个程序。

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

int main ( int argc, char * argv[] )
{
   int *ptr = NULL;

   printf( "Current uid = %d euid = %d\n", ( int )getuid(), ( int )geteuid() );
   printf( "Result of seteuid( 500 ) = %d\n", seteuid( 500 ) );
   printf( "Current uid = %d euid = %d\n", ( int )getuid(), ( int )geteuid() );
   creat( "/tmp/scz_blah", S_IRWXU );
   printf( "Result of setuid( 0 ) = %d\n", setuid( 0 ) );
   printf( "Current uid = %d euid = %d\n", ( int )getuid(), ( int )geteuid() );
   *ptr = 0;
   return( EXIT_SUCCESS );
}  /* end of main */
--------------------------------------------------------------------------

# gcc -Wall -O3 -o suidtest suidtest.c
# strip suidtest
# file suidtest
suidtest:       ELF 32-位 MSB 可执行 SPARC 版本 1,动态链接,除去
# ls -l suidtest
-rwxr-xr-x   1 root     other       4988  6月 29 21:21 suidtest*
# ./suidtest
Current uid = 0 euid = 0
Result of seteuid( 500 ) = 0
Current uid = 0 euid = 500
Result of setuid( 0 ) = 0
Current uid = 0 euid = 0
段错误
# ls -l core
core: 无此文件或目录
#

这个程序应该core dump,但是现在没有core文件产生。注意,此时suidtest仅仅是
自己调用了setuid(),并非被"chmod u+s suidtest"过。有无/etc/system内核可配
置参数改变这种行为。

A: Sun Microsystems 2001-04-11

出于安全考虑,suid程序以及调用setuid()的程序缺省情况下不产生core dump。如
果确实需要产生core dump以便进行调试,修改/etc/system文件并重启系统

* 缺省该值为0,此时禁止suid程序以及调用setuid()的程序core dump
set allow_setid_core = 1

对于Solaris 2.6,需要先打补丁105181-22或更高版本,才能使用上述技术。对于
7及其更高版本的Solaris操作系统,不需要任何补丁。

A: 小四 <scz@nsfocus.com> 2001-07-30 20:14

对于SPARC/Solaris 7来说,为了方便调试,执行coreadm -e proc-setid命令即可。

6.6 消息队列调整

Q: 在/etc/system中如何调整消息队列

A: <solaris@sean.de>

消息队列统一使用 msgsys:msginfo_ 前缀。你可以用sysdef获取一些缺省值,还可
以参看/usr/include/sys/msg.h头文件了解更多信息。此外不要忘记<<APUE>>

msgsys:msginfo_msgmap

   default 100 max 2147483647 <sys/msg.h> 100

msgsys:msginfo_msgmax

   default 2048 max 2147483647 <sys/msg.h> 8192 typical value 2048

msgsys:msginfo_msgmnb

   default 4096 max 2147483647 <sys/msg.h> 2048 typical value 4096

msgsys:msginfo_msgmni

   default 50 max 2147483647 <sys/msg.h> 50 typical value 50

msgsys:msginfo_msgssz

   default 8 max 2147483647 <sys/msg.h> 8

msgsys:msginfo_msgtql

   default 40 max 2147483647 <sys/msg.h> 50 typical value 40

msgsys:msginfo_msgseg

   default 1024 max 32767 <sys/msg.h> 1024

7. DNS相关问题

7.1 如何进行DNS区传输

A: scz <scz@nsfocus.com>

  用nslookup是最普遍适用的
  nslookup
  > server ns.tsinghua.edu.cn
  > set type=axfr
  > ls tsinghua.edu.cn [> tsinghua.txt] (方括号里的可选)

  有些系统提供了dig命令
  dig @ns.tsinghua.edu.cn axfr tsinghua.edu.cn

A: lgwu

  有些系统提供了host命令,这个命令不太保险
  host -l net.tsinghua.edu.cn (后面指定域)
  host -l ncic.ac.cn

7.2 如何获知权威名字服务器

A: scz <scz@nsfocus.com>

  nslookup
  > set query=ns
  > ncic.ac.cn (获知管辖该域的权威名字服务器)
  Authoritative answers can be found from:
  gatekeeper.ncic.ac.cn   internet address = 159.226.41.188
  > server gatekeeper.ncic.ac.cn
  > set type=axfr (准备区传输)
  > ls ncic.ac.cn > ncic.txt

7.3 如何配置DNS的委托解析

Q: 我想把子域DNS解析下放到下面去,在我这里如何配置

A: zhangql@bbs.tsinghua.edu.cn

子域  IN  NS  <负责子域DNS解析的IP>

7.4 如何获知BIND的版本号

Q: 如何识别当前运行的bind是什么版本

A: M. Zuber <helmlein@hotmail.com>

  dig @<victim_ip> txt chaos version.bind

  或者

  nslookup
  server <victim_ip>
  set query=txt
  set class=chaos
  version.bind

  但是这个返回结果可以通过/etc/named.conf自己设置,并不可靠。如果你正在运
  行BIND 8,可以执行

  /usr/sbin/ndc status

A: backend <backend@nsfocus.com>

#!/bin/sh
# bv (Bind Version) script
# written by backend@nsfocus.com

USAGE="Usage: $0 <address>"

if [ $# -ne 1 ]; then
       echo $USAGE
       exit
fi

if [ ! -f /usr/bin/dig ]; then
       echo -en "\\033[1;31mCan't find \"dig\" program.\\033[0;39m\n\n"
       exit
fi

VER=`/usr/bin/dig @$1 version.bind chaos txt | grep "VERSION.BIND"`

if [ "x$VER" = "x" ]; then
       echo -en "\\033[1;31mSorry. Can't get BIND version.\\033[0;39m\n\n"
else
       echo -en "BIND version of \\033[1;33m$1\\033[0;39m = "
       echo -en "\\033[1;33m"
       echo $VER | awk '{print $5;}'

       echo -en "\\033[0;39m\n"
fi

A: deepin <deepin@nsfocus.com>

很多主机没有dig,最方便的办法是
nslookup -q=txt -class=chaos version.bind IP-addr
如果要美观一点,所以可以用这样的一个小脚本

#!/bin/sh
if [ $# = 0 ];then echo "useage: $0 IP-Addr."; exit 1;fi
VER=`nslookup -q=txt -class=chaos version.bind $1 | grep "VERSION.BIND"`
if [ $? = 0 ];then
       echo -en "BIND version of \\033[1;33m$1\\033[0;39m = " `echo $VER | awk
'{print $4,$5,$6;}'` "\\033[0;39m\n"
else
       echo -en "\\033[1;31mSorry. Can't get BIND version.\\033[0;39m\n\n"
fi

命令行上直接指定IP,会进行反向域名解析,有可能失败,进入nslookup之后server
指定IP,则无此问题。

7.5 Solaris/FreeBSD/Linux如何指定域名解析的顺序

Q: 如何在Solaris中使/etc/resolv.conf的设置生效

A: cp /etc/nsswitch.dns /etc/nsswitch.conf
  或者
  vi /etc/nsswitch.conf

  hosts: files dns

Q: FreeBSD中有类似Solaris的/etc/nsswitch.conf的文件吗

A: /etc/host.conf

--------------------------------------------------------------------------
# First try the /etc/hosts file
hosts
# Now try the nameserver next.
# 如果不希望做反向域名解析,则注释掉下面这行
# bind
# If you have YP/NIS configured, uncomment the next line
# nis
--------------------------------------------------------------------------

Q: Linux中有类似Solaris的/etc/nsswitch.conf的文件吗

D: /etc/host.conf

--------------------------------------------------------------------------
order hosts, bind, nis
multi on
--------------------------------------------------------------------------

D: rai@SMTH Unix 2001-11-28 09:42

改了/etc/host.conf还是不行,后来试了一下/etc/nsswitch.conf就可以了,Linux
也有这个文件的,必须保证下一行中有dns

--------------------------------------------------------------------------
# hosts:     db files nisplus nis dns
hosts:      files nisplus nis dns
--------------------------------------------------------------------------

8. Solaris内核编程相关问题

8.1 Solaris内核模块中如何getcwd

Q: 在Solaris 7 64-bit内核模块中如何获知一个进程的当前工作目录(cwd),getcwd
  并不是一个系统调用


文章评论

共有 0 位网友发表了评论 此处只显示部分留言 点击查看完整评论页面

300x250广告位招租