xref: /onnv-gate/usr/src/cmd/lastcomm/lc_utils.c (revision 4321:a8930ec16e52)
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 **
get_pri_dirs()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
srch_dir(char * path)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
setupdevs()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 *
getdev(dev_t dev)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 *
flagbits(int f)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 *
getname(uid_t uid)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