xref: /illumos-gate/usr/src/cmd/lastcomm/lc_utils.c (revision 86d949f9497332fe19be6b5d711d265eb957439f)
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 #include "lastcomm.h"
27 
28 /*
29  * lc_utils contains utility functions used by both the basic and extended
30  * accounting components of lastcomm.  getdev(), on its first call, builds
31  * the set of tty device name to dev_t mappings.
32  */
33 
34 #define	N_DEVS		43		/* hash value for device names */
35 #define	NDEVS		500		/* max number of file names in /dev */
36 
37 #define	HASH(d)	(((int)d) % N_DEVS)	/* hash function */
38 
39 struct	devhash {
40 	dev_t	dev_dev;
41 	char	dev_name [PATHNAMLEN];
42 	struct	devhash *dev_nxt;
43 };
44 
45 static struct devhash *dev_hash[N_DEVS];
46 static struct devhash *dev_chain;
47 static int ndevs = NDEVS;
48 static struct devhash *hashtab;
49 
50 /*
51  * Default search list, used if /etc/ttysrch unavailable or unparsable.
52  */
53 static char *def_srch_dirs[] = {
54 	"/dev/term",
55 	"/dev/pts",
56 	"/dev/xt",
57 	NULL
58 };
59 static char *raw_sf;	/* buffer containing raw image of the search file */
60 
61 #define	SRCH_FILE_NAME  "/etc/ttysrch"
62 /*
63  * /etc/ttysrch tokens.
64  */
65 #define	COMMENT_CHAR    '#'
66 #define	EOLN		'\n'
67 /*
68  * /etc/ttysrch parser states.
69  */
70 #define	START_STATE	1
71 #define	COMMENT_STATE   2
72 #define	DIRNAME_STATE   3
73 
74 /*
75  * The following 2 routines are modified version of get_pri_dirs
76  * and srch_dir in ttyname.c.
77  */
78 static char **
79 get_pri_dirs()
80 {
81 	int bcount = 0;
82 	int c;
83 	int sf_lines = 0;	/* number of lines in search file */
84 	int dirno = 0;
85 	int state;
86 	FILE *sf;
87 	char **pri_dirs;	/* priority search list */
88 	char *sfp;		/* pointer inside the raw image buffer */
89 	struct stat sfsb;	/* search file's stat structure buffer */
90 
91 
92 	if ((sf = fopen(SRCH_FILE_NAME, "r")) == NULL)
93 		return (def_srch_dirs);
94 	if (stat(SRCH_FILE_NAME, &sfsb) < 0) {
95 		(void) fclose(sf);
96 		return (def_srch_dirs);
97 	}
98 	raw_sf = malloc(sfsb.st_size + 1);
99 	sfp = raw_sf;
100 	while ((bcount++ < sfsb.st_size) && ((c = getc(sf)) != EOF)) {
101 		*sfp++ = (char)c;
102 		if (c == EOLN)
103 			sf_lines++;
104 	}
105 	(void) fclose(sf);
106 	*sfp = EOLN;
107 	pri_dirs = malloc(++sf_lines * sizeof (char *));
108 
109 	sfp = raw_sf;
110 	state = START_STATE;
111 	while (--bcount) {
112 		switch (state) {
113 		case START_STATE:
114 			if (*sfp == COMMENT_CHAR) {
115 				state = COMMENT_STATE;
116 			} else if (!isspace(*sfp)) {
117 				state = DIRNAME_STATE;
118 				pri_dirs[dirno++] = sfp;
119 			}
120 			break;
121 		case COMMENT_STATE:
122 			if (*sfp == EOLN)
123 				state = START_STATE;
124 			break;
125 		case DIRNAME_STATE:
126 			if (*sfp == EOLN) {
127 				*sfp = '\0';
128 				state = START_STATE;
129 			} else if (isspace(*sfp)) {
130 				*sfp = '\0';
131 				state = COMMENT_STATE;
132 			}
133 			break;
134 
135 		} /* switch */
136 		sfp++;
137 	}
138 
139 	*sfp = '\0';
140 	pri_dirs[dirno] = NULL;
141 	return (pri_dirs);
142 }
143 
144 /*
145  * Build a chain of character devices in dev_chain, starting with the given
146  * path.
147  */
148 static int
149 srch_dir(char *path)
150 {
151 	DIR *dirp;
152 	struct dirent *direntp;
153 	struct stat st;
154 	char file_name[PATHNAMLEN];
155 
156 	if ((dirp = opendir(path)) == NULL)
157 		return (0);
158 
159 	if ((readdir(dirp) == NULL) || (readdir(dirp) == NULL))
160 		return (0);
161 
162 	while ((direntp = readdir(dirp)) != NULL) {
163 		(void) strcpy(file_name, path);
164 		(void) strcat(file_name, "/");
165 		(void) strcat(file_name, direntp->d_name);
166 		if (stat((const char *)file_name, &st) < 0)
167 			continue;
168 		if ((st.st_mode & S_IFMT) == S_IFCHR) {
169 			(void) strcpy(hashtab->dev_name,
170 			    file_name + strlen("/dev/"));
171 			hashtab->dev_nxt = dev_chain;
172 			dev_chain = hashtab;
173 			hashtab++;
174 			if (--ndevs < 0)
175 				return (-1);
176 		}
177 	}
178 	(void) closedir(dirp);
179 	return (1);
180 }
181 
182 
183 static void
184 setupdevs()
185 {
186 	int dirno = 0;
187 	char **srch_dirs;
188 
189 	hashtab = malloc(NDEVS * sizeof (struct devhash));
190 	if (hashtab == NULL) {
191 		(void) fprintf(stderr, gettext("No memory for device table\n"));
192 		return;
193 	}
194 
195 	srch_dirs = get_pri_dirs();
196 
197 	while (srch_dirs[dirno] != NULL) {
198 		if (srch_dir(srch_dirs[dirno]) < 0)
199 			return;
200 		dirno++;
201 	}
202 
203 	dirno = 0;
204 	while (srch_dirs[dirno] != NULL) {
205 		if (strcmp("/dev", srch_dirs[dirno]) == 0)
206 			/*
207 			 * Don't search /dev twice.
208 			 */
209 			return;
210 		dirno++;
211 	}
212 }
213 
214 char *
215 getdev(dev_t dev)
216 {
217 	struct devhash *hp, *nhp;
218 	struct stat statb;
219 	char name[PATHNAMLEN];
220 	static dev_t lastdev = (dev_t)-1;
221 	static char *lastname;
222 	static int init = 0;
223 
224 	if (dev == NODEV)
225 		return ("__");
226 	if (dev == lastdev)
227 		return (lastname);
228 	if (!init) {
229 		setupdevs();
230 		init++;
231 	}
232 
233 	for (hp = dev_hash[HASH(dev)]; hp; hp = hp->dev_nxt)
234 		if (hp->dev_dev == dev) {
235 			lastdev = dev;
236 			return (lastname = hp->dev_name);
237 		}
238 
239 	for (hp = dev_chain; hp; hp = nhp) {
240 		nhp = hp->dev_nxt;
241 		(void) strcpy(name, "/dev/");
242 		(void) strcat(name, hp->dev_name);
243 		if (stat(name, &statb) < 0)	/* name truncated usually */
244 			continue;
245 		if ((statb.st_mode & S_IFMT) != S_IFCHR)
246 			continue;
247 		hp->dev_dev = statb.st_rdev;
248 		hp->dev_nxt = dev_hash[HASH(hp->dev_dev)];
249 		dev_hash[HASH(hp->dev_dev)] = hp;
250 		if (hp->dev_dev == dev) {
251 			dev_chain = nhp;
252 			lastdev = dev;
253 			return (lastname = hp->dev_name);
254 		}
255 	}
256 	dev_chain = NULL;
257 	return ("??");
258 }
259 
260 char *
261 flagbits(int f)
262 {
263 	int i = 0;
264 	static char flags[20];
265 
266 #define	BIT(flag, ch)	flags[i++] = (f & flag) ? ch : ' '
267 	BIT(ASU, 'S');
268 	BIT(AFORK, 'F');
269 	flags[i] = '\0';
270 	return (flags);
271 #undef	BIT
272 }
273 
274 char *
275 getname(uid_t uid)
276 {
277 	struct passwd *pw;
278 	static char uidname[NMAX];
279 
280 	if ((pw = getpwuid(uid)) == NULL) {
281 		(void) sprintf(uidname, "%u", uid);
282 		return (uidname);
283 	}
284 	return (pw->pw_name);
285 }
286