Exemplo n.º 1
0
/**
 * @brief Run authopen to acquire a file descriptor to the mmc device
 *
 * Like Linux, OSX does not allow processes to read and write devices as
 * normal users. OSX provides a utility called authopen that can ask the
 * user for permission to access a file.
 *
 * @param pathname the full path to the device
 * @return a descriptor or -1 on error
 */
static int authopen_fd(char * const pathname)
{
    int sockets[2];
    if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0)
        fwup_err(EXIT_FAILURE, "Can't create socketpair");

    pid_t pid = fork();
    if (pid == 0) {
        // child
        int devnull = open("/dev/null", O_RDWR);
        if (devnull < 0)
            fwup_err(EXIT_FAILURE, "/dev/null");

        close(STDIN_FILENO);
        close(STDOUT_FILENO);
        if (dup2(devnull, STDIN_FILENO) < 0)
            fwup_err(EXIT_FAILURE, "dup2 devnull");
        if (dup2(sockets[1], STDOUT_FILENO) < 0)
            fwup_err(EXIT_FAILURE, "dup2 pipe");
        close(devnull);

        char permissions[16];
        sprintf(permissions, "%d", O_RDWR);
        char * const exec_argv[] = { "/usr/libexec/authopen",
                              "-stdoutpipe",
                              "-o",
                              permissions,
                              pathname,
                              0 };
        execvp(exec_argv[0], exec_argv);

        // Not supposed to reach here.
        fwup_err(EXIT_FAILURE, "execvp failed");
    } else {
        // parent
        close(sockets[1]); // No writes to the pipe

        // Receive the authorized file descriptor from authopen
        char buffer[sizeof(struct cmsghdr) + sizeof(int)];
        struct iovec io_vec[1];
        io_vec[0].iov_base = buffer;
        io_vec[0].iov_len = sizeof(buffer);

        struct msghdr message;
        memset(&message, 0, sizeof(message));
        message.msg_iov = io_vec;
        message.msg_iovlen = 1;

        char cmsg_socket[CMSG_SPACE(sizeof(int))];
        message.msg_control = cmsg_socket;
        message.msg_controllen = sizeof(cmsg_socket);

        int fd = -1;
        for (;;) {
            ssize_t size = recvmsg(sockets[0], &message, 0);
            if (size > 0) {
                struct cmsghdr* cmsg_socket_header = CMSG_FIRSTHDR(&message);
                if (cmsg_socket_header &&
                        cmsg_socket_header->cmsg_level == SOL_SOCKET &&
                        cmsg_socket_header->cmsg_type == SCM_RIGHTS) {
                    // Got file descriptor
                    memcpy(&fd, CMSG_DATA(cmsg_socket_header), sizeof(fd));
                    break;
                }
            } else if (errno != EINTR) {
                // Any other cause
                break;
            }
        }

        // No more reads from the pipe.
        close(sockets[0]);

        return fd;
    }
}
Exemplo n.º 2
0
int mmc_umount_all(const char *mmc_device)
{
    FILE *fp = fopen("/proc/mounts", "r");
    if (!fp)
        fwup_err(EXIT_FAILURE, "/proc/mounts");

    char *todo[64] = {0};
    int todo_ix = 0;
    int ultimate_rc = 0;

    char line[FWUP_BLOCK_SIZE] = {0};
    while (!feof(fp) &&
            fgets(line, sizeof(line), fp)) {
        char devname[64];
        char mountpoint[256];
        if (sscanf(line, "%63s %255s", devname, mountpoint) != 2)
            continue;

        if (strstr(devname, mmc_device) == devname) {
            // mmc_device is a prefix of this device, i.e. mmc_device is /dev/sdc
            // and /dev/sdc1 is mounted.

            if (todo_ix == NUM_ELEMENTS(todo))
                fwup_errx(EXIT_FAILURE, "Device mounted too many times");

            // strings from /proc/mounts are escaped, so unescape them
            todo[todo_ix++] = unescape_string(mountpoint);
        }
    }
    fclose(fp);

    int mtab_exists = (access("/etc/mtab", F_OK) != -1);
    for (int i = 0; i < todo_ix; i++) {
        if (mtab_exists) {
            // If /etc/mtab, then call umount(8) so that
            // gets updated correctly.
            int rc = fork_exec("/bin/umount", todo[i]);
            if (rc != 0) {
                fwup_warnx("Error calling umount on '%s'", todo[i]);
                ultimate_rc = -1;
            }
        } else {
            // No /etc/mtab, so call the kernel directly.
#if HAS_UMOUNT
            if (umount(todo[i]) < 0) {
                fwup_warnx("umount %s", todo[i]);
                ultimate_rc = -1;
            }
#else
            // If no umount on this platform, warn, but don't
            // return failure.
            fwup_warnx("umount %s: not supported", todo[i]);
#endif
        }
    }

    for (int i = 0; i < todo_ix; i++)
        free(todo[i]);

    return ultimate_rc;
}