
In the unix package, in System.Posix.User, we have the following functions [1]: * getLoginName (getlogin) * getUserEntryForID (getpwuid_r) * getGroupEntryForID (getgrgid_r) * getUserEntryForName (getpwnam_r) * getGroupEntryForName (getgrnam_r) They have signature `IO String`, and use `throwErrnoIfNull` to call the c functions listed in parenthesis. ## Proposal Change the signature of the functions listed above to `IO (Maybe String)`. The new semantics would be: * If the c function returns a NULL pointer with errno set to ENOENT, meaning the given user or group could not be found, the result is Nothing. * If another error occured, an error is thrown (no change). * Otherwise the result is Just "result". ## Motivation At least `getlogin` and `getgrgid` are unreliable on Linux. It is possible for them to return NULL pointers [2] even when the user is logged in and has an associated user entry in /etc/passwd and group entry in /etc/group. Examples: * when `getLoginName` is called using a terminal emulator that doesn't write login records to /var/run/utmp, or inside screen/tmux, `getlogin` tends to return NULL pointers [3]. * `getGroupEntryForID` can throw a NULL pointer exception inside chroots or other environments where the information in /etc/groups is not to be considered reliable [4]. Since we can, let's give the above Haskell functions a type safe(r) api. If the proposal gets rejected, I will just add a warning message to the docstrings of the functions in question and permanently disable their tests from the unix testsuite, since this is currently causing problems [5,6]. Discussion period: 2 weeks. ## Links [1] https://github.com/haskell/unix/blob/master/System/Posix/User.hsc [2] http://linux.die.net/man/3/getlogin [3] https://github.com/haskell/unix/blob/cad1ef27bb0a51bc68ebadb1297de1ae05bee9d... [4] https://ghc.haskell.org/trac/ghc/ticket/8293 [5] http://www.haskell.org/pipermail/ghc-devs/2014-September/006420.html [6] https://ghc.haskell.org/trac/ghc/ticket/1487#comment:23 ## Details * Another function in the same module that needs to change is `getEffectiveUserName`, because it calls the function `getUserEntryForID` mentioned before. * The following functions don't need to change, since they return the empty list if no entries are found: - getGroups (getgroups) - getAllGroupEntries (getgrent) - getAllUserEntries (getpwent) * The rest of the functions in the module don't need to change either, since they are not expected to return NULL pointers, according to their respective man pages: - getRealUserID (getuid) - getRealGroupID (getgid) - getEffectiveUserID (geteuid) - getEffectiveGroupID (getegid)