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