username.c revision 24140
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 37struct 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! */ 52struct hash_el hash_table[Table_size]; 53 54init_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 64char *username(uid) 65 66register 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 80int userid(username) 81 82char *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 103int enter_user(uid, name, wecare) 104 105register int uid; 106register char *name; 107int 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 139int get_user(uid) 140 141register 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} 186