xref: /illumos-gate/usr/src/cmd/lastcomm/lc_utils.c (revision f3041bfa)
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