* Determine if there is a suitable alternate filename under the specified * prefix for the specified path. If the create flag is set, then the * alternate prefix will be used so long as the parent directory exists. * This is used by the various compatibility ABIs so that Linux binaries prefer * files under /compat/linux for example. The chosen path (whether under * the prefix or under /) is
| 1601 | * the M_TEMP bucket if one is returned. |
| 1602 | */ |
| 1603 | int |
| 1604 | kern_alternate_path(struct thread *td, const char *prefix, const char *path, |
| 1605 | enum uio_seg pathseg, char **pathbuf, int create, int dirfd) |
| 1606 | { |
| 1607 | struct nameidata nd, ndroot; |
| 1608 | char *ptr, *buf, *cp; |
| 1609 | size_t len, sz; |
| 1610 | int error; |
| 1611 | |
| 1612 | buf = (char *) malloc(MAXPATHLEN, M_TEMP, M_WAITOK); |
| 1613 | *pathbuf = buf; |
| 1614 | |
| 1615 | /* Copy the prefix into the new pathname as a starting point. */ |
| 1616 | len = strlcpy(buf, prefix, MAXPATHLEN); |
| 1617 | if (len >= MAXPATHLEN) { |
| 1618 | *pathbuf = NULL; |
| 1619 | free(buf, M_TEMP); |
| 1620 | return (EINVAL); |
| 1621 | } |
| 1622 | sz = MAXPATHLEN - len; |
| 1623 | ptr = buf + len; |
| 1624 | |
| 1625 | /* Append the filename to the prefix. */ |
| 1626 | if (pathseg == UIO_SYSSPACE) |
| 1627 | error = copystr(path, ptr, sz, &len); |
| 1628 | else |
| 1629 | error = copyinstr(path, ptr, sz, &len); |
| 1630 | |
| 1631 | if (error) { |
| 1632 | *pathbuf = NULL; |
| 1633 | free(buf, M_TEMP); |
| 1634 | return (error); |
| 1635 | } |
| 1636 | |
| 1637 | /* Only use a prefix with absolute pathnames. */ |
| 1638 | if (*ptr != '/') { |
| 1639 | error = EINVAL; |
| 1640 | goto keeporig; |
| 1641 | } |
| 1642 | |
| 1643 | if (dirfd != AT_FDCWD) { |
| 1644 | /* |
| 1645 | * We want the original because the "prefix" is |
| 1646 | * included in the already opened dirfd. |
| 1647 | */ |
| 1648 | bcopy(ptr, buf, len); |
| 1649 | return (0); |
| 1650 | } |
| 1651 | |
| 1652 | /* |
| 1653 | * We know that there is a / somewhere in this pathname. |
| 1654 | * Search backwards for it, to find the file's parent dir |
| 1655 | * to see if it exists in the alternate tree. If it does, |
| 1656 | * and we want to create a file (cflag is set). We don't |
| 1657 | * need to worry about the root comparison in this case. |
| 1658 | */ |
| 1659 | |
| 1660 | if (create) { |