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