⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unix faq

📁 UNIX FAQ 中文版
💻
📖 第 1 页 / 共 2 页
字号:
发信人: wshu (树上的老虎), 信区: Unix
标  题: UNIX FAQ 中文版(四)
发信站: BBS 水木清华站 (Mon May 19 10:12:11 1997)

本篇文章回答以下问题:

       4.1)  要如何在使用者不必按 RETURN 的情况下从 terminal 读进东西?
       4.2)  我要如何在未曾真的读进东西的情况下检查是否有字元等待读取?
       4.3)  要怎样才能得知一个已open 档案之档名?
       4.4)  一个执行中的程式如何知道自己的 pathname?
       4.5)  如何用 popen() 对一个 process 做读写的动作?
       4.6)  在 C 程式中要怎么用 sleep() 才能够 sleep 小于一秒?
       4.7)  如何让 setuid 的 shell script 可以使用?
       4.8)  我要如何得知有哪些 process 开了某一档案,或某一 process 正在使用哪
             一个 fileystem(以至于我无法 unmount 这个 filesystem)?
       4.9)  我要怎么知道是谁在 finger 我啊?
       4.10) 能不能在一个 process 和 terminal 的连接已经断掉之后再接回来,例如
             在 background 跑一个程式然后就 logout 而断掉的程式?
       4.11) 有没有办法可以偷听一个 terminal,就是说将其输出复制一份至其他的
             terminal。

 4.1)  要如何在使用者不必按 RETURN 的情况下从 terminal 读进东西?

         在 BSD 中用 cbreak 模式,在 SysV 中则用 ~ICANON 模式。

         如果你懒得用 "ioctl(2)" 来设定 terminal 的参数,也可以用 stty 来做,
         不过有点慢又没有效率就是了。底下的程式自己看著办吧:

               #include <stdio.h>
               main()
               {
                     int c;

                     printf("Hit any character to continue\n");
                     /*
                      * ioctl() would be better here; only lazy
                      * programmers do it this way:
                      */
                     system("/bin/stty cbreak");        /* or "stty raw" */
                     c = getchar();
                     system("/bin/stty -cbreak");
                     printf("Thank you for typing %c.\n", c);

                     exit(0);
               }

         有好几个人送给我更正确的解法。不过很抱歉我不想把它们加进去,因为这已经
         超出这份文件的范围了。

         通常对这个问题有兴趣的人,都是想要做一些控制萤幕显示之类的事情。如果你
         也是的话,那请参考 "curses" 的相关文件。 "curses" 是一个 portable 的萤
         幕控制函数库。


 4.2)  我要如何在未曾真的读进东西的情况下检查是否有字元等待读取?

         一些版本的 UNIX 提供了检查某个 file descriptor 目前是否有东西待读取的
         方法。在 BSD 中,可以用 "select(2),也可以用 FIONREAD ioctl,检查有几
         个字元等待读取,不过这只对 terminal, pipe, 与 socket 有用。在 System
         V Release 3 中可以用 poll(2),不过只对 stream 有用。在 Xenix 与 Sys V
         r3.2 及其以后的版本里,有一个名叫 rdchk() 的 system call 可以用来检查
         对一个 file descriptor 做 read() 会不会卡住。

         没有方法可以用来判断是否有字元在 FILE pointer 中待读取。(你可以直接查
         看 stdio 的资料结构,看看是否 input buffer 是空的,但是这方法有时会失
         效,因为你没有办法知道当你下一次要填满这个 buffer 时会发生什么事。)

         有时人们问这个问题是因为想写
                 if (characters available from fd)
                     read(fd, buf, sizeof buf);
         以达成 nonblocking read。这不是一种好的做法,因为可能测的时候有东西,
         要读的时候,已经没有东西可读了。正确的做法应该是用 fcntl(2) 里的
         F_SETFL 设定 O_NDELAY。比较旧的系统(Version 7, 4.1 BSD) 没有
         O_NDELAY,那就得用 alarm(2) 来设定 read 的 timeout,以达成近似
         nonblocking read 的功能。


 4.3)  要怎样才能得知一个已 open 档案之档名?

         这个是非常困难的。若是这个 file descriptor 是对应到 pipe 或 pty 就没
         有名字了。这个 file descriptor 对应的档案也有可能已被删除。若是有
         symbolic link 或 hard link,则可能有许多个名字。

         如果你经过一再考虑后别无选择一定要这么做的话,可以用 find 的 -inum 与
         -xdev 选项,或用 ncheck,或用自己写类似的程式来做。在这么做时要耐心的
         等,因为在一个几百 megabyte 甚至几 gigabyte 的 file system中找一个档
         案,一定得花不少时间。


 4.4)  一个执行中的程式如何知道自己的 pathname?

         若果 argv[0] 是以 "/" 开始的字,它可能就是你的程式所在地的绝对路径。
         如果不是那就得照顺序检查 PATH 里的每一个目录看看里面是否有与 argv[0]
         一样的程式。如果找得到的话将那个目录与程式名称兜起来可能就是你要的
         pathname 了。

         不过上述方法找到的并不一定是正确的,因为在程式中用到 exec() 时,
         argv[0] 是可以随便给的。将 argv[0] 设为与要执行的程式名称相同只是一
         种惯用法罢了!

         以下的例子可能会使你更清楚些:

                 #include <stdio.h>
                 main()
                 {
                     execl("/usr/games/rogue", "vi Thesis", (char *)NULL);
                 }

         这个被执行的程式就会认为它的名字(argv[0] 之值)是 "vi Thesis")。


 4.5)  如何用 popen() 对一个 process 做读写的动作?

         用 pipe 将一个 process 的输出、输入转给任意的 process 所可能会发生的
         问题就是 deadlock,譬如这两个 processes 刚好同时都在等待「尚未产生」
         的输入时。唯一能避免 deadlock 的方法就是在 pipe 的两端都要遵循严格的
         deadlock-free 协定,但是需要这些 processes 之间的互相合作才能达成,
         而对于像 popen() 这类的函数来说并不太适合。

         在 'expect' 这个软体中附有一个能够让 C 程式直接引用的函式库。其中有
         一个函式不管是在读或写都能达到和 popen 相同的功能。但是这个函式使
?
         用 ptys 而不是 pipes,也没有 deadlock 的问题,并且在 BSD 或 SV 中都
         能使用。若想对 'expect' 有进一步的了解,可参考下一个问题的解答。


 4.6)  在 C 程式中要怎么用 sleep() 才能够 sleep 小于一秒?

         首先要注意的是,你只能指定 delay 的「最短」时间;实际上会 delay 多久和
         系统的 scheduling 方式有关,例如系统当时有负载。如果你倒楣的话,它还可
         能会 delay 蛮长的时间。

         并没有一个标准函式能够在「小睡」(很短的 sleep)期间提供你计数的功能。
         某些系统有提供 usleep(n) 的函式,它能够暂停执行 n 微秒(microsecond)
         的时间。如果你所使用的系统没有提供 usleep() 函式,那么以下有可在 BSD,
         System V 使用中的作法。

         接下来的这段程式码是 Doug Gwyn 在 System V 中模拟 4BSD 并利用 4BSD
         中的 select() 系统呼叫。Doung 自己都叫它为 'nap()' ;你也可以把它叫做
         "usleep()";

         /*
             usleep -- support routine for 4.2BSD system call emulations
             last edit:  29-Oct-1984     D A Gwyn
         */

       extern int        select();

       int
       usleep( usec )                            /* returns 0 if ok, else -1 */
             long                usec;           /* delay in microseconds */
             {
             static struct                       /* `timeval' */
                     {
                     long        tv_sec;         /* seconds */
                     long        tv_usec;        /* microsecs */
                     }   delay;          /* _select() timeout */

             delay.tv_sec = usec / 1000000L;
             delay.tv_usec = usec % 1000000L;

             return select( 0, (long *)0, (long *)0, (long *)0, &delay );
             }

       On System V you might do it this way:

       /*
       subseconds sleeps for System V - or anything that has poll()
       Don Libes, 4/1/1991

       The BSD analog to this function is defined in terms of
       microseconds while poll() is defined in terms of milliseconds.
       For compatibility, this function provides accuracy "over the long
       run" by truncating actual requests to milliseconds and
       accumulating microseconds across calls with the idea that you are
       probably calling it in a tight loop, and that over the long run,
       the error will even out.

       If you aren't calling it in a tight loop, then you almost
       certainly aren't making microsecond-resolution requests anyway,
       in which case you don't care about microseconds.  And if you did,
       you wouldn't be using UNIX anyway because random system
       indigestion (i.e., scheduling) can make mincemeat out of any
       timing code.

       Returns 0 if successful timeout, -1 if unsuccessful.

       */

       #include <poll.h>

       int
       usleep(usec)
       unsigned int usec;                /* microseconds */
       {
             static subtotal = 0;        /* microseconds */
             int msec;                   /* milliseconds */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -