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