1 // RUN: %clangxx %s -o %t && %run %t
2 
3 #include <assert.h>
4 #include <grp.h>
5 #include <memory>
6 #include <pwd.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 
11 std::unique_ptr<char []> any_group;
12 const int N = 123456;
13 
Check(const char * str)14 void Check(const char *str) {
15   if (!str)
16     return;
17   assert(strlen(str) != N);
18 }
19 
Check(const passwd * result)20 void Check(const passwd *result) {
21   Check(result->pw_name);
22   Check(result->pw_passwd);
23   assert(result->pw_uid != N);
24   assert(result->pw_gid != N);
25 #if !defined(__ANDROID__)
26   Check(result->pw_gecos);
27 #endif
28   Check(result->pw_dir);
29 
30 #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
31   assert(result->pw_change != N);
32   Check(result->pw_class);
33   assert(result->pw_expire != N);
34 #endif
35 
36 #if defined(__FreeBSD__)
37   assert(result->pw_fields != N);
38 #endif
39 
40   // SunOS also has pw_age and pw_comment which are documented as unused.
41 }
42 
Check(const group * result)43 void Check(const group *result) {
44   Check(result->gr_name);
45   Check(result->gr_passwd);
46   assert(result->gr_gid != N);
47   for (char **mem = result->gr_mem; *mem; ++mem)
48     Check(*mem);
49   if (!any_group) {
50     auto length = strlen(result->gr_name);
51     any_group.reset(new char[length + 1]);
52     memcpy(any_group.get(), result->gr_name, length + 1);
53   }
54 }
55 
56 template <class T, class Fn, class... Args>
test(Fn f,Args...args)57 void test(Fn f, Args... args) {
58   T *result = f(args...);
59   Check(result);
60 }
61 
62 template <class T, class Fn, class... Args>
test_r(Fn f,Args...args)63 void test_r(Fn f, Args... args) {
64   T gr;
65   T *result;
66   char buff[10000];
67   assert(!f(args..., &gr, buff, sizeof(buff), &result));
68   Check(&gr);
69   Check(result);
70 }
71 
main(int argc,const char * argv[])72 int main(int argc, const char *argv[]) {
73   test<passwd>(&getpwuid, 0);
74   test<passwd>(&getpwnam, "root");
75   test<group>(&getgrgid, 0);
76   test<group>(&getgrnam, any_group.get());
77 
78 #if !defined(__ANDROID__)
79   setpwent();
80   test<passwd>(&getpwent);
81   setgrent();
82   test<group>(&getgrent);
83 
84 #if !defined(__APPLE__) && !(defined(__sun__) && defined(__svr4__))
85   setpwent();
86   test_r<passwd>(&getpwent_r);
87   setgrent();
88   test_r<group>(&getgrent_r);
89 #endif
90 
91   test_r<passwd>(&getpwuid_r, 0);
92   test_r<passwd>(&getpwnam_r, "root");
93 
94   test_r<group>(&getgrgid_r, 0);
95   test_r<group>(&getgrnam_r, any_group.get());
96 
97 #if defined(__linux__)
98   auto pwd_file = [] {
99     return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/passwd", "r"),
100                                                     &fclose);
101   };
102   auto gr_file = [] {
103     return std::unique_ptr<FILE, decltype(&fclose)>(fopen("/etc/group", "r"),
104                                                     &fclose);
105   };
106   test<passwd>(&fgetpwent, pwd_file().get());
107   test<group>(&fgetgrent, gr_file().get());
108   test_r<passwd>(&fgetpwent_r, pwd_file().get());
109   test_r<group>(&fgetgrent_r, gr_file().get());
110 #endif
111 
112 #endif // __ANDROID__
113 
114   return 0;
115 }
116