xref: /freebsd/sys/compat/linux/linux_util.c (revision 776fc0e90e9072cda064b69e91a6a0e6bede1aa1)
1 /*-
2  * Copyright (c) 1994 Christos Zoulas
3  * Copyright (c) 1995 Frank van der Linden
4  * Copyright (c) 1995 Scott Bartram
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *	from: svr4_util.c,v 1.5 1995/01/22 23:44:50 christos Exp
30  */
31 
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34 
35 #include <sys/param.h>
36 #include <sys/bus.h>
37 #include <sys/lock.h>
38 #include <sys/malloc.h>
39 #include <sys/linker_set.h>
40 #include <sys/mutex.h>
41 #include <sys/namei.h>
42 #include <sys/proc.h>
43 #include <sys/syscallsubr.h>
44 #include <sys/systm.h>
45 #include <sys/vnode.h>
46 
47 #include <machine/stdarg.h>
48 
49 #include <compat/linux/linux_util.h>
50 
51 const char      linux_emul_path[] = "/compat/linux";
52 
53 /*
54  * Search an alternate path before passing pathname arguments on
55  * to system calls. Useful for keeping a separate 'emulation tree'.
56  *
57  * If cflag is set, we check if an attempt can be made to create
58  * the named file, i.e. we check if the directory it should
59  * be in exists.
60  */
61 int
62 linux_emul_convpath(td, path, pathseg, pbuf, cflag)
63 	struct thread	 *td;
64 	char		 *path;
65 	enum uio_seg	  pathseg;
66 	char		**pbuf;
67 	int		  cflag;
68 {
69 
70 	return (kern_alternate_path(td, linux_emul_path, path, pathseg, pbuf,
71 		cflag));
72 }
73 
74 void
75 linux_msg(const struct thread *td, const char *fmt, ...)
76 {
77 	va_list ap;
78 	struct proc *p;
79 
80 	p = td->td_proc;
81 	printf("linux: pid %d (%s): ", (int)p->p_pid, p->p_comm);
82 	va_start(ap, fmt);
83 	vprintf(fmt, ap);
84 	va_end(ap);
85 	printf("\n");
86 }
87 
88 MALLOC_DECLARE(M_LINUX);
89 
90 struct device_element
91 {
92 	TAILQ_ENTRY(device_element) list;
93 	struct linux_device_handler entry;
94 };
95 
96 static TAILQ_HEAD(, device_element) devices =
97 	TAILQ_HEAD_INITIALIZER(devices);
98 
99 static struct linux_device_handler null_handler =
100 	{ "mem", "mem", "null", "null", 1, 3, 1};
101 
102 DATA_SET(linux_device_handler_set, null_handler);
103 
104 char *
105 linux_driver_get_name_dev(device_t dev)
106 {
107 	struct device_element *de;
108 	const char *device_name = device_get_name(dev);
109 
110 	if (device_name == NULL)
111 		return NULL;
112 	TAILQ_FOREACH(de, &devices, list) {
113 		if (strcmp(device_name, de->entry.bsd_driver_name) == 0)
114 			return (de->entry.linux_driver_name);
115 	}
116 
117 	return NULL;
118 }
119 
120 int
121 linux_driver_get_major_minor(char *node, int *major, int *minor)
122 {
123 	struct device_element *de;
124 
125 	if (node == NULL || major == NULL || minor == NULL)
126 		return 1;
127 	TAILQ_FOREACH(de, &devices, list) {
128 		if (strcmp(node, de->entry.bsd_device_name) == 0) {
129 			*major = de->entry.linux_major;
130 			*minor = de->entry.linux_minor;
131 			return 0;
132 		}
133 	}
134 
135 	return 1;
136 }
137 
138 char *
139 linux_get_char_devices()
140 {
141 	struct device_element *de;
142 	char *temp, *string, *last;
143 	char formated[256];
144 	int current_size = 0, string_size = 1024;
145 
146 	MALLOC(string, char *, string_size, M_LINUX, M_WAITOK);
147 	string[0] = '\000';
148 	last = "";
149 	TAILQ_FOREACH(de, &devices, list) {
150 		if (!de->entry.linux_char_device)
151 			continue;
152 		temp = string;
153 		if (strcmp(last, de->entry.bsd_driver_name) != 0) {
154 			last = de->entry.bsd_driver_name;
155 
156 			snprintf(formated, sizeof(formated), "%3d %s\n",
157 				 de->entry.linux_major,
158 				 de->entry.linux_device_name);
159 			if (strlen(formated) + current_size
160 			    >= string_size) {
161 				string_size *= 2;
162 				MALLOC(string, char *, string_size,
163 				    M_LINUX, M_WAITOK);
164 				bcopy(temp, string, current_size);
165 				FREE(temp, M_LINUX);
166 			}
167 			strcat(string, formated);
168 			current_size = strlen(string);
169 		}
170 	}
171 
172 	return string;
173 }
174 
175 void
176 linux_free_get_char_devices(char *string)
177 {
178 	FREE(string, M_LINUX);
179 }
180 
181 static int linux_major_starting = 200;
182 
183 int
184 linux_device_register_handler(struct linux_device_handler *d)
185 {
186 	struct device_element *de;
187 
188 	if (d == NULL)
189 		return (EINVAL);
190 
191 	MALLOC(de, struct device_element *, sizeof(*de),
192 	    M_LINUX, M_WAITOK);
193 	if (d->linux_major < 0) {
194 		d->linux_major = linux_major_starting++;
195 	}
196 	bcopy(d, &de->entry, sizeof(*d));
197 
198 	/* Add the element to the list, sorted on span. */
199 	TAILQ_INSERT_TAIL(&devices, de, list);
200 
201 	return (0);
202 }
203 
204 int
205 linux_device_unregister_handler(struct linux_device_handler *d)
206 {
207 	struct device_element *de;
208 
209 	if (d == NULL)
210 		return (EINVAL);
211 
212 	TAILQ_FOREACH(de, &devices, list) {
213 		if (bcmp(d, &de->entry, sizeof(*d)) == 0) {
214 			TAILQ_REMOVE(&devices, de, list);
215 			FREE(de, M_LINUX);
216 			return (0);
217 		}
218 	}
219 
220 	return (EINVAL);
221 }
222