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