1
- {-# LANGUAGE Trustworthy, CApiFFI #-}
1
+ {-# LANGUAGE Trustworthy, CApiFFI, PatternSynonyms, ViewPatterns #-}
2
2
-----------------------------------------------------------------------------
3
3
-- |
4
4
-- Module : System.Posix.User
@@ -25,13 +25,25 @@ module System.Posix.User (
25
25
getEffectiveUserName ,
26
26
27
27
-- *** The group database
28
- GroupEntry (.. ),
28
+ groupName ,
29
+ groupPassword ,
30
+ groupID ,
31
+ groupMembers ,
32
+ pattern GroupEntry ,
29
33
getGroupEntryForID ,
30
34
getGroupEntryForName ,
31
35
getAllGroupEntries ,
32
36
33
37
-- *** The user database
34
- UserEntry (.. ),
38
+ userName ,
39
+ userPassword ,
40
+ userID ,
41
+ userGroupID ,
42
+ userGecos ,
43
+ homeDirectory ,
44
+ userShell ,
45
+ pattern UserEntry ,
46
+
35
47
getUserEntryForID ,
36
48
getUserEntryForName ,
37
49
getAllUserEntries ,
@@ -53,6 +65,12 @@ import Foreign.C
53
65
import Foreign.Ptr
54
66
import Foreign.Marshal
55
67
import Foreign.Storable
68
+ import System.Posix.User.Common ( UserEntry , GroupEntry
69
+ #if defined(HAVE_PWD_H)
70
+ , unpackUserEntry , unpackGroupEntry , LKUPTYPE (.. ), CPasswd , CGroup
71
+ #endif
72
+ )
73
+ import qualified System.Posix.User.Common as User
56
74
57
75
#if defined(HAVE_GETPWENT) || defined(HAVE_GETGRENT)
58
76
#if defined(freebsd_HOST_OS)
@@ -63,19 +81,13 @@ import Control.Exception
63
81
#endif
64
82
import Control.Monad
65
83
import System.IO.Error
84
+ import qualified Data.ByteString.Char8 as C8
66
85
67
86
#if !defined(HAVE_PWD_H)
68
87
import System.IO.Error ( ioeSetLocation )
69
88
import GHC.IO.Exception ( unsupportedOperation )
70
89
#endif
71
90
72
- #if defined(HAVE_PWD_H)
73
-
74
- -- internal types
75
- data {-# CTYPE "struct passwd" #-} CPasswd
76
- data {-# CTYPE "struct group" #-} CGroup
77
-
78
- #endif // HAVE_PWD_H
79
91
80
92
#if !defined(HAVE_PWD_H)
81
93
@@ -204,7 +216,6 @@ getEffectiveUserName = ioError (ioeSetLocation unsupportedOperation "getEffectiv
204
216
-- lot of complexity by deprecating the "get all" functions and simply
205
217
-- always returning an empty list.
206
218
--
207
- data LKUPTYPE = GETONE | GETALL
208
219
209
220
#if defined(HAVE_GETPWENT)
210
221
pwlock :: MVar ()
@@ -371,13 +382,28 @@ getEffectiveUserName = do
371
382
-- -----------------------------------------------------------------------------
372
383
-- The group database (grp.h)
373
384
374
- data GroupEntry =
375
- GroupEntry {
376
- groupName :: String , -- ^ The name of this group (gr_name)
377
- groupPassword :: String , -- ^ The password for this group (gr_passwd)
378
- groupID :: GroupID , -- ^ The unique numeric ID for this group (gr_gid)
379
- groupMembers :: [String ] -- ^ A list of zero or more usernames that are members (gr_mem)
380
- } deriving (Show , Read , Eq )
385
+ groupName :: GroupEntry -> String
386
+ groupName (GroupEntry gn _ _ _) = gn
387
+
388
+ groupPassword :: GroupEntry -> String
389
+ groupPassword (GroupEntry _ gp _ _) = gp
390
+
391
+ groupID :: GroupEntry -> GroupID
392
+ groupID (GroupEntry _ _ id' _) = id'
393
+
394
+ groupMembers :: GroupEntry -> [String ]
395
+ groupMembers (GroupEntry _ _ _ gm) = gm
396
+
397
+ -- | Manually constructing 'GroupEntry' in String modules is discouraged. It will truncate
398
+ -- Chars to 8bit. Use 'System.Posix.User.ByteString' instead.
399
+ pattern GroupEntry :: String -- ^ The name of this group (gr_name)
400
+ -> String -- ^ The password for this group (gr_passwd)
401
+ -> GroupID -- ^ The unique numeric ID for this group (gr_gid)
402
+ -> [String ] -- ^ A list of zero or more usernames that are members (gr_mem)
403
+ -> GroupEntry
404
+ pattern GroupEntry gn gp gi gm <- User. GroupEntry (C8. unpack -> gn) (C8. unpack -> gp) gi (fmap C8. unpack -> gm) where
405
+ GroupEntry gn gp gi gm = User. GroupEntry (C8. pack gn) (C8. pack gp) gi (C8. pack <$> gm)
406
+ {-# COMPLETE GroupEntry #-}
381
407
382
408
#if !defined(HAVE_PWD_H)
383
409
@@ -474,30 +500,57 @@ grBufSize = 1024
474
500
#endif
475
501
#endif
476
502
477
- unpackGroupEntry :: Ptr CGroup -> IO GroupEntry
478
- unpackGroupEntry ptr = do
479
- name <- (# peek struct group, gr_name) ptr >>= peekCAString
480
- passwd <- (# peek struct group, gr_passwd) ptr >>= peekCAString
481
- gid <- (# peek struct group, gr_gid) ptr
482
- mem <- (# peek struct group, gr_mem) ptr
483
- members <- peekArray0 nullPtr mem >>= mapM peekCAString
484
- return (GroupEntry name passwd gid members)
485
-
486
503
#endif // HAVE_PWD_H
487
504
488
505
-- -----------------------------------------------------------------------------
489
506
-- The user database (pwd.h)
490
507
491
- data UserEntry =
492
- UserEntry {
493
- userName :: String , -- ^ Textual name of this user (pw_name)
494
- userPassword :: String , -- ^ Password -- may be empty or fake if shadow is in use (pw_passwd)
495
- userID :: UserID , -- ^ Numeric ID for this user (pw_uid)
496
- userGroupID :: GroupID , -- ^ Primary group ID (pw_gid)
497
- userGecos :: String , -- ^ Usually the real name for the user (pw_gecos)
498
- homeDirectory :: String , -- ^ Home directory (pw_dir)
499
- userShell :: String -- ^ Default shell (pw_shell)
500
- } deriving (Show , Read , Eq )
508
+ userName :: UserEntry -> String
509
+ userName (UserEntry n _ _ _ _ _ _) = n
510
+
511
+ userPassword :: UserEntry -> String
512
+ userPassword (UserEntry _ p _ _ _ _ _) = p
513
+
514
+ userID :: UserEntry -> UserID
515
+ userID (UserEntry _ _ id' _ _ _ _) = id'
516
+
517
+ userGroupID :: UserEntry -> GroupID
518
+ userGroupID (UserEntry _ _ _ gid _ _ _) = gid
519
+
520
+ userGecos :: UserEntry -> String
521
+ userGecos (UserEntry _ _ _ _ ge _ _) = ge
522
+
523
+ homeDirectory :: UserEntry -> String
524
+ homeDirectory (UserEntry _ _ _ _ _ hd _) = hd
525
+
526
+ userShell :: UserEntry -> String
527
+ userShell (UserEntry _ _ _ _ _ _ us) = us
528
+
529
+ -- | Manually constructing 'UserEntry' in String modules is discouraged. It will truncate
530
+ -- Chars to 8bit. Use 'System.Posix.User.ByteString' instead.
531
+ pattern UserEntry :: String -- ^ Textual name of this user (pw_name)
532
+ -> String -- ^ Password -- may be empty or fake if shadow is in use (pw_passwd)
533
+ -> UserID -- ^ Numeric ID for this user (pw_uid)
534
+ -> GroupID -- ^ Primary group ID (pw_gid)
535
+ -> String -- ^ Usually the real name for the user (pw_gecos)
536
+ -> String -- ^ Home directory (pw_dir)
537
+ -> String -- ^ Default shell (pw_shell)
538
+ -> UserEntry
539
+ pattern UserEntry un up ui ugi ug hd us <- User. UserEntry (C8. unpack -> un)
540
+ (C8. unpack -> up)
541
+ ui
542
+ ugi
543
+ (C8. unpack -> ug)
544
+ (C8. unpack -> hd)
545
+ (C8. unpack -> us) where
546
+ UserEntry un up ui ugi ug hd us = User. UserEntry (C8. pack un)
547
+ (C8. pack up)
548
+ ui
549
+ ugi
550
+ (C8. pack ug)
551
+ (C8. pack hd)
552
+ (C8. pack us)
553
+ {-# COMPLETE UserEntry #-}
501
554
502
555
-- | @getUserEntryForID uid@ calls @getpwuid_r@ to obtain
503
556
-- the @UserEntry@ information associated with @UserID@
@@ -621,20 +674,6 @@ doubleAllocWhileERANGE loc enttype initlen unpack action =
621
674
ioError $ flip ioeSetErrorString (" no such " ++ enttype)
622
675
$ mkIOError doesNotExistErrorType loc Nothing Nothing
623
676
624
- unpackUserEntry :: Ptr CPasswd -> IO UserEntry
625
- unpackUserEntry ptr = do
626
- name <- (# peek struct passwd, pw_name) ptr >>= peekCAString
627
- passwd <- (# peek struct passwd, pw_passwd) ptr >>= peekCAString
628
- uid <- (# peek struct passwd, pw_uid) ptr
629
- gid <- (# peek struct passwd, pw_gid) ptr
630
- #ifdef HAVE_NO_PASSWD_PW_GECOS
631
- gecos <- return " " -- pw_gecos does not exist on android
632
- #else
633
- gecos <- (# peek struct passwd, pw_gecos) ptr >>= peekCAString
634
- #endif
635
- dir <- (# peek struct passwd, pw_dir) ptr >>= peekCAString
636
- shell <- (# peek struct passwd, pw_shell) ptr >>= peekCAString
637
- return (UserEntry name passwd uid gid gecos dir shell)
638
677
639
678
-- Used when a function returns NULL to indicate either an error or
640
679
-- EOF, depending on whether the global errno is nonzero.
0 commit comments