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 **
get_pri_dirs()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
srch_dir(char * path)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
setupdevs()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 *
getdev(dev_t dev)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 *
flagbits(int f)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 *
getname(uid_t uid)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