1 | /* |
---|
2 | * Top users/processes display for Unix |
---|
3 | * Version 3 |
---|
4 | * |
---|
5 | * This program may be freely redistributed, |
---|
6 | * but this entire comment MUST remain intact. |
---|
7 | * |
---|
8 | * Copyright (c) 1984, 1989, William LeFebvre, Rice University |
---|
9 | * Copyright (c) 1989, 1990, 1992, William LeFebvre, Northwestern University |
---|
10 | */ |
---|
11 | |
---|
12 | /* |
---|
13 | * Username translation code for top. |
---|
14 | * |
---|
15 | * These routines handle uid to username mapping. |
---|
16 | * They use a hashing table scheme to reduce reading overhead. |
---|
17 | * For the time being, these are very straightforward hashing routines. |
---|
18 | * Maybe someday I'll put in something better. But with the advent of |
---|
19 | * "random access" password files, it might not be worth the effort. |
---|
20 | * |
---|
21 | * Changes to these have been provided by John Gilmore (gnu@toad.com). |
---|
22 | * |
---|
23 | * The hash has been simplified in this release, to avoid the |
---|
24 | * table overflow problems of previous releases. If the value |
---|
25 | * at the initial hash location is not right, it is replaced |
---|
26 | * by the right value. Collisions will cause us to call getpw* |
---|
27 | * but hey, this is a cache, not the Library of Congress. |
---|
28 | * This makes the table size independent of the passwd file size. |
---|
29 | */ |
---|
30 | |
---|
31 | #include <stdio.h> |
---|
32 | #include <pwd.h> |
---|
33 | |
---|
34 | #include "top.local.h" |
---|
35 | #include "utils.h" |
---|
36 | |
---|
37 | struct hash_el { |
---|
38 | int uid; |
---|
39 | char name[9]; |
---|
40 | }; |
---|
41 | |
---|
42 | #define is_empty_hash(x) (hash_table[x].name[0] == 0) |
---|
43 | |
---|
44 | /* simple minded hashing function */ |
---|
45 | /* Uid "nobody" is -2 results in hashit(-2) = -2 which is out of bounds for |
---|
46 | the hash_table. Applied abs() function to fix. 2/16/96 tpugh |
---|
47 | */ |
---|
48 | #define hashit(i) (abs(i) % Table_size) |
---|
49 | |
---|
50 | /* K&R requires that statically declared tables be initialized to zero. */ |
---|
51 | /* We depend on that for hash_table and YOUR compiler had BETTER do it! */ |
---|
52 | struct hash_el hash_table[Table_size]; |
---|
53 | |
---|
54 | init_hash() |
---|
55 | |
---|
56 | { |
---|
57 | /* |
---|
58 | * There used to be some steps we had to take to initialize things. |
---|
59 | * We don't need to do that anymore, but we will leave this stub in |
---|
60 | * just in case future changes require initialization steps. |
---|
61 | */ |
---|
62 | } |
---|
63 | |
---|
64 | char *username(uid) |
---|
65 | |
---|
66 | register int uid; |
---|
67 | |
---|
68 | { |
---|
69 | register int hashindex; |
---|
70 | |
---|
71 | hashindex = hashit(uid); |
---|
72 | if (is_empty_hash(hashindex) || (hash_table[hashindex].uid != uid)) |
---|
73 | { |
---|
74 | /* not here or not right -- get it out of passwd */ |
---|
75 | hashindex = get_user(uid); |
---|
76 | } |
---|
77 | return(hash_table[hashindex].name); |
---|
78 | } |
---|
79 | |
---|
80 | int userid(username) |
---|
81 | |
---|
82 | char *username; |
---|
83 | |
---|
84 | { |
---|
85 | struct passwd *pwd; |
---|
86 | |
---|
87 | /* Eventually we want this to enter everything in the hash table, |
---|
88 | but for now we just do it simply and remember just the result. |
---|
89 | */ |
---|
90 | |
---|
91 | if ((pwd = getpwnam(username)) == NULL) |
---|
92 | { |
---|
93 | return(-1); |
---|
94 | } |
---|
95 | |
---|
96 | /* enter the result in the hash table */ |
---|
97 | enter_user(pwd->pw_uid, username, 1); |
---|
98 | |
---|
99 | /* return our result */ |
---|
100 | return(pwd->pw_uid); |
---|
101 | } |
---|
102 | |
---|
103 | int enter_user(uid, name, wecare) |
---|
104 | |
---|
105 | register int uid; |
---|
106 | register char *name; |
---|
107 | int wecare; /* 1 = enter it always, 0 = nice to have */ |
---|
108 | |
---|
109 | { |
---|
110 | register int hashindex; |
---|
111 | |
---|
112 | #ifdef DEBUG |
---|
113 | fprintf(stderr, "enter_hash(%d, %s, %d)\n", uid, name, wecare); |
---|
114 | #endif |
---|
115 | |
---|
116 | hashindex = hashit(uid); |
---|
117 | |
---|
118 | if (!is_empty_hash(hashindex)) |
---|
119 | { |
---|
120 | if (!wecare) |
---|
121 | return 0; /* Don't clobber a slot for trash */ |
---|
122 | if (hash_table[hashindex].uid == uid) |
---|
123 | return(hashindex); /* Fortuitous find */ |
---|
124 | } |
---|
125 | |
---|
126 | /* empty or wrong slot -- fill it with new value */ |
---|
127 | hash_table[hashindex].uid = uid; |
---|
128 | (void) strncpy(hash_table[hashindex].name, name, 8); |
---|
129 | return(hashindex); |
---|
130 | } |
---|
131 | |
---|
132 | /* |
---|
133 | * Get a userid->name mapping from the system. |
---|
134 | * If the passwd database is hashed (#define RANDOM_PW), we |
---|
135 | * just handle this uid. Otherwise we scan the passwd file |
---|
136 | * and cache any entries we pass over while looking. |
---|
137 | */ |
---|
138 | |
---|
139 | int get_user(uid) |
---|
140 | |
---|
141 | register int uid; |
---|
142 | |
---|
143 | { |
---|
144 | struct passwd *pwd; |
---|
145 | |
---|
146 | #ifdef RANDOM_PW |
---|
147 | /* no performance penalty for using getpwuid makes it easy */ |
---|
148 | if ((pwd = getpwuid(uid)) != NULL) |
---|
149 | { |
---|
150 | return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); |
---|
151 | } |
---|
152 | #else |
---|
153 | |
---|
154 | int from_start = 0; |
---|
155 | |
---|
156 | /* |
---|
157 | * If we just called getpwuid each time, things would be very slow |
---|
158 | * since that just iterates through the passwd file each time. So, |
---|
159 | * we walk through the file instead (using getpwent) and cache each |
---|
160 | * entry as we go. Once the right record is found, we cache it and |
---|
161 | * return immediately. The next time we come in, getpwent will get |
---|
162 | * the next record. In theory, we never have to read the passwd file |
---|
163 | * a second time (because we cache everything we read). But in |
---|
164 | * practice, the cache may not be large enough, so if we don't find |
---|
165 | * it the first time we have to scan the file a second time. This |
---|
166 | * is not very efficient, but it will do for now. |
---|
167 | */ |
---|
168 | |
---|
169 | while (from_start++ < 2) |
---|
170 | { |
---|
171 | while ((pwd = getpwent()) != NULL) |
---|
172 | { |
---|
173 | if (pwd->pw_uid == uid) |
---|
174 | { |
---|
175 | return(enter_user(pwd->pw_uid, pwd->pw_name, 1)); |
---|
176 | } |
---|
177 | (void) enter_user(pwd->pw_uid, pwd->pw_name, 0); |
---|
178 | } |
---|
179 | /* try again */ |
---|
180 | setpwent(); |
---|
181 | } |
---|
182 | #endif |
---|
183 | /* if we can't find the name at all, then use the uid as the name */ |
---|
184 | return(enter_user(uid, itoa7(uid), 1)); |
---|
185 | } |
---|