1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright (c) 1999-2000 by Sun Microsystems, Inc. 24 * All rights reserved. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lastcomm.h" 30 31 /* 32 * lc_utils contains utility functions used by both the basic and extended 33 * accounting components of lastcomm. getdev(), on its first call, builds 34 * the set of tty device name to dev_t mappings. 35 */ 36 37 #define N_DEVS 43 /* hash value for device names */ 38 #define NDEVS 500 /* max number of file names in /dev */ 39 40 #define HASH(d) (((int)d) % N_DEVS) /* hash function */ 41 42 struct devhash { 43 dev_t dev_dev; 44 char dev_name [PATHNAMLEN]; 45 struct devhash *dev_nxt; 46 }; 47 48 static struct devhash *dev_hash[N_DEVS]; 49 static struct devhash *dev_chain; 50 static int ndevs = NDEVS; 51 static struct devhash *hashtab; 52 53 /* 54 * Default search list, used if /etc/ttysrch unavailable or unparsable. 55 */ 56 static char *def_srch_dirs[] = { 57 "/dev/term", 58 "/dev/pts", 59 "/dev/xt", 60 NULL 61 }; 62 static char *raw_sf; /* buffer containing raw image of the search file */ 63 64 #define SRCH_FILE_NAME "/etc/ttysrch" 65 /* 66 * /etc/ttysrch tokens. 67 */ 68 #define COMMENT_CHAR '#' 69 #define EOLN '\n' 70 /* 71 * /etc/ttysrch parser states. 72 */ 73 #define START_STATE 1 74 #define COMMENT_STATE 2 75 #define DIRNAME_STATE 3 76 77 /* 78 * The following 2 routines are modified version of get_pri_dirs 79 * and srch_dir in ttyname.c. 80 */ 81 static char ** 82 get_pri_dirs() 83 { 84 int bcount = 0; 85 int c; 86 int sf_lines = 0; /* number of lines in search file */ 87 int dirno = 0; 88 int state; 89 FILE *sf; 90 char **pri_dirs; /* priority search list */ 91 char *sfp; /* pointer inside the raw image buffer */ 92 struct stat sfsb; /* search file's stat structure buffer */ 93 94 95 if ((sf = fopen(SRCH_FILE_NAME, "r")) == NULL) 96 return (def_srch_dirs); 97 if (stat(SRCH_FILE_NAME, &sfsb) < 0) { 98 (void) fclose(sf); 99 return (def_srch_dirs); 100 } 101 raw_sf = malloc(sfsb.st_size + 1); 102 sfp = raw_sf; 103 while ((bcount++ < sfsb.st_size) && ((c = getc(sf)) != EOF)) { 104 *sfp++ = (char)c; 105 if (c == EOLN) 106 sf_lines++; 107 } 108 (void) fclose(sf); 109 *sfp = EOLN; 110 pri_dirs = malloc(++sf_lines * sizeof (char *)); 111 112 sfp = raw_sf; 113 state = START_STATE; 114 while (--bcount) { 115 switch (state) { 116 case START_STATE: 117 if (*sfp == COMMENT_CHAR) { 118 state = COMMENT_STATE; 119 } else if (!isspace(*sfp)) { 120 state = DIRNAME_STATE; 121 pri_dirs[dirno++] = sfp; 122 } 123 break; 124 case COMMENT_STATE: 125 if (*sfp == EOLN) 126 state = START_STATE; 127 break; 128 case DIRNAME_STATE: 129 if (*sfp == EOLN) { 130 *sfp = '\0'; 131 state = START_STATE; 132 } else if (isspace(*sfp)) { 133 *sfp = '\0'; 134 state = COMMENT_STATE; 135 } 136 break; 137 138 } /* switch */ 139 sfp++; 140 } 141 142 *sfp = '\0'; 143 pri_dirs[dirno] = NULL; 144 return (pri_dirs); 145 } 146 147 /* 148 * Build a chain of character devices in dev_chain, starting with the given 149 * path. 150 */ 151 static int 152 srch_dir(char *path) 153 { 154 DIR *dirp; 155 struct dirent *direntp; 156 struct stat st; 157 char file_name[PATHNAMLEN]; 158 159 if ((dirp = opendir(path)) == NULL) 160 return (0); 161 162 if ((readdir(dirp) == NULL) || (readdir(dirp) == NULL)) 163 return (0); 164 165 while ((direntp = readdir(dirp)) != NULL) { 166 (void) strcpy(file_name, path); 167 (void) strcat(file_name, "/"); 168 (void) strcat(file_name, direntp->d_name); 169 if (stat((const char *)file_name, &st) < 0) 170 continue; 171 if ((st.st_mode & S_IFMT) == S_IFCHR) { 172 (void) strcpy(hashtab->dev_name, 173 file_name + strlen("/dev/")); 174 hashtab->dev_nxt = dev_chain; 175 dev_chain = hashtab; 176 hashtab++; 177 if (--ndevs < 0) 178 return (-1); 179 } 180 } 181 (void) closedir(dirp); 182 return (1); 183 } 184 185 186 static void 187 setupdevs() 188 { 189 int dirno = 0; 190 char **srch_dirs; 191 192 hashtab = malloc(NDEVS * sizeof (struct devhash)); 193 if (hashtab == NULL) { 194 (void) fprintf(stderr, gettext("No memory for device table\n")); 195 return; 196 } 197 198 srch_dirs = get_pri_dirs(); 199 200 while (srch_dirs[dirno] != NULL) { 201 if (srch_dir(srch_dirs[dirno]) < 0) 202 return; 203 dirno++; 204 } 205 206 dirno = 0; 207 while (srch_dirs[dirno] != NULL) { 208 if (strcmp("/dev", srch_dirs[dirno]) == 0) 209 /* 210 * Don't search /dev twice. 211 */ 212 return; 213 dirno++; 214 } 215 } 216 217 char * 218 getdev(dev_t dev) 219 { 220 struct devhash *hp, *nhp; 221 struct stat statb; 222 char name[PATHNAMLEN]; 223 static dev_t lastdev = (dev_t)-1; 224 static char *lastname; 225 static int init = 0; 226 227 if (dev == NODEV) 228 return ("__"); 229 if (dev == lastdev) 230 return (lastname); 231 if (!init) { 232 setupdevs(); 233 init++; 234 } 235 236 for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 237 if (hp->dev_dev == dev) { 238 lastdev = dev; 239 return (lastname = hp->dev_name); 240 } 241 242 for (hp = dev_chain; hp; hp = nhp) { 243 nhp = hp->dev_nxt; 244 (void) strcpy(name, "/dev/"); 245 (void) strcat(name, hp->dev_name); 246 if (stat(name, &statb) < 0) /* name truncated usually */ 247 continue; 248 if ((statb.st_mode & S_IFMT) != S_IFCHR) 249 continue; 250 hp->dev_dev = statb.st_rdev; 251 hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 252 dev_hash[HASH(hp->dev_dev)] = hp; 253 if (hp->dev_dev == dev) { 254 dev_chain = nhp; 255 lastdev = dev; 256 return (lastname = hp->dev_name); 257 } 258 } 259 dev_chain = NULL; 260 return ("??"); 261 } 262 263 char * 264 flagbits(int f) 265 { 266 int i = 0; 267 static char flags[20]; 268 269 #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 270 BIT(ASU, 'S'); 271 BIT(AFORK, 'F'); 272 flags[i] = '\0'; 273 return (flags); 274 #undef BIT 275 } 276 277 char * 278 getname(uid_t uid) 279 { 280 struct passwd *pw; 281 static char uidname[NMAX]; 282 283 if ((pw = getpwuid(uid)) == NULL) { 284 (void) sprintf(uidname, "%ld", uid); 285 return (uidname); 286 } 287 return (pw->pw_name); 288 } 289