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