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 };