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 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * when a stat() is done for a non-device file, the devt returned
28 * via the stat is the devt of the device backing the filesystem which
29 * contains the file the stat was performed on. these devts are currently
30 * untranslated. if this turns out to cause problems in the future then
31 * we might want to add more devt translators to convert sd and cmdk
32 * devts into linux devts that normally represent disks.
33 *
34 * XXX this may not be the best place to have the devt translation code.
35 * devt translation will also be needed for /proc fs support, which will
36 * probably be done in the kernel. we may need to move this code into
37 * the kernel and add a brand syscall to do the translation for us. this
38 * will need to be worked out before putback.
39 */
40
41 #include <assert.h>
42 #include <errno.h>
43 #include <stdio.h>
44 #include <strings.h>
45 #include <unistd.h>
46 #include <libintl.h>
47 #include <sys/fcntl.h>
48 #include <sys/stat.h>
49 #include <sys/types.h>
50 #include <sys/lx_types.h>
51 #include <sys/lx_stat.h>
52 #include <sys/lx_misc.h>
53 #include <sys/lx_debug.h>
54 #include <sys/lx_ptm.h>
55 #include <sys/lx_audio.h>
56 #include <sys/lx_fcntl.h>
57 #include <sys/modctl.h>
58
59 /* define _KERNEL to get the devt manipulation macros */
60 #define _KERNEL
61 #include <sys/sysmacros.h>
62 #undef _KERNEL
63
64
65 #define LX_PTS_MAJOR_MIN 136
66 #define LX_PTS_MAJOR_MAX 143
67 #define LX_PTS_MAX \
68 ((LX_PTS_MAJOR_MAX - LX_PTS_MAJOR_MIN + 1) * LX_MINORMASK)
69
70 #define LX_PTM_MAJOR 5
71 #define LX_PTM_MINOR 2
72
73 /* values for dt_type */
74 #define DTT_INVALID 0
75 #define DTT_LIST 1
76 #define DTT_CUSTOM 2
77
78 /* convience macros for access the dt_minor union */
79 #define dt_list dt_minor.dtm_list
80 #define dt_custom dt_minor.dtm_custom
81
82 /*
83 * structure used to define devt translators
84 */
85 typedef struct minor_translator {
86 char *mt_path; /* solaris minor node path */
87 minor_t mt_minor; /* solaris minor node number */
88 int mt_lx_major; /* linux major node number */
89 int mt_lx_minor; /* linux minor node number */
90 } minor_translator_t;
91
92 typedef struct devt_translator {
93 char *dt_driver; /* solaris driver name */
94 major_t dt_major; /* solaris driver number */
95
96 /* dt_type dictates how we intrepret dt_minor */
97 int dt_type;
98 union {
99 uintptr_t dtm_foo; /* required to compile */
100 minor_translator_t *dtm_list;
101 int (*dtm_custom)(dev_t, lx_dev_t *, int);
102 } dt_minor;
103 } devt_translator_t;
104
105
106 /*
107 * forward declerations
108 */
109 static devt_translator_t devt_translators[];
110
111 /*
112 * called to initialize the devt translation subsystem
113 */
114 int
115 lx_stat_init()
116 {
117 minor_translator_t *mt;
118 struct stat st;
119 major_t major;
120 char *driver;
121 int i, j, ret;
122
123 for (i = 0; devt_translators[i].dt_driver != NULL; i++) {
124
125 assert(devt_translators[i].dt_type != DTT_INVALID);
126
127 /* figure out the major numbers for our devt translators */
128 driver = devt_translators[i].dt_driver;
129 ret = modctl(MODGETMAJBIND,
130 driver, strlen(driver) + 1, &major);
131 if (ret != 0) {
132 lx_err(gettext("%s%s) failed: %s\n"),
133 "lx_stat_init(): modctl(MODGETMAJBIND, ",
134 driver, strerror(errno));
135 lx_err(gettext("%s: %s translator disabled for: %s\n"),
136 "lx_stat_init()", "devt", driver);
137 devt_translators[i].dt_major = (major_t)-1;
138 continue;
139 }
140
141 /* save the major node value */
142 devt_translators[i].dt_major = major;
143
144 /* if this translator doesn't use a list mapping we're done. */
145 if (devt_translators[i].dt_type != DTT_LIST)
146 continue;
147
148 /* for each device listed, lookup the minor node number */
149 mt = devt_translators[i].dt_list;
150 for (j = 0; mt[j].mt_path != NULL; j++) {
151
152 /* stat the device */
153 ret = stat(mt[j].mt_path, &st);
154 if (ret != 0) {
155 lx_err(gettext("%s%s) failed: %s\n"),
156 "lx_stat_init(): stat(",
157 mt[j].mt_path, strerror(errno));
158 lx_err(gettext(
159 "%s: %s translator disabled for: %s\n"),
160 "lx_stat_init()", "devt",
161 mt[j].mt_path);
162 st.st_rdev = NODEV;
163 } else {
164 /* make sure the major node matches */
165 assert(getmajor(st.st_rdev) == major);
166 assert(mt[j].mt_minor < LX_MINORMASK);
167 }
168
169 /* save the minor node value */
170 mt[j].mt_minor = getminor(st.st_rdev);
171 }
172 }
173 return (0);
174 }
175
176 static int
177 /*ARGSUSED*/
178 pts_devt_translator(dev_t dev, lx_dev_t *jdev, int fd)
179 {
180 minor_t min = getminor(dev);
181 int lx_maj;
182 int lx_min;
183
184 /*
185 * linux has a really small minor number name space (8 bits).
186 * so if pts devices are limited to one major number you could
187 * only have 256 of them. linux addresses this issue by using
188 * multiple major numbers for pts devices.
189 */
190 if (min >= LX_PTS_MAX)
191 return (EOVERFLOW);
192
193 lx_maj = LX_PTS_MAJOR_MIN + (min / LX_MINORMASK);
194 lx_min = min % LX_MINORMASK;
195
196 *jdev = LX_MAKEDEVICE(lx_maj, lx_min);
197 return (0);
198 }
199
200
201 static int
202 /*ARGSUSED*/
203 ptm_devt_translator(dev_t dev, lx_dev_t *jdev, int fd)
204 {
205 *jdev = LX_MAKEDEVICE(LX_PTM_MAJOR, LX_PTM_MINOR);
206 return (0);
207 }
208
209 static int
210 audio_devt_translator(dev_t dev, lx_dev_t *jdev, int fd)
211 {
212 int s_minor, l_minor;
213
214 if (fd == -1) {
215 s_minor = getminor(dev);
216 } else {
217 /*
218 * this is a cloning device so we have to ask the driver
219 * what kind of minor node this is
220 */
221 if (ioctl(fd, LXA_IOC_GETMINORNUM, &s_minor) < 0)
222 return (-EINVAL);
223 }
224
225 switch (s_minor) {
226 case LXA_MINORNUM_DSP:
227 l_minor = 3;
228 break;
229 case LXA_MINORNUM_MIXER:
230 l_minor = 0;
231 break;
232 default:
233 return (-EINVAL);
234 }
235
236 *jdev = LX_MAKEDEVICE(14, l_minor);
237 return (0);
238 }
239
240 static void
241 s2l_dev_report(dev_t dev, lx_dev_t jdev)
242 {
243 major_t maj;
244 minor_t min;
245 int lx_maj, lx_min;
246
247 if (lx_debug_enabled == 0)
248 return;
249
250 maj = getmajor(dev);
251 min = getminor(dev);
252
253 lx_maj = LX_GETMAJOR(jdev);
254 lx_min = LX_GETMINOR(jdev);
255
256 lx_debug("\ttranslated devt [%d, %d] -> [%d, %d]",
257 maj, min, lx_maj, lx_min);
258 }
259
260 static int
261 s2l_devt(dev_t dev, lx_dev_t *jdev, int fd)
262 {
263 minor_translator_t *mt;
264 int i, j, err;
265 major_t maj = getmajor(dev);
266 minor_t min = getminor(dev);
267
268 /* look for a devt translator for this major number */
269 for (i = 0; devt_translators[i].dt_driver != NULL; i++) {
270 if (devt_translators[i].dt_major == maj)
271 break;
272 }
273 if (devt_translators[i].dt_driver != NULL) {
274
275 /* try to translate the solaris devt to a linux devt */
276 switch (devt_translators[i].dt_type) {
277 case DTT_LIST:
278 mt = devt_translators[i].dt_list;
279 for (j = 0; mt[j].mt_path != NULL; j++) {
280 if (mt[j].mt_minor == min) {
281 assert(mt[j].mt_minor < LX_MINORMASK);
282
283 /* found a translation */
284 *jdev = LX_MAKEDEVICE(
285 mt[j].mt_lx_major,
286 mt[j].mt_lx_minor);
287 s2l_dev_report(dev, *jdev);
288 return (0);
289 }
290 }
291 break;
292
293 case DTT_CUSTOM:
294 err = devt_translators[i].dt_custom(dev, jdev, fd);
295 if (err == 0)
296 s2l_dev_report(dev, *jdev);
297 return (err);
298 break;
299 }
300 }
301
302 /* we don't have a translator for this device */
303 *jdev = LX_MAKEDEVICE(maj, min);
304 return (0);
305 }
306
307 static int
308 stat_convert(uintptr_t lx_statp, struct stat *s, int fd)
309 {
310 struct lx_stat buf;
311 lx_dev_t st_dev, st_rdev;
312 int err;
313
314 if ((err = s2l_devt(s->st_dev, &st_dev, fd)) != 0)
315 return (err);
316 if ((err = s2l_devt(s->st_rdev, &st_rdev, fd)) != 0)
317 return (err);
318
319 if ((st_dev > USHRT_MAX) || (st_rdev > USHRT_MAX) ||
320 (s->st_nlink > USHRT_MAX) || (s->st_size > ULONG_MAX))
321 return (-EOVERFLOW);
322
323 /* Linux seems to report a 0 st_size for all block devices */
324 if ((s->st_mode & S_IFMT) == S_IFBLK)
325 s->st_size = 0;
326
327 bzero(&buf, sizeof (buf));
328 buf.st_dev = st_dev;
329 buf.st_rdev = st_rdev;
330 buf.st_ino = s->st_ino;
331 buf.st_mode = s->st_mode;
332 buf.st_nlink = s->st_nlink;
333 buf.st_uid = LX_UID32_TO_UID16(s->st_uid);
334 buf.st_gid = LX_GID32_TO_GID16(s->st_gid);
335 buf.st_size = s->st_size;
336 buf.st_blksize = s->st_blksize;
337 buf.st_blocks = s->st_blocks;
338 buf.st_atime.ts_sec = s->st_atim.tv_sec;
339 buf.st_atime.ts_nsec = s->st_atim.tv_nsec;
340 buf.st_ctime.ts_sec = s->st_ctim.tv_sec;
341 buf.st_ctime.ts_nsec = s->st_ctim.tv_nsec;
342 buf.st_mtime.ts_sec = s->st_mtim.tv_sec;
343 buf.st_mtime.ts_nsec = s->st_mtim.tv_nsec;
344
345 if (uucopy(&buf, (void *)lx_statp, sizeof (buf)) != 0)
346 return (-errno);
347
348 return (0);
349 }
350
351 static int
352 stat64_convert(uintptr_t lx_statp, struct stat64 *s, int fd)
353 {
354 struct lx_stat64 buf;
355 lx_dev_t st_dev, st_rdev;
356 int err;
357
358 if ((err = s2l_devt(s->st_dev, &st_dev, fd)) != 0)
359 return (err);
360 if ((err = s2l_devt(s->st_rdev, &st_rdev, fd)) != 0)
361 return (err);
362
363 /* Linux seems to report a 0 st_size for all block devices */
364 if ((s->st_mode & S_IFMT) == S_IFBLK)
365 s->st_size = 0;
366
367 bzero(&buf, sizeof (buf));
368 buf.st_dev = st_dev;
369 buf.st_rdev = st_rdev;
370 buf.st_small_ino = (lx_ino_t)(s->st_ino & UINT_MAX);
371 buf.st_ino = (lx_ino64_t)s->st_ino;
372 buf.st_mode = s->st_mode;
373 buf.st_nlink = s->st_nlink;
374 buf.st_uid = s->st_uid;
375 buf.st_gid = s->st_gid;
376 buf.st_size = s->st_size;
377 buf.st_blksize = s->st_blksize;
378 buf.st_blocks = s->st_blocks;
379 buf.st_atime.ts_sec = s->st_atim.tv_sec;
380 buf.st_atime.ts_nsec = s->st_atim.tv_nsec;
381 buf.st_ctime.ts_sec = s->st_ctim.tv_sec;
382 buf.st_ctime.ts_nsec = s->st_ctim.tv_nsec;
383 buf.st_mtime.ts_sec = s->st_mtim.tv_sec;
384 buf.st_mtime.ts_nsec = s->st_mtim.tv_nsec;
385
386 if (uucopy(&buf, (void *)lx_statp, sizeof (buf)) != 0)
387 return (-errno);
388
389 return (0);
390 }
391
392 int
393 lx_stat(uintptr_t p1, uintptr_t p2)
394 {
395 char *path = (char *)p1;
396 struct stat sbuf;
397
398 lx_debug("\tstat(%s, ...)", path);
399 if (stat(path, &sbuf))
400 return (-errno);
401
402 return (stat_convert(p2, &sbuf, -1));
403 }
404
405
406 int
407 lx_fstat(uintptr_t p1, uintptr_t p2)
408 {
409 int fd = (int)p1;
410 struct stat sbuf;
411 char *path, path_buf[MAXPATHLEN];
412
413 if (lx_debug_enabled != 0) {
414 path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
415 if (path == NULL)
416 path = "?";
417
418 lx_debug("\tfstat(%d - %s, ...)", fd, path);
419 }
420 if (fstat(fd, &sbuf))
421 return (-errno);
422
423 return (stat_convert(p2, &sbuf, fd));
424 }
425
426
427 int
428 lx_lstat(uintptr_t p1, uintptr_t p2)
429 {
430 char *path = (char *)p1;
431 struct stat sbuf;
432
433 lx_debug("\tlstat(%s, ...)", path);
434 if (lstat(path, &sbuf))
435 return (-errno);
436
437 return (stat_convert(p2, &sbuf, -1));
438 }
439
440 int
441 lx_stat64(uintptr_t p1, uintptr_t p2)
442 {
443 char *path = (char *)p1;
444 struct stat64 sbuf;
445
446 lx_debug("\tstat64(%s, ...)", path);
447 if (stat64(path, &sbuf))
448 return (-errno);
449
450 return (stat64_convert(p2, &sbuf, -1));
451 }
452
453
454 int
455 lx_fstat64(uintptr_t p1, uintptr_t p2)
456 {
457 int fd = (int)p1;
458 struct stat64 sbuf;
459 char *path, path_buf[MAXPATHLEN];
460
461 if (lx_debug_enabled != 0) {
462 path = lx_fd_to_path(fd, path_buf, sizeof (path_buf));
463 if (path == NULL)
464 path = "?";
465
466 lx_debug("\tfstat64(%d - %s, ...)", fd, path);
467 }
468 if (fstat64(fd, &sbuf))
469 return (-errno);
470
471 return (stat64_convert(p2, &sbuf, fd));
472 }
473
474 int
475 lx_fstatat64(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
476 {
477 int atfd = (int)p1;
478 const char *path = (const char *)p2;
479 int flag;
480 struct stat64 sbuf;
481
482 if (atfd == LX_AT_FDCWD)
483 atfd = AT_FDCWD;
484
485 flag = ltos_at_flag(p4, AT_SYMLINK_NOFOLLOW);
486 if (flag < 0)
487 return (-EINVAL);
488
489 if (fstatat64(atfd, path, &sbuf, flag))
490 return (-errno);
491
492 return (stat64_convert(p3, &sbuf, -1));
493 }
494
495
496 int
497 lx_lstat64(uintptr_t p1, uintptr_t p2)
498 {
499 char *path = (char *)p1;
500 struct stat64 sbuf;
501
502 lx_debug("\tlstat64(%s, ...)", path);
503 if (lstat64(path, &sbuf))
504 return (-errno);
505
506 return (stat64_convert(p2, &sbuf, -1));
507 }
508
509 /*
510 * devt translator definitions
511 */
512 #define MINOR_TRANSLATOR(path, lx_major, lx_minor) \
513 { path, 0, lx_major, lx_minor }
514
515 #define MINOR_TRANSLATOR_END \
516 { NULL, 0, 0, 0 }
517
518 #define DEVT_TRANSLATOR(drv, flags, i) \
519 { drv, 0, flags, (uintptr_t)i }
520
521 /*
522 * translators for devts
523 */
524 static minor_translator_t mtranslator_mm[] = {
525 MINOR_TRANSLATOR("/dev/null", 1, 3),
526 MINOR_TRANSLATOR("/dev/zero", 1, 5),
527 MINOR_TRANSLATOR_END
528 };
529 static minor_translator_t mtranslator_random[] = {
530 MINOR_TRANSLATOR("/dev/random", 1, 8),
531 MINOR_TRANSLATOR("/dev/urandom", 1, 9),
532 MINOR_TRANSLATOR_END
533 };
534 static minor_translator_t mtranslator_sy[] = {
535 MINOR_TRANSLATOR("/dev/tty", 5, 0),
536 MINOR_TRANSLATOR_END
537 };
538 static minor_translator_t mtranslator_zcons[] = {
539 MINOR_TRANSLATOR("/dev/console", 5, 1),
540 MINOR_TRANSLATOR_END
541 };
542 static devt_translator_t devt_translators[] = {
543 DEVT_TRANSLATOR("mm", DTT_LIST, &mtranslator_mm),
544 DEVT_TRANSLATOR("random", DTT_LIST, &mtranslator_random),
545 DEVT_TRANSLATOR("sy", DTT_LIST, &mtranslator_sy),
546 DEVT_TRANSLATOR("zcons", DTT_LIST, &mtranslator_zcons),
547 DEVT_TRANSLATOR(LX_AUDIO_DRV, DTT_CUSTOM, audio_devt_translator),
548 DEVT_TRANSLATOR(LX_PTM_DRV, DTT_CUSTOM, ptm_devt_translator),
549 DEVT_TRANSLATOR("pts", DTT_CUSTOM, pts_devt_translator),
550 DEVT_TRANSLATOR(NULL, 0, 0)
551 };