{-# LINE 1 "System/Posix/User/ByteString.hsc" #-}
{-# LANGUAGE Trustworthy, CApiFFI, PatternSynonyms, ViewPatterns #-}
module System.Posix.User.ByteString (
getRealUserID,
getRealGroupID,
getEffectiveUserID,
getEffectiveGroupID,
getGroups,
getLoginName,
getEffectiveUserName,
GroupEntry(..),
getGroupEntryForID,
getGroupEntryForName,
getAllGroupEntries,
UserEntry(..),
getUserEntryForID,
getUserEntryForName,
getAllUserEntries,
setUserID,
setGroupID,
setEffectiveUserID,
setEffectiveGroupID,
setGroups
) where
import System.Posix.Types
import System.IO.Unsafe (unsafePerformIO)
import Foreign.C ( CSize(..), CInt(..), CString, CLong(..), getErrno, throwErrno, eOK, throwErrnoIfMinus1_, throwErrnoIfNull, resetErrno, Errno(..), eRANGE, errnoToIOError )
import Foreign.Ptr
import Foreign.Marshal
import Foreign.Storable
import System.Posix.User.Common
{-# LINE 61 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 64 "System/Posix/User/ByteString.hsc" #-}
import Control.Concurrent.MVar ( MVar, newMVar, withMVar )
import Control.Exception
{-# LINE 67 "System/Posix/User/ByteString.hsc" #-}
import Control.Monad
import System.IO.Error
import Data.ByteString ( ByteString, packCString, useAsCString )
{-# LINE 75 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 140 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 206 "System/Posix/User/ByteString.hsc" #-}
pwlock :: MVar ()
pwlock = unsafePerformIO $ newMVar ()
{-# NOINLINE pwlock #-}
lockpw :: LKUPTYPE -> IO a -> IO a
{-# LINE 219 "System/Posix/User/ByteString.hsc" #-}
lockpw GETONE = id
lockpw GETALL = withMVar pwlock . const
{-# LINE 222 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 225 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 227 "System/Posix/User/ByteString.hsc" #-}
grlock :: MVar ()
grlock = unsafePerformIO $ newMVar ()
{-# NOINLINE grlock #-}
lockgr :: LKUPTYPE -> IO a -> IO a
{-# LINE 240 "System/Posix/User/ByteString.hsc" #-}
lockgr GETONE = id
lockgr GETALL = withMVar grlock . const
{-# LINE 243 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 246 "System/Posix/User/ByteString.hsc" #-}
getRealUserID :: IO UserID
getRealUserID = c_getuid
foreign import ccall unsafe "getuid"
c_getuid :: IO CUid
getRealGroupID :: IO GroupID
getRealGroupID = c_getgid
foreign import ccall unsafe "getgid"
c_getgid :: IO CGid
getEffectiveUserID :: IO UserID
getEffectiveUserID = c_geteuid
foreign import ccall unsafe "geteuid"
c_geteuid :: IO CUid
getEffectiveGroupID :: IO GroupID
getEffectiveGroupID = c_getegid
foreign import ccall unsafe "getegid"
c_getegid :: IO CGid
getGroups :: IO [GroupID]
getGroups = do
ngroups <- c_getgroups 0 nullPtr
allocaArray (fromIntegral ngroups) $ \arr -> do
throwErrnoIfMinus1_ "getGroups" (c_getgroups ngroups arr)
groups <- peekArray (fromIntegral ngroups) arr
return groups
foreign import ccall unsafe "getgroups"
c_getgroups :: CInt -> Ptr CGid -> IO CInt
setGroups :: [GroupID] -> IO ()
setGroups groups = do
withArrayLen groups $ \ ngroups arr ->
throwErrnoIfMinus1_ "setGroups" (c_setgroups (fromIntegral ngroups) arr)
foreign import ccall unsafe "setgroups"
c_setgroups :: CInt -> Ptr CGid -> IO CInt
getLoginName :: IO ByteString
getLoginName = do
str <- throwErrnoIfNull "getLoginName" c_getlogin
packCString str
foreign import ccall unsafe "getlogin"
c_getlogin :: IO CString
setUserID :: UserID -> IO ()
setUserID uid = throwErrnoIfMinus1_ "setUserID" (c_setuid uid)
foreign import ccall unsafe "setuid"
c_setuid :: CUid -> IO CInt
setEffectiveUserID :: UserID -> IO ()
setEffectiveUserID uid = throwErrnoIfMinus1_ "setEffectiveUserID" (c_seteuid uid)
foreign import ccall unsafe "seteuid"
c_seteuid :: CUid -> IO CInt
setGroupID :: GroupID -> IO ()
setGroupID gid = throwErrnoIfMinus1_ "setGroupID" (c_setgid gid)
foreign import ccall unsafe "setgid"
c_setgid :: CGid -> IO CInt
setEffectiveGroupID :: GroupID -> IO ()
setEffectiveGroupID gid =
throwErrnoIfMinus1_ "setEffectiveGroupID" (c_setegid gid)
foreign import ccall unsafe "setegid"
c_setegid :: CGid -> IO CInt
getEffectiveUserName :: IO ByteString
getEffectiveUserName = do
euid <- getEffectiveUserID
pw <- getUserEntryForID euid
return (userName pw)
{-# LINE 366 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 389 "System/Posix/User/ByteString.hsc" #-}
getGroupEntryForID :: GroupID -> IO GroupEntry
{-# LINE 396 "System/Posix/User/ByteString.hsc" #-}
getGroupEntryForID gid = lockgr GETONE $
allocaBytes (32) $ \pgr ->
{-# LINE 398 "System/Posix/User/ByteString.hsc" #-}
doubleAllocWhileERANGE "getGroupEntryForID" "group"
grBufSize unpackGroupEntry $ c_getgrgid_r gid pgr
foreign import capi safe "HsUnix.h getgrgid_r"
c_getgrgid_r :: CGid -> Ptr CGroup -> CString
-> CSize -> Ptr (Ptr CGroup) -> IO CInt
{-# LINE 408 "System/Posix/User/ByteString.hsc" #-}
getGroupEntryForName :: ByteString -> IO GroupEntry
{-# LINE 415 "System/Posix/User/ByteString.hsc" #-}
getGroupEntryForName name = lockgr GETONE $
allocaBytes (32) $ \pgr ->
{-# LINE 417 "System/Posix/User/ByteString.hsc" #-}
useAsCString name $ \ pstr ->
doubleAllocWhileERANGE "getGroupEntryForName" "group"
grBufSize unpackGroupEntry $ c_getgrnam_r pstr pgr
foreign import capi safe "HsUnix.h getgrnam_r"
c_getgrnam_r :: CString -> Ptr CGroup -> CString
-> CSize -> Ptr (Ptr CGroup) -> IO CInt
{-# LINE 428 "System/Posix/User/ByteString.hsc" #-}
getAllGroupEntries :: IO [GroupEntry]
{-# LINE 439 "System/Posix/User/ByteString.hsc" #-}
getAllGroupEntries = lockgr GETALL $ bracket_ c_setgrent c_endgrent $ worker []
where
worker accum = do
resetErrno
ppw <- throwErrnoIfNullAndError "getAllGroupEntries" $ c_getgrent
if ppw == nullPtr
then return (reverse accum)
else do thisentry <- unpackGroupEntry ppw
worker (thisentry : accum)
foreign import ccall safe "getgrent" c_getgrent :: IO (Ptr CGroup)
foreign import ccall safe "setgrent" c_setgrent :: IO ()
foreign import ccall safe "endgrent" c_endgrent :: IO ()
{-# LINE 456 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 458 "System/Posix/User/ByteString.hsc" #-}
grBufSize :: Int
{-# LINE 460 "System/Posix/User/ByteString.hsc" #-}
grBufSize = sysconfWithDefault 1024 (69)
{-# LINE 461 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 464 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 465 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 467 "System/Posix/User/ByteString.hsc" #-}
getUserEntryForID :: UserID -> IO UserEntry
{-# LINE 478 "System/Posix/User/ByteString.hsc" #-}
getUserEntryForID uid = lockpw GETONE $
allocaBytes (48) $ \ppw ->
{-# LINE 480 "System/Posix/User/ByteString.hsc" #-}
doubleAllocWhileERANGE "getUserEntryForID" "user"
pwBufSize unpackUserEntry $ c_getpwuid_r uid ppw
foreign import capi safe "HsUnix.h getpwuid_r"
c_getpwuid_r :: CUid -> Ptr CPasswd ->
CString -> CSize -> Ptr (Ptr CPasswd) -> IO CInt
{-# LINE 490 "System/Posix/User/ByteString.hsc" #-}
getUserEntryForName :: ByteString -> IO UserEntry
{-# LINE 497 "System/Posix/User/ByteString.hsc" #-}
getUserEntryForName name = lockpw GETONE $
allocaBytes (48) $ \ppw ->
{-# LINE 499 "System/Posix/User/ByteString.hsc" #-}
useAsCString name $ \ pstr ->
doubleAllocWhileERANGE "getUserEntryForName" "user"
pwBufSize unpackUserEntry $ c_getpwnam_r pstr ppw
foreign import capi safe "HsUnix.h getpwnam_r"
c_getpwnam_r :: CString -> Ptr CPasswd
-> CString -> CSize -> Ptr (Ptr CPasswd) -> IO CInt
{-# LINE 510 "System/Posix/User/ByteString.hsc" #-}
getAllUserEntries :: IO [UserEntry]
{-# LINE 515 "System/Posix/User/ByteString.hsc" #-}
getAllUserEntries = lockpw GETALL $ bracket_ c_setpwent c_endpwent $ worker []
where
worker accum = do
resetErrno
ppw <- throwErrnoIfNullAndError "getAllUserEntries" $ c_getpwent
if ppw == nullPtr
then return (reverse accum)
else do thisentry <- unpackUserEntry ppw
worker (thisentry : accum)
foreign import ccall safe "getpwent" c_getpwent :: IO (Ptr CPasswd)
foreign import ccall safe "setpwent" c_setpwent :: IO ()
foreign import ccall safe "endpwent" c_endpwent :: IO ()
{-# LINE 532 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 534 "System/Posix/User/ByteString.hsc" #-}
pwBufSize :: Int
{-# LINE 536 "System/Posix/User/ByteString.hsc" #-}
pwBufSize = sysconfWithDefault 1024 (70)
{-# LINE 537 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 540 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 541 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 543 "System/Posix/User/ByteString.hsc" #-}
foreign import ccall unsafe "sysconf"
c_sysconf :: CInt -> IO CLong
sysconfWithDefault :: Int -> CInt -> Int
sysconfWithDefault def sc =
unsafePerformIO $ do v <- fmap fromIntegral $ c_sysconf sc
return $ if v == (-1) then def else v
{-# LINE 555 "System/Posix/User/ByteString.hsc" #-}
{-# LINE 557 "System/Posix/User/ByteString.hsc" #-}
doubleAllocWhileERANGE
:: String
-> String
-> Int
-> (Ptr r -> IO a)
-> (Ptr b -> CSize -> Ptr (Ptr r) -> IO CInt)
-> IO a
doubleAllocWhileERANGE loc enttype initlen unpack action =
alloca $ go initlen
where
go len res = do
r <- allocaBytes len $ \buf -> do
rc <- action buf (fromIntegral len) res
if rc /= 0
then return (Left rc)
else do p <- peek res
when (p == nullPtr) $ notFoundErr
fmap Right (unpack p)
case r of
Right x -> return x
Left rc | Errno rc == eRANGE ->
go (2 * len) res
Left rc ->
ioError (errnoToIOError loc (Errno rc) Nothing Nothing)
notFoundErr =
ioError $ flip ioeSetErrorString ("no such " ++ enttype)
$ mkIOError doesNotExistErrorType loc Nothing Nothing
throwErrnoIfNullAndError :: String -> IO (Ptr a) -> IO (Ptr a)
throwErrnoIfNullAndError loc act = do
rc <- act
errno <- getErrno
if rc == nullPtr && errno /= eOK
then throwErrno loc
else return rc
{-# LINE 605 "System/Posix/User/ByteString.hsc" #-}