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 | |
14 | void Check(const char *str) { |
15 | if (!str) |
16 | return; |
17 | assert(strlen(str) != N); |
18 | } |
19 | |
20 | void Check(const passwd *result) { |
21 | Check(str: result->pw_name); |
22 | Check(str: result->pw_passwd); |
23 | assert(result->pw_uid != N); |
24 | assert(result->pw_gid != N); |
25 | #if !defined(__ANDROID__) |
26 | Check(str: result->pw_gecos); |
27 | #endif |
28 | Check(str: 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 | |
43 | void Check(const group *result) { |
44 | Check(str: result->gr_name); |
45 | Check(str: result->gr_passwd); |
46 | assert(result->gr_gid != N); |
47 | for (char **mem = result->gr_mem; *mem; ++mem) |
48 | Check(str: *mem); |
49 | if (!any_group) { |
50 | auto length = strlen(s: result->gr_name); |
51 | any_group.reset(p: new char[length + 1]); |
52 | memcpy(dest: any_group.get(), src: result->gr_name, n: length + 1); |
53 | } |
54 | } |
55 | |
56 | template <class T, class Fn, class... 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> |
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 | |
72 | int main(int argc, const char *argv[]) { |
73 | test<passwd>(f: &getpwuid, args: 0); |
74 | test<passwd>(f: &getpwnam, args: "root" ); |
75 | test<group>(f: &getgrgid, args: 0); |
76 | test<group>(f: &getgrnam, args: any_group.get()); |
77 | |
78 | #if !defined(__ANDROID__) |
79 | setpwent(); |
80 | test<passwd>(f: &getpwent); |
81 | setgrent(); |
82 | test<group>(f: &getgrent); |
83 | |
84 | #if !defined(__APPLE__) && !(defined(__sun__) && defined(__svr4__)) |
85 | setpwent(); |
86 | test_r<passwd>(f: &getpwent_r); |
87 | setgrent(); |
88 | test_r<group>(f: &getgrent_r); |
89 | #endif |
90 | |
91 | test_r<passwd>(f: &getpwuid_r, args: 0); |
92 | test_r<passwd>(f: &getpwnam_r, args: "root" ); |
93 | |
94 | test_r<group>(f: &getgrgid_r, args: 0); |
95 | test_r<group>(f: &getgrnam_r, args: any_group.get()); |
96 | |
97 | #if defined(__linux__) |
98 | auto pwd_file = [] { |
99 | return std::unique_ptr<FILE, decltype(&fclose)>(fopen(filename: "/etc/passwd" , modes: "r" ), |
100 | &fclose); |
101 | }; |
102 | auto gr_file = [] { |
103 | return std::unique_ptr<FILE, decltype(&fclose)>(fopen(filename: "/etc/group" , modes: "r" ), |
104 | &fclose); |
105 | }; |
106 | test<passwd>(f: &fgetpwent, args: pwd_file().get()); |
107 | test<group>(f: &fgetgrent, args: gr_file().get()); |
108 | test_r<passwd>(f: &fgetpwent_r, args: pwd_file().get()); |
109 | test_r<group>(f: &fgetgrent_r, args: gr_file().get()); |
110 | #endif |
111 | |
112 | #endif // __ANDROID__ |
113 | |
114 | return 0; |
115 | } |
116 | |