xref: /illumos-gate/usr/src/cmd/acct/lib/devtolin.c (revision c9d5afdc)
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 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23 /*	  All Rights Reserved  	*/
24 
25 /*
26  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 /*
31  *	convert device to linename (as in /dev/linename)
32  *	return ptr to LSZ-byte string, "?" if not found
33  *	device must be character device
34  *	maintains small list in tlist structure for speed
35  */
36 
37 #include <stdio.h>
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include "acctdef.h"
41 #include <dirent.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 
45 static int tsize1;
46 static struct tlist {
47 	char	tname[LSZ];	/* linename */
48 	dev_t	tdev;		/* device */
49 } tl[TSIZE1];
50 
51 char	*strncpy();
52 dev_t	lintodev();
53 
54 static char dev_dir[] = "/dev";
55 static char *def_srch_dirs[] = {
56 	"/dev/term",
57 	"/dev/pts",
58 	"/dev/xt",
59 	NULL
60 };
61 char file_name[MAX_DEV_PATH];	/* name being returned */
62 
63 static int srch_dir();
64 
65 char *
devtolin(dev_t device)66 devtolin(dev_t device)
67 {
68 	struct tlist *tp;
69 	char **srch_dirs;	/* priority directories to search first */
70 	int found = 0;
71 	int dirno = 0;
72 
73 	for (tp = tl; tp < &tl[tsize1]; tp++)
74 		if (device == tp->tdev)
75 			return (tp->tname);
76 
77 	srch_dirs = def_srch_dirs;
78 
79 	while ((!found) && (srch_dirs[dirno] != NULL)) {
80 		/*
81 		 * if /dev is one of the priority directories we should only
82 		 * search its top level for now (set depth = MAX_SEARCH_DEPTH)
83 		 */
84 
85 		found = srch_dir(device, srch_dirs[dirno],
86 		    ((strcmp(srch_dirs[dirno], dev_dir) == 0) ?
87 		    MAX_SRCH_DEPTH : 1), NULL);
88 		dirno++;
89 	}
90 
91 	/*
92 	 * if not yet found search remaining /dev directory skipping the
93 	 * priority directories
94 	 */
95 
96 	if (!found)
97 		found = srch_dir(device, dev_dir, 0, srch_dirs);
98 
99 	/*
100 	 * if found then put it (without the "/dev/" prefix) in the tlist
101 	 * structure and return the path name without the "/dev/" prefix
102 	 */
103 
104 	if (found) {
105 		if (tsize1 < TSIZE1) {
106 			tp->tdev = device;
107 			CPYN(tp->tname, file_name+5);
108 			tsize1++;
109 		}
110 		return (file_name+5);
111 	} else {
112 		/*
113 		 * if not found put "?" in the tlist structure for that device
114 		 * and return "?"
115 		 */
116 
117 		if (tsize1 < TSIZE1) {
118 			tp->tdev = device;
119 			CPYN(tp->tname, "?");
120 			tsize1++;
121 		}
122 	}
123 	return ("?");
124 }
125 
126 /*
127  * Arguments:
128  *	device		device we are looking for
129  *	path		current path
130  *	depth		current depth
131  *	skip_dirs	directories that don't need searched
132  */
133 static int
srch_dir(dev_t device,char * path,int depth,char * skip_dirs[])134 srch_dir(dev_t device, char *path, int depth, char *skip_dirs[])
135 {
136 	DIR *fdev;
137 	struct dirent *d;
138 	int dirno = 0;
139 	int found = 0;
140 	int path_len;
141 	char *last_comp;
142 	struct stat sb;
143 
144 	/* do we need to search this directory? */
145 
146 	if ((skip_dirs != NULL) && (depth != 0))
147 		while (skip_dirs[dirno] != NULL)
148 			if (strcmp(skip_dirs[dirno++], path) == 0)
149 				return (0);
150 
151 
152 	/* open the directory */
153 
154 	if ((fdev = opendir(path)) == NULL)
155 		return (0);
156 
157 	/* initialize file name using path name */
158 
159 	path_len = strlen(path);
160 	strcpy(file_name, path);
161 	last_comp = file_name + path_len;
162 	*last_comp++ = '/';
163 
164 	/* start searching this directory */
165 
166 	while ((!found) && ((d = readdir(fdev)) != NULL)) {
167 		if (d->d_ino != 0) {
168 
169 			/*
170 			 * if name would not be too long append it to
171 			 * directory name, otherwise skip this entry
172 			 */
173 
174 			if ((int)(path_len + strlen(d->d_name) + 2) >
175 			    MAX_DEV_PATH)
176 				continue;
177 			else
178 				strcpy(last_comp, d->d_name);
179 
180 			/*
181 			 * if this directory entry has the device number we
182 			 * need, then the name is found. Otherwise if it's a
183 			 * directory (not . or ..) and we haven't gone too
184 			 * deep, recurse.
185 			 */
186 
187 			if (lintodev(file_name+5) == device) {
188 				found = 1;
189 				break;
190 			} else if ((depth < MAX_SRCH_DEPTH) &&
191 			    (strcmp(d->d_name, ".") != 0) &&
192 			    (strcmp(d->d_name, "..") != 0) &&
193 			    (stat(file_name, &sb) != -1) &&
194 			    ((sb.st_mode & S_IFMT) == S_IFDIR)) {
195 				found = srch_dir(device, file_name, depth+1,
196 				    skip_dirs);
197 			}
198 		}
199 	}
200 	closedir(fdev);
201 	return (found);
202 }
203