2012-03-20 7 views
6

ho scoperto il prossimo numero in questo semplice codice:OCaml: un'eccezione imprevista con Unix.getlogin quando stdin rediretto

let() = 
    print_endline "Hello"; 
    print_endline (Unix.getlogin()) 

esecuzione nel caso normale, con ./a.out dà:

Hello 
ricardo 

Ma correndo come ./a.out </dev/null rende Unix.getlogin venga meno

Hello 
Fatal error: exception Unix.Unix_error(20, "getlogin", "") 

Qualsiasi id E perché questo succede?

+0

Ho appena provato questo sul mio sistema: Mac OS X 10.6.8/OCaml 3.12.0 e non vedo il problema. L'output è lo stesso in entrambi i casi. Qual è il tuo sistema? –

+0

Linux, ho letto di nuovo man 3 getlogin e ho visto il "bug" in glibc sul reindirizzamento dello stdin: -/ – Ricardo

+0

Sì, bkconrad lo ha inchiodato! –

risposta

5

Il reindirizzamento dell'input di un programma ha la precedenza sul suo terminale di controllo. Senza un terminale di controllo, non v'è alcun accesso da trovare:

$ tty 
/dev/pts/2 
$ tty < /dev/null 
not a tty 

È possibile, tuttavia, ancora trovare il nome di un utente (forse) ottenendo id dell'utente (getuid) e alzando il suo passwd entry (related docs) (getpwuid), poi trovando il suo nome utente in esso.

+0

La risposta dovrebbe provenire dall'uid del processo, non dal terminale di controllo. Ma questo potrebbe essere il problema. –

+0

Supponendo che chiami il vero 'getlogin' (http://linux.die.net/man/3/getlogin), allora, di fatto, proviene dal terminale di controllo. – bkconrad

+0

Wow. Su BSD (e Mac OS X), è un set di valori separato quando si accede. Non è basato su getuid() o geteuid() come mi aspettavo, ma non sul terminale di controllo. Sembra un po 'meglio per me. –

3

A seconda dell'applicazione:

  • se non vi interessa veramente il valore restituito da "getlogin", si può fare qualcosa di simile:

    try 
        Unix.getlogin() 
    with _ -> Sys.getenv "USER" 
    

    si avrà probabilmente ottenere qualcosa meglio di getuid, dato che funzionerà anche con programmi con flag Set-User-ID (sudo/su).

  • se ti interessa veramente il valore restituito da "getlogin", cioè vuoi davvero sapere chi è loggato, dovresti semplicemente fallire quando getlogin fallisce. Qualsiasi altra soluzione fornirà solo un'approssimazione del risultato corretto.