?? unix faq
字號:
發(fā)信人: wshu (樹上的老虎), 信區(qū): Unix
標(biāo) 題: UNIX FAQ 中文版(四)
發(fā)信站: BBS 水木清華站 (Mon May 19 10:12:11 1997)
本篇文章回答以下問題:
4.1) 要如何在使用者不必按 RETURN 的情況下從 terminal 讀進東西?
4.2) 我要如何在未曾真的讀進東西的情況下檢查是否有字元等待讀取?
4.3) 要怎樣才能得知一個已open 檔案之檔名?
4.4) 一個執(zhí)行中的程式如何知道自己的 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 的連接已經(jīng)斷掉之后再接回來,例如
在 background 跑一個程式然后就 logout 而斷掉的程式?
4.11) 有沒有辦法可以偷聽一個 terminal,就是說將其輸出復(fù)制一份至其他的
terminal。
4.1) 要如何在使用者不必按 RETURN 的情況下從 terminal 讀進東西?
在 BSD 中用 cbreak 模式,在 SysV 中則用 ~ICANON 模式。
如果你懶得用 "ioctl(2)" 來設(shè)定 terminal 的參數(shù),也可以用 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);
}
有好幾個人送給我更正確的解法。不過很抱歉我不想把它們加進去,因為這已經(jīng)
超出這份文件的范圍了。
通常對這個問題有興趣的人,都是想要做一些控制螢?zāi)伙@示之類的事情。如果你
也是的話,那請參考 "curses" 的相關(guān)文件。 "curses" 是一個 portable 的螢
幕控制函數(shù)庫。
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 的資料結(jié)構(gòu),看看是否 input buffer 是空的,但是這方法有時會失
效,因為你沒有辦法知道當(dāng)你下一次要填滿這個 buffer 時會發(fā)生什么事。)
有時人們問這個問題是因為想寫
if (characters available from fd)
read(fd, buf, sizeof buf);
以達(dá)成 nonblocking read。這不是一種好的做法,因為可能測的時候有東西,
要讀的時候,已經(jīng)沒有東西可讀了。正確的做法應(yīng)該是用 fcntl(2) 里的
F_SETFL 設(shè)定 O_NDELAY。比較舊的系統(tǒng)(Version 7, 4.1 BSD) 沒有
O_NDELAY,那就得用 alarm(2) 來設(shè)定 read 的 timeout,以達(dá)成近似
nonblocking read 的功能。
4.3) 要怎樣才能得知一個已 open 檔案之檔名?
這個是非常困難的。若是這個 file descriptor 是對應(yīng)到 pipe 或 pty 就沒
有名字了。這個 file descriptor 對應(yīng)的檔案也有可能已被刪除。若是有
symbolic link 或 hard link,則可能有許多個名字。
如果你經(jīng)過一再考慮后別無選擇一定要這么做的話,可以用 find 的 -inum 與
-xdev 選項,或用 ncheck,或用自己寫類似的程式來做。在這么做時要耐心的
等,因為在一個幾百 megabyte 甚至幾 gigabyte 的 file system中找一個檔
案,一定得花不少時間。
4.4) 一個執(zhí)行中的程式如何知道自己的 pathname?
若果 argv[0] 是以 "/" 開始的字,它可能就是你的程式所在地的絕對路徑。
如果不是那就得照順序檢查 PATH 里的每一個目錄看看里面是否有與 argv[0]
一樣的程式。如果找得到的話將那個目錄與程式名稱兜起來可能就是你要的
pathname 了。
不過上述方法找到的并不一定是正確的,因為在程式中用到 exec() 時,
argv[0] 是可以隨便給的。將 argv[0] 設(shè)為與要執(zhí)行的程式名稱相同只是一
種慣用法罷了!
以下的例子可能會使你更清楚些:
#include <stdio.h>
main()
{
execl("/usr/games/rogue", "vi Thesis", (char *)NULL);
}
這個被執(zhí)行的程式就會認(rèn)為它的名字(argv[0] 之值)是 "vi Thesis")。
4.5) 如何用 popen() 對一個 process 做讀寫的動作?
用 pipe 將一個 process 的輸出、輸入轉(zhuǎn)給任意的 process 所可能會發(fā)生的
問題就是 deadlock,譬如這兩個 processes 剛好同時都在等待「尚未產(chǎn)生」
的輸入時。唯一能避免 deadlock 的方法就是在 pipe 的兩端都要遵循嚴(yán)格的
deadlock-free 協(xié)定,但是需要這些 processes 之間的互相合作才能達(dá)成,
而對于像 popen() 這類的函數(shù)來說并不太適合。
在 'expect' 這個軟體中附有一個能夠讓 C 程式直接引用的函式庫。其中有
一個函式不管是在讀或?qū)懚寄苓_(dá)到和 popen 相同的功能。但是這個函式使
?
用 ptys 而不是 pipes,也沒有 deadlock 的問題,并且在 BSD 或 SV 中都
能使用。若想對 'expect' 有進一步的了解,可參考下一個問題的解答。
4.6) 在 C 程式中要怎么用 sleep() 才能夠 sleep 小于一秒?
首先要注意的是,你只能指定 delay 的「最短」時間;實際上會 delay 多久和
系統(tǒng)的 scheduling 方式有關(guān),例如系統(tǒng)當(dāng)時有負(fù)載。如果你倒楣的話,它還可
能會 delay 蠻長的時間。
并沒有一個標(biāo)準(zhǔn)函式能夠在「小睡」(很短的 sleep)期間提供你計數(shù)的功能。
某些系統(tǒng)有提供 usleep(n) 的函式,它能夠暫停執(zhí)行 n 微秒(microsecond)
的時間。如果你所使用的系統(tǒng)沒有提供 usleep() 函式,那么以下有可在 BSD,
System V 使用中的作法。
接下來的這段程式碼是 Doug Gwyn 在 System V 中模擬 4BSD 并利用 4BSD
中的 select() 系統(tǒng)呼叫。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 */
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -