RETURN
?
Subject: How do I read characters ... without requiring the user to hit RETURN? Date: Thu Mar 18 17:16:55 EST 1993Preverite način
cbreak
v BSD ali način ~ICANON
v SysV.
Če se sami ne želite spoprijeti s terminalskimi parametri (z uporabo
sistemskega klica ioctl(2)
), lahko prepustite delo programu
stty
- a to je počasno in neučinkovito, in včasih boste morali
spremeniti kodo, da bo delala pravilno:
#include <stdio.h> main() { int c; printf("Pritisnite katerikoli znak za nadaljevanje\n"); /* * funkcija ioctl() bi bila tukaj boljša; * le leni programerji delajo takole: */ system("/bin/stty cbreak"); /* ali "stty raw" */ c = getchar(); system("/bin/stty -cbreak"); printf("Hvala, ker ste vnesli %c.\n", c); exit(0); }
Preveriti boste želeli tudi dokumentacijo prenosljive knjižnice
zaslonskih funkcij, imenovane ,,curses
``. Če vas zanima V/I
enega samega znaka, vas pogosto zanima tudi neka vrsta kontrole
prikaza na zaslonu, in knjižnica curses
priskrbi različne
prenosljive rutine za obe funkciji.
Subject: How do I check to see if there are characters to be read ... ? Date: Thu Mar 18 17:16:55 EST 1993
V nekaterih različicah Unixa je mogoče preveriti, ali je v danem
datotečnem deskriptorju kaj neprebranih znakov. V BSD-ju lahko
uporabite select(2)
. Uporabite lahko tudi FIONREAD
ioctl
, ki vrne število znakov, ki čakajo na prebranje, a to
deluje le pri terminalih, cevovodih in vtičih. V System V Release 3
lahko uporabite poll(2)
, a to deluje le na tokovih. V Xenixu
- in torej na Unixu SysV r3.2 in poznejših - sistemski klic
rdchk()
poroča o tem ali se bo klic read()
na danem
datotečnem deskriptorju blokiral.
Ni načina, da bi preverili, ali so znaki dostopni za branje s kazalca
FILE
. (Lahko gledate po notranjih podatkovnih strukturah stdio,
da bi videli, če je vmesni pomnilnik vhoda neprazen, a to ne bo
delovalo, saj ne veste, kaj se bo zgodilo naslednjič, ko boste hoteli
napolniti vmesni pomnilnik.)
Včasih ljudje vprašujejo to vprašanje z namenom, da bi napisali
if (znaki dostopni iz fd)
read(fd, buf, sizeof buf);
in dobili učinek neblokovnega branja z read
. To ni najboljši
način za izvedbo tega, saj je možno, da bodo znaki dostopni, ko
preverite dostopnost, a ne bodo več dostopni, ko pokličete read
.
Namesto tega prižgite zastavico O_NDELAY
(ki se pod BSD
imenuje tudi FNDELAY
) z izbiro F_SETFL
funkcije
fcntl(2)
. Starejši sistemi (Version 7, 4.1 BSD) nimajo
O_NDELAY
; na teh sistemih lahko najbližje neblokovnemu branju
pridete z uporabo alarm(2)
, da branju poteče čas.
Subject: How do I find the name of an open file? Date: Thu Mar 18 17:16:55 EST 1993V splošnem je to pretežko. Datotečni deskriptor je lahko obešen na cevovod ali pty, in v tem primeru nima imena. Lahko je obešen na datoteko, ki je bila odstranjena. Lahko ima več imen, zaradi pravih ali simboličnih povezav.
Če morate to res storiti, in prepričajte se, da ste o tem razmislili
na dolgo in široko in se odločili, da nimate druge izbire, lahko
uporabite find
z izbiro -inum
in morda še -xdev
, ali
uporabite ncheck
, ali še enkrat oponašajte funkcionalnost enega
od teh orodij v vašem programu. Zavedajte se, da preiskovanje 600
megabytnega datotečnega sistema za datoteko, ki je morda sploh ni,
traja nekaj časa.
Subject: How can an executing program determine its own pathname? Date: Thu Mar 18 17:16:55 EST 1993Vaš program lahko pogleda
argv[0]
; če se začenja z
,,/
``, je to verjetno ime absolutne poti do vašega programa,
sicer lahko vaš program pogleda v vsak imenik, imenovan v okoljski
spremenljivki PATH
in poskuša najti prvi imenik, ki vsebuje
izvedljivo datoteko, katere ime se ujema s programovim argv[0]
(ki je po dogovoru ime programa, ki se izvaja). Če združite ta imenik
in vrednost argv[0]
, imate verjetno pravo ime.
Ne morete pa biti prepričani, saj je povsem legalno, da en program
izvede drugega z exec()
s katerokoli vrednostjo argv[0]
,
ki si jo zaželi. Da exec
izvaja nove programe z imenom
izvedljive datoteke v argv[0]
, je le dogovor.
Na primer, povsem hipotetični primer:
#include <stdio.h>
main()
{
execl("/usr/games/rogue", "vi Disertacija", (char *)NULL);
}
Izvedeni program misli, da je njegovo ime (njegova vrednost
argv[0]
) ,,vi Disertacija
``. (Tudi nekateri drugi
programi lahko mislijo, da je ime programa, ki ga trenutno poganjate
,,vi Disertacija
``, a seveda je to le hipotetični primer,
zato tega ne poskušajte sami :-)
popen()
za odprtje procesa za branje in pisanje?
Subject: How do I use popen() to open a process for reading AND writing? Date: Thu Mar 18 17:16:55 EST 1993
Problem, ko poskušate preusmeriti vhod in izhod poljubnemu suženjskemu
procesu je, da lahko nastane mrtva zanka, če oba procesa hkrati čakata
na še-ne-generiran vhod. Zanki se lahko izognemo tako, da obe
strani upoštevata strog protokol brez mrtvih zank, toda, ker to
zahteva sodelovanje med procesi, je neprimerno za knjižnično funkcijo,
podobno popen()
.
Distribucija ,,expect
`` vključuje knjižnico funkcij, ki jih lahko
C-jevski programer kliče neposredno. Ena izmed funkcij dela isto
stvar kot popen
za hkratno branje in pisanje. Uporablja ptys
namesto cevi, in nima problemov z zaciklanjem. Prenosljiva je na BSD
in SV. Glejte vprašanje
,,Kako poženem passwd, ftp, telnet, tip in druge interaktivne programe v skriptu ukazne lupine v ozadju?`` za več podatkov o distribuciji
expect
.
sleep()
za manj kot sekundo?
Subject: How do I sleep() in a C program for less than one second? Date: Thu Mar 18 17:16:55 EST 1993
Najprej se zavedajte, da je vse, kar lahko določite minimalna količina zakasnitve; dejanska zakasnitev bo odvisna od upravniških zadev, kot je obremenitev sistema, in je lahko poljubno dolga, če nimate sreče.
Ne obstaja funkcija standardne knjižnice, na katero bi se lahko
zanesli v vseh okolji za ,,dremanje`` (angl. napping, običajen izraz
za kratke spance). Nekatera okolja priskrbijo funkcijo
,,usleep(n)
``, ki zadrži izvajanje za n
mikrosekund. Če vaše okolje ne podpira usleep()
, je tukaj nekaj
njenih implementacij za okolja BSD in System V.
Naslednja koda Douga Gwyna je prirejena z emulacijske podpore
Systema V za 4BSD in izrablja sistemski klic select()
na 4BSD-ju. Doug jo je prvotno imenoval ,,nap()
``; vi jo
boste verjetno želeli klicati ,,usleep()
``:
/* usleep - podporna rutina za emulacijo sistemskih klicev 4.2BSD zadnja sprememba originalne verzije: 29. oktober 1984 D A Gwyn */ extern int select(); int usleep( usec ) /* vrne 0, če je ok, sicer -1 */ long usec; /* premor v mikrosekundah */ { static struct /* `timeval' */ { long tv_sec; /* sekunde */ long tv_usec; /* mikrosekunde */ } delay; /* premor _select() */ delay.tv_sec = usec / 1000000L; delay.tv_usec = usec % 1000000L; return select( 0, (long *)0, (long *)0, (long *)0, &delay ); }
Na Unixih System V bi lahko to storili takole:
/* podsekundni premori za System V - ali karkoli, kar ima poll() Don Libes, 4/1/1991 BSD-jeva analogija te funkcije je definirana v mikrosekundah, medtem, kot je poll() definiran v milisekundah. Zaradi združljivosti, ta funkcija priskrbi natančnost "po dolgem teku" tako, da oklesti prave zahteve na milisekundo natančno in akumulira mikrosekunde med posameznimi klici z idejo, da jo verjetno kličete v tesni zanki, in se bo po dolgem teku napaka izničila. Če je ne kličete v tesni zanki, potem skoraj gotovo ne potrebujete mikrosekundne natančnosti in v tem primeru vam ni mar za mikrosekunde. Če vam bi bilo mar, tako ali tako ne bi uporabljali Unixa, saj lahko naključno prebavljanje sistema (npr. razporejanje) zmelje časomerilno kodo. Vrne 0 ob uspešnem premoru, -1 ob neuspešnem. */ #include <poll.h> int usleep(usec) unsigned int usec; /* mikrosekunde */ { static subtotal = 0; /* mikrosekunde */ int msec; /* milisekunde */ /* 'foo' je tukaj le zato, ker so imele nekatere verzije 5.3 * hrošča, pri katerem se prvi argument poll() preverja za * obstoj pravilnega pomnilniškega naslova, čeprav je drugi * argument enak 0. */ struct pollfd foo; subtotal += usec; /* če je premor < 1 ms, ne naredi ničesar, a si zapomni */ if (subtotal < 1000) return(0); msec = subtotal/1000; subtotal = subtotal%1000; return poll(&foo,(unsigned long)0,msec); }
s5nap
Jona Zeeffa, objavljen v
comp.sources.misc, volume 4. Ne
potrebuje namestitve gonilnika naprave, a deluje brez napak, ko se
namesti, (Njegova ločljivost je omejena z vrednostjo HZ
v jedru,
saj uporablja rutino delay()
jedra.)
Mnogo novejših Unixov ima funkcijo nanosleep
.
Subject: How can I get setuid shell scripts to work? Date: Thu Mar 18 17:16:55 EST 1993[ Ta odgovor je dolg, a to je zapleteno in pogosto zastavljeno vprašanje. Hvala Maartenu Litmaathu za ta odgovor in za spodaj omenjeni program ,,
indir
``. ]
#!/bin/sh
Skript se imenuje ,,izvedljivi``, ker se tako kot resnična
(binarna) izvedljiva datoteka začne s tako imenovano
,,magično številko``, ki določa tip izvedljive datoteke.
Glejte tudi razdelek
,,Zakaj se nekateri skripti začnejo z ,,#!...``?``.
V našem primeru je ta številka enaka ,,#!
`` in OS vzame
ostanek prve vrstice kot interpreter za skript, ki mu morda
sledi 1 uvodna izbira kot je:
#!/bin/sed -f
Denimo, da se ta skript imenuje ,foo
` in se nahaja
v imeniku /bin
. Če potem napišete:
foo arg1 arg2 arg3
bo OS preuredil zadeve tako, kot bi napisali:
/bin/sed -f /bin/foo arg1 arg2 arg3
Vendar je tukaj neka razlika: če je prižgan bit setuid za ,foo
`,
bo spoštovan v prvi obliki ukaza; če zares vpišete drugo obliko,
bo OS spoštoval bite z dovoljenji programa /bin/sed
, ki
seveda ni setuid.
#!
`, ali, če moj OS o tem nič ne ve?
No, če ga ukazna lupina (ali kdorkoli drug) poskuša izvesti, bo OS vrnil indikacijo napake, saj se datoteka ne začne z veljavno magično številko. Ukazna lupina bo po sprejetju te indikacije predpostavila, da gre za skript ukazne lupine in mu dala še eno priložnost:
/bin/sh lupinski_skript argumenti
A zdaj smo že videli, da se v tem primeru bit setuid datoteke
,lupinski_skript
` ne bo spoštoval!
Dobro, denimo, da se skript imenuje ,/etc/skript_setuid
`
in se začenja z vrstico:
#!/bin/sh
Zdaj pa poglejmo kaj se zgodi, če izvedemo naslednje ukaze:
$ cd /tmp
$ ln /etc/skript_setuid -i
$ PATH=.
$ -i
Vemo, da bo zadnji ukaz preurejen v:
/bin/sh -i
Toda ta ukaz nam bo dal interaktivno ukazno lupino, ki bo z bitom
setuid tekla, kot da bi jo pognal lastnik skripta!
Na srečo lahko to varnostno luknjo zlahka zapremo, če napišemo v prvo vrstico:
#!/bin/sh -
Znak ,-
` označuje konec seznama izbir: naslednji argument
,-i
` bo vzet kot ime datoteke, iz katere naj se berejo
ukazi, kot bi tudi moral biti!
$ cd /tmp
$ ln /etc/skript_setuid temp
$ nice -20 temp &
$ mv moj_skript temp
Tretji ukaz bo preurejen v:
nice -20 /bin/sh - temp
Ker se ta ukaz izvaja počasi, bo morda lahko četrti ukaz
zamenjal originalno datoteko ,temp
` s trojanskim konjem
,moj_skript
` preden ukazna lupina sploh
odpre ,temp
`! Obstajajo 4 načini za krpanje te varnostne
luknje:
/dev/fd
,
s katerim podata interpreterju datotečni deskriptor skripta;
indir
` iz arhiva
comp.sources.unix
bodo skripti setuid izgledali takole:
#!/bin/indir -u
#?/bin/sh /etc/skript_setuid
Seveda! Za skripte ukazne lupine ne smete pozabiti eksplicitno
nastavitev spremenljivke PATH
na varno pot. Lahko ugotovite
zakaj? Tukaj je še spremenljivka IFS
, ki lahko povzroča
težave, če ni pravilno nastavljena. Tudi druge okoljske
spremenljivke lahko ogrozijo varnost sistema, npr. SHELL
...
Nadalje se morate prepričati, da ukazi v skriptih ne dovoljujejo
interaktivnih ubežnih zaporedij ukazne lupine! Potem je tukaj
umask, ki je lahko nastavljen na kaj čudnega ...
Et cetera. Zavedati se morate, da skript setuid ,,podeduje`` vse hrošče in varnostna tveganja ukazov, ki jih kliče!
Subject: How can I find out which user or process has a file open ... ? Date: Thu Mar 18 17:16:55 EST 1993
Uporabite fuser
(system V), fstat
(BSD), ofiles
(v javni
lasti) ali pff
(v javni lasti). Ti programi vam bodo povedali
različne stvari o procesih, ki uporabljajo določene datoteke.
V arhivih
comp.sources.unix,
volume 18, najdete prenos fstat
z 4.3 BSD na Dynix, SunOS in Ultrix.
pff
je del paketa kstuff
in deluje na kar nekaj sistemih.
Navodila za nabavo kstuff
najdete v vprašanju
,,Kako lahko v skriptu ali programu ugotovim ID procesa programa z določenim imenom?``.
Obveščen sem bil, da obstaja tudi program, imenovan lsof
, a ne
vem, kje se ga dobi.
Michael Fink <Michael.Fink@uibk.ac.at
> dodaja:
Če ne morete odmestiti datotečnega sistema (z umount
), za
katerega zgornja orodja ne poročajo o odprtih datotekah, se
prepričajte, da datotečni sistem, ki ga poskušate odmeščati ne vsebuje
aktivnih točk nameščanja (uporabite df(1)
).
finger
)?
Subject: How do I keep track of people who are fingering me? From: Jonathan I. Kamens From: malenovi@plains.NoDak.edu (Nikola Malenović) Date: Thu, 29 Sep 1994 07:28:37 -0400
V splošnem ne morete ugotoviti userid nekoga, ki vas tipa z
oddaljenega stroja. Morda lahko ugotovite stroj, s katerega prihajajo
oddaljene zahteve. Ena od možnosti, če jo vaš sistem podpira, in, če
je tipalnemu strežniku (angl. finger daemon) prav, jo, da naredite
vašo datoteko .plan
za ,,imenovano cev`` (angl. named pipe)
namesto običajno datoteko. (Za to uporabite ,mknod
`.)
Potem lahko poženete program, ki bo odprl vašo datoteko .plan
za
pisanje; odpiranje bo blokirano dokler nek drugi proces (namreč
fingerd
) ne odpre .plan
za branje. Zdaj lahko skozi to pipo
pošljete, kar pač želite, kar vam omogoča, da prikažete različno
informacijo .plan
vsakič, ko vas nekdo potipa. Eden od programov
za to je paket ,,planner
``, objavljen v volume 41 arhivov
comp.sources.misc.
Seveda to sploh ne bo delovalo, če vaš sistem ne podpira imenovanih
cevi ali, če vaš lokalni fingerd
vztraja, da imate navadne
datoteke .plan
.
Vaš program lahko tudi izkoristi priložnost in pogleda v izhod
programa ,,netstat
``, ter s tem ugotovi, odkod prihaja zahteva za
finger
, toda to vam ne bo izdalo identitete oddaljenega
uporabnika.
Če želite dobiti oddaljeni userid, mora oddaljena stran poganjati
identifikacijski strežnik, kot je RFC 931. Trenutno obstajajo tri
implementacije RFC 931 za popularne stroje BSD, in nekaj aplikacij
(kot ftpd
z wuarchive), ki podpirajo ta strežnik. Za več
informacij se priključite elektronskemu spisku rfc931-users
z
običajno zahtevo ,,subscribe
`` na
rfc931-users-request@kramden.acf.nyu.edu.
Glede tega odgovora obstajajo tri opozorila. Prvo je, da mnogi sistemi NFS napačno prepoznajo imenovano cev. To pomeni, da bo poskus branja cevi na drugem stroju lahko blokiral, dokler ne poteče predviden čas, ali videl cev kot datoteko dolžine 0, in je ne bo nikoli izpisal.
Drugi problem je, da na veliko sistemih strežnik fingerd
preveri,
ali datoteka .plan
vsebuje podatke (in je bralna), preden jo
poskuša brati. V tem primeru bodo oddaljeni klici finger
popolnoma zgrešili vašo datoteko .plan
.
Tretji problem je, da imajo sistemi, ki podpirajo imenovane cevi, na
voljo v danem času le fiksno (končno) število le-teh - preverite
nastavitveno datoteko jedra in izbiro FIFOCNT
. Če število cevi
na sistemu prekorači vrednost FIFOCNT
, sistem prepreči izdelavo
novih cevi, dokler nekdo ne sprosti virov. Razlog za to je, da je
vmesni pomnilnik odmerjen v pomnilniku, ki se ne preklaplja
(angl. buffers are allocated in a non-paged memory).
Subject: Is it possible to reconnect a process to a terminal ... ? Date: Thu Mar 18 17:16:55 EST 1993
Večina različic Unixa ne podpira ,,odklopa`` in ,,priklopa`` procesov (angl. detaching/attaching processes), kot ju podpirajo operacijski sistemi kot sta VMS in Multics. Vendar obstajajo prosto dostopni paketi, s katerimi lahko poženete procese na takšen način, da se lahko pozneje spet pritrdijo na terminal.
screen
``, ki je opisan v arhivih
comp.sources.unix kot
,,Screen, multiple windows on a CRT`` (slov. ,,Zaslon, več oken na CRT``
- glejte paket screen-3.2
v
comp.sources.misc, volume 28). Ta paket bo tekel
vsaj na sistemih BSD, System V r3.2 in SCO UNIX.
pty
``, ki je v arhivih
comp.sources.unix opisan kot ,,Run a program under a pty
session`` (slov. ,,Poženite program v seji pty`` - glejte pty
v volume 23). Načrtovan je le za uporabo v sistemih, podobnih BSD.
dislocate
``, ki je skript, priložen distribuciji
expect
. Za razliko od prejšnjih dveh bi moral ta teči na
vseh različicah Unixa. Podrobnosti o tem, kako dobite expect
najdete v vprašanju
,,Kako poženem passwd, ftp, telnet, tip in druge interaktivne programe v skriptu ukazne lupine v ozadju?``.screen
ali pty
, če ga
želite odklopiti in priklopiti.
Subject: Is it possible to "spy" on a terminal ... ? Date: Wed, 28 Dec 1994 18:35:00 -0500
Za to obstaja več različnih poti, čeprav nobena od njih ni popolna:
kibitz
dovoljuje dvema (ali več) človekoma, da sta
v stiku prek ukazne lupine (ali poljubnega programa).
Uporaba vključuje:
kibitz
pride kot del distribucije expect
. Glejte
,,Kako poženem passwd, ftp, telnet, tip in druge interaktivne programe v skriptu ukazne lupine v ozadju?``.
Za uporabo pripomočka kibitz
potrebujete dovoljenje osebe,
ki jo želite vohuniti. Vohunjenje brez privolitve zahteva manj
prijetne pristope:
screen
vključuje večuporabniški
način. Nekaj podatkov o paketu screen
najdete v vprašanju
,,Je mogoče ponovno priključiti proces na terminal, ko je bil ta odklopljen, tj. po zagonu programa v ozadju in odjavi?``.
advise
na tok vsakič,
ko se odpre tty ali pty).