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