10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*4321Scasper * Common Development and Distribution License (the "License"). 6*4321Scasper * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 210Sstevel@tonic-gate /* 22*4321Scasper * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23*4321Scasper * Use is subject to license terms. 240Sstevel@tonic-gate */ 250Sstevel@tonic-gate 260Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 270Sstevel@tonic-gate 280Sstevel@tonic-gate #include "lastcomm.h" 290Sstevel@tonic-gate 300Sstevel@tonic-gate /* 310Sstevel@tonic-gate * lc_utils contains utility functions used by both the basic and extended 320Sstevel@tonic-gate * accounting components of lastcomm. getdev(), on its first call, builds 330Sstevel@tonic-gate * the set of tty device name to dev_t mappings. 340Sstevel@tonic-gate */ 350Sstevel@tonic-gate 360Sstevel@tonic-gate #define N_DEVS 43 /* hash value for device names */ 370Sstevel@tonic-gate #define NDEVS 500 /* max number of file names in /dev */ 380Sstevel@tonic-gate 390Sstevel@tonic-gate #define HASH(d) (((int)d) % N_DEVS) /* hash function */ 400Sstevel@tonic-gate 410Sstevel@tonic-gate struct devhash { 420Sstevel@tonic-gate dev_t dev_dev; 430Sstevel@tonic-gate char dev_name [PATHNAMLEN]; 440Sstevel@tonic-gate struct devhash *dev_nxt; 450Sstevel@tonic-gate }; 460Sstevel@tonic-gate 470Sstevel@tonic-gate static struct devhash *dev_hash[N_DEVS]; 480Sstevel@tonic-gate static struct devhash *dev_chain; 490Sstevel@tonic-gate static int ndevs = NDEVS; 500Sstevel@tonic-gate static struct devhash *hashtab; 510Sstevel@tonic-gate 520Sstevel@tonic-gate /* 530Sstevel@tonic-gate * Default search list, used if /etc/ttysrch unavailable or unparsable. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate static char *def_srch_dirs[] = { 560Sstevel@tonic-gate "/dev/term", 570Sstevel@tonic-gate "/dev/pts", 580Sstevel@tonic-gate "/dev/xt", 590Sstevel@tonic-gate NULL 600Sstevel@tonic-gate }; 610Sstevel@tonic-gate static char *raw_sf; /* buffer containing raw image of the search file */ 620Sstevel@tonic-gate 630Sstevel@tonic-gate #define SRCH_FILE_NAME "/etc/ttysrch" 640Sstevel@tonic-gate /* 650Sstevel@tonic-gate * /etc/ttysrch tokens. 660Sstevel@tonic-gate */ 670Sstevel@tonic-gate #define COMMENT_CHAR '#' 680Sstevel@tonic-gate #define EOLN '\n' 690Sstevel@tonic-gate /* 700Sstevel@tonic-gate * /etc/ttysrch parser states. 710Sstevel@tonic-gate */ 720Sstevel@tonic-gate #define START_STATE 1 730Sstevel@tonic-gate #define COMMENT_STATE 2 740Sstevel@tonic-gate #define DIRNAME_STATE 3 750Sstevel@tonic-gate 760Sstevel@tonic-gate /* 770Sstevel@tonic-gate * The following 2 routines are modified version of get_pri_dirs 780Sstevel@tonic-gate * and srch_dir in ttyname.c. 790Sstevel@tonic-gate */ 800Sstevel@tonic-gate static char ** 810Sstevel@tonic-gate get_pri_dirs() 820Sstevel@tonic-gate { 830Sstevel@tonic-gate int bcount = 0; 840Sstevel@tonic-gate int c; 850Sstevel@tonic-gate int sf_lines = 0; /* number of lines in search file */ 860Sstevel@tonic-gate int dirno = 0; 870Sstevel@tonic-gate int state; 880Sstevel@tonic-gate FILE *sf; 890Sstevel@tonic-gate char **pri_dirs; /* priority search list */ 900Sstevel@tonic-gate char *sfp; /* pointer inside the raw image buffer */ 910Sstevel@tonic-gate struct stat sfsb; /* search file's stat structure buffer */ 920Sstevel@tonic-gate 930Sstevel@tonic-gate 940Sstevel@tonic-gate if ((sf = fopen(SRCH_FILE_NAME, "r")) == NULL) 950Sstevel@tonic-gate return (def_srch_dirs); 960Sstevel@tonic-gate if (stat(SRCH_FILE_NAME, &sfsb) < 0) { 970Sstevel@tonic-gate (void) fclose(sf); 980Sstevel@tonic-gate return (def_srch_dirs); 990Sstevel@tonic-gate } 1000Sstevel@tonic-gate raw_sf = malloc(sfsb.st_size + 1); 1010Sstevel@tonic-gate sfp = raw_sf; 1020Sstevel@tonic-gate while ((bcount++ < sfsb.st_size) && ((c = getc(sf)) != EOF)) { 1030Sstevel@tonic-gate *sfp++ = (char)c; 1040Sstevel@tonic-gate if (c == EOLN) 1050Sstevel@tonic-gate sf_lines++; 1060Sstevel@tonic-gate } 1070Sstevel@tonic-gate (void) fclose(sf); 1080Sstevel@tonic-gate *sfp = EOLN; 1090Sstevel@tonic-gate pri_dirs = malloc(++sf_lines * sizeof (char *)); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate sfp = raw_sf; 1120Sstevel@tonic-gate state = START_STATE; 1130Sstevel@tonic-gate while (--bcount) { 1140Sstevel@tonic-gate switch (state) { 1150Sstevel@tonic-gate case START_STATE: 1160Sstevel@tonic-gate if (*sfp == COMMENT_CHAR) { 1170Sstevel@tonic-gate state = COMMENT_STATE; 1180Sstevel@tonic-gate } else if (!isspace(*sfp)) { 1190Sstevel@tonic-gate state = DIRNAME_STATE; 1200Sstevel@tonic-gate pri_dirs[dirno++] = sfp; 1210Sstevel@tonic-gate } 1220Sstevel@tonic-gate break; 1230Sstevel@tonic-gate case COMMENT_STATE: 1240Sstevel@tonic-gate if (*sfp == EOLN) 1250Sstevel@tonic-gate state = START_STATE; 1260Sstevel@tonic-gate break; 1270Sstevel@tonic-gate case DIRNAME_STATE: 1280Sstevel@tonic-gate if (*sfp == EOLN) { 1290Sstevel@tonic-gate *sfp = '\0'; 1300Sstevel@tonic-gate state = START_STATE; 1310Sstevel@tonic-gate } else if (isspace(*sfp)) { 1320Sstevel@tonic-gate *sfp = '\0'; 1330Sstevel@tonic-gate state = COMMENT_STATE; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate break; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate } /* switch */ 1380Sstevel@tonic-gate sfp++; 1390Sstevel@tonic-gate } 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate *sfp = '\0'; 1420Sstevel@tonic-gate pri_dirs[dirno] = NULL; 1430Sstevel@tonic-gate return (pri_dirs); 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* 1470Sstevel@tonic-gate * Build a chain of character devices in dev_chain, starting with the given 1480Sstevel@tonic-gate * path. 1490Sstevel@tonic-gate */ 1500Sstevel@tonic-gate static int 1510Sstevel@tonic-gate srch_dir(char *path) 1520Sstevel@tonic-gate { 1530Sstevel@tonic-gate DIR *dirp; 1540Sstevel@tonic-gate struct dirent *direntp; 1550Sstevel@tonic-gate struct stat st; 1560Sstevel@tonic-gate char file_name[PATHNAMLEN]; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate if ((dirp = opendir(path)) == NULL) 1590Sstevel@tonic-gate return (0); 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate if ((readdir(dirp) == NULL) || (readdir(dirp) == NULL)) 1620Sstevel@tonic-gate return (0); 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate while ((direntp = readdir(dirp)) != NULL) { 1650Sstevel@tonic-gate (void) strcpy(file_name, path); 1660Sstevel@tonic-gate (void) strcat(file_name, "/"); 1670Sstevel@tonic-gate (void) strcat(file_name, direntp->d_name); 1680Sstevel@tonic-gate if (stat((const char *)file_name, &st) < 0) 1690Sstevel@tonic-gate continue; 1700Sstevel@tonic-gate if ((st.st_mode & S_IFMT) == S_IFCHR) { 1710Sstevel@tonic-gate (void) strcpy(hashtab->dev_name, 1720Sstevel@tonic-gate file_name + strlen("/dev/")); 1730Sstevel@tonic-gate hashtab->dev_nxt = dev_chain; 1740Sstevel@tonic-gate dev_chain = hashtab; 1750Sstevel@tonic-gate hashtab++; 1760Sstevel@tonic-gate if (--ndevs < 0) 1770Sstevel@tonic-gate return (-1); 1780Sstevel@tonic-gate } 1790Sstevel@tonic-gate } 1800Sstevel@tonic-gate (void) closedir(dirp); 1810Sstevel@tonic-gate return (1); 1820Sstevel@tonic-gate } 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate static void 1860Sstevel@tonic-gate setupdevs() 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate int dirno = 0; 1890Sstevel@tonic-gate char **srch_dirs; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate hashtab = malloc(NDEVS * sizeof (struct devhash)); 1920Sstevel@tonic-gate if (hashtab == NULL) { 1930Sstevel@tonic-gate (void) fprintf(stderr, gettext("No memory for device table\n")); 1940Sstevel@tonic-gate return; 1950Sstevel@tonic-gate } 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate srch_dirs = get_pri_dirs(); 1980Sstevel@tonic-gate 1990Sstevel@tonic-gate while (srch_dirs[dirno] != NULL) { 2000Sstevel@tonic-gate if (srch_dir(srch_dirs[dirno]) < 0) 2010Sstevel@tonic-gate return; 2020Sstevel@tonic-gate dirno++; 2030Sstevel@tonic-gate } 2040Sstevel@tonic-gate 2050Sstevel@tonic-gate dirno = 0; 2060Sstevel@tonic-gate while (srch_dirs[dirno] != NULL) { 2070Sstevel@tonic-gate if (strcmp("/dev", srch_dirs[dirno]) == 0) 2080Sstevel@tonic-gate /* 2090Sstevel@tonic-gate * Don't search /dev twice. 2100Sstevel@tonic-gate */ 2110Sstevel@tonic-gate return; 2120Sstevel@tonic-gate dirno++; 2130Sstevel@tonic-gate } 2140Sstevel@tonic-gate } 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate char * 2170Sstevel@tonic-gate getdev(dev_t dev) 2180Sstevel@tonic-gate { 2190Sstevel@tonic-gate struct devhash *hp, *nhp; 2200Sstevel@tonic-gate struct stat statb; 2210Sstevel@tonic-gate char name[PATHNAMLEN]; 2220Sstevel@tonic-gate static dev_t lastdev = (dev_t)-1; 2230Sstevel@tonic-gate static char *lastname; 2240Sstevel@tonic-gate static int init = 0; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if (dev == NODEV) 2270Sstevel@tonic-gate return ("__"); 2280Sstevel@tonic-gate if (dev == lastdev) 2290Sstevel@tonic-gate return (lastname); 2300Sstevel@tonic-gate if (!init) { 2310Sstevel@tonic-gate setupdevs(); 2320Sstevel@tonic-gate init++; 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate 2350Sstevel@tonic-gate for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt) 2360Sstevel@tonic-gate if (hp->dev_dev == dev) { 2370Sstevel@tonic-gate lastdev = dev; 2380Sstevel@tonic-gate return (lastname = hp->dev_name); 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate for (hp = dev_chain; hp; hp = nhp) { 2420Sstevel@tonic-gate nhp = hp->dev_nxt; 2430Sstevel@tonic-gate (void) strcpy(name, "/dev/"); 2440Sstevel@tonic-gate (void) strcat(name, hp->dev_name); 2450Sstevel@tonic-gate if (stat(name, &statb) < 0) /* name truncated usually */ 2460Sstevel@tonic-gate continue; 2470Sstevel@tonic-gate if ((statb.st_mode & S_IFMT) != S_IFCHR) 2480Sstevel@tonic-gate continue; 2490Sstevel@tonic-gate hp->dev_dev = statb.st_rdev; 2500Sstevel@tonic-gate hp->dev_nxt = dev_hash[HASH(hp->dev_dev)]; 2510Sstevel@tonic-gate dev_hash[HASH(hp->dev_dev)] = hp; 2520Sstevel@tonic-gate if (hp->dev_dev == dev) { 2530Sstevel@tonic-gate dev_chain = nhp; 2540Sstevel@tonic-gate lastdev = dev; 2550Sstevel@tonic-gate return (lastname = hp->dev_name); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate } 2580Sstevel@tonic-gate dev_chain = NULL; 2590Sstevel@tonic-gate return ("??"); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate char * 2630Sstevel@tonic-gate flagbits(int f) 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate int i = 0; 2660Sstevel@tonic-gate static char flags[20]; 2670Sstevel@tonic-gate 2680Sstevel@tonic-gate #define BIT(flag, ch) flags[i++] = (f & flag) ? ch : ' ' 2690Sstevel@tonic-gate BIT(ASU, 'S'); 2700Sstevel@tonic-gate BIT(AFORK, 'F'); 2710Sstevel@tonic-gate flags[i] = '\0'; 2720Sstevel@tonic-gate return (flags); 2730Sstevel@tonic-gate #undef BIT 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate 2760Sstevel@tonic-gate char * 2770Sstevel@tonic-gate getname(uid_t uid) 2780Sstevel@tonic-gate { 2790Sstevel@tonic-gate struct passwd *pw; 2800Sstevel@tonic-gate static char uidname[NMAX]; 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate if ((pw = getpwuid(uid)) == NULL) { 283*4321Scasper (void) sprintf(uidname, "%u", uid); 2840Sstevel@tonic-gate return (uidname); 2850Sstevel@tonic-gate } 2860Sstevel@tonic-gate return (pw->pw_name); 2870Sstevel@tonic-gate } 288