lc_utils.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
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
42struct	devhash {
43	dev_t	dev_dev;
44	char	dev_name [PATHNAMLEN];
45	struct	devhash *dev_nxt;
46};
47
48static struct devhash *dev_hash[N_DEVS];
49static struct devhash *dev_chain;
50static int ndevs = NDEVS;
51static struct devhash *hashtab;
52
53/*
54 * Default search list, used if /etc/ttysrch unavailable or unparsable.
55 */
56static char *def_srch_dirs[] = {
57	"/dev/term",
58	"/dev/pts",
59	"/dev/xt",
60	NULL
61};
62static 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 */
81static char **
82get_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 */
151static int
152srch_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
186static void
187setupdevs()
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
217char *
218getdev(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
263char *
264flagbits(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
277char *
278getname(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