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
45static int tsize1;
46static struct tlist {
47	char	tname[LSZ];	/* linename */
48	dev_t	tdev;		/* device */
49} tl[TSIZE1];
50
51char	*strncpy();
52dev_t	lintodev();
53
54static char dev_dir[] = "/dev";
55static char *def_srch_dirs[] = {
56	"/dev/term",
57	"/dev/pts",
58	"/dev/xt",
59	NULL
60};
61char file_name[MAX_DEV_PATH];	/* name being returned */
62
63static int srch_dir();
64
65char *
66devtolin(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 */
133static int
134srch_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