/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * This file is part of libaacs * Copyright (C) 2009-2010 Obliter0n * Copyright (C) 2010-2015 npzacs * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see * . */ #if HAVE_CONFIG_H #include "config.h" #endif #include "mmc_device.h" #include "path.h" #include "util/logging.h" #include "util/macro.h" #include "util/strutl.h" #include #include #include #include #include #include #ifdef HAVE_MNTENT_H #include #endif #ifdef HAVE_LINUX_CDROM_H #include #include #include #endif /* * */ struct mmcdev { int fd; }; int device_send_cmd(MMCDEV *dev, const uint8_t *cmd, uint8_t *buf, size_t tx, size_t rx) { #if defined(HAVE_LINUX_CDROM_H) struct cdrom_generic_command cgc; struct request_sense sense; char str[512]; int result; memset(&cgc, 0, sizeof(cgc)); memcpy(cgc.cmd, cmd, CDROM_PACKET_SIZE); cgc.sense = &sense; cgc.timeout = 5000; if (buf) { if (tx) { cgc.data_direction = CGC_DATA_WRITE; cgc.buflen = tx; cgc.buffer = buf; } else if (rx) { cgc.data_direction = CGC_DATA_READ; cgc.buflen = rx; cgc.buffer = buf; } } else { cgc.data_direction = CGC_DATA_NONE; cgc.buflen = 0; cgc.buffer = NULL; } result = ioctl(dev->fd, CDROM_SEND_PACKET, &cgc); BD_DEBUG(DBG_MMC, "Send LINUX MMC cmd %s:\n", str_print_hex(str, cmd, 16)); if (tx) { BD_DEBUG(DBG_MMC, " Buffer: %s ->\n", str_print_hex(str, buf, tx>255?255:tx)); } else { BD_DEBUG(DBG_MMC, " Buffer: %s <-\n", str_print_hex(str, buf, rx>255?255:rx)); } if (result >= 0) { BD_DEBUG(DBG_MMC, " Send succeeded! [%d]\n", result); return 1; } BD_DEBUG(DBG_MMC, " Send failed! [%d] %s\n", result, strerror(errno)); #else #warning no MMC drive support BD_DEBUG(DBG_MMC | DBG_CRIT, "No MMC drive support\n"); #endif return 0; } MMCDEV *device_open(const char *path) { char resolved_path[AACS_PATH_MAX]; size_t path_len; struct stat st; int fd = -1; /* resolve path */ if (!aacs_resolve_path(path, resolved_path)) { BD_DEBUG(DBG_MMC | DBG_CRIT, "Failed resolving path %s\n", path); return NULL; } /* strip trailing '/'s */ path_len = strlen(resolved_path); while (path_len > 0 && resolved_path[--path_len] == '/') { resolved_path[path_len] = '\0'; } if (stat(resolved_path, &st)) { BD_DEBUG(DBG_MMC | DBG_CRIT, "stat(%s) failed\n", resolved_path); return NULL; } if (S_ISBLK(st.st_mode)) { /* opening device */ BD_DEBUG(DBG_MMC, "Opening block device %s\n", resolved_path); fd = open(resolved_path, O_RDONLY | O_NONBLOCK); if (fd < 0) { BD_DEBUG(DBG_MMC | DBG_CRIT, "Error opening block device %s\n", resolved_path); } } else { #if !defined(HAVE_MNTENT_H) BD_DEBUG(DBG_MMC | DBG_CRIT, "Only block devices supported\n"); return NULL; #endif } #if defined(HAVE_MNTENT_H) if (fd < 0) { /* resolve mount point to block device */ FILE *proc_mounts; if ((proc_mounts = setmntent("/proc/mounts", "r"))) { struct mntent* mount_entry; BD_DEBUG(DBG_MMC, "Opening LINUX MMC drive mounted to %s...\n", resolved_path); while ((mount_entry = getmntent(proc_mounts)) != NULL) { if (strcmp(mount_entry->mnt_dir, resolved_path) == 0) { fd = open(mount_entry->mnt_fsname, O_RDONLY | O_NONBLOCK); if (fd >= 0) { BD_DEBUG(DBG_MMC, "LINUX MMC drive %s opened - fd: %d\n", mount_entry->mnt_fsname, fd); break; } BD_DEBUG(DBG_MMC | DBG_CRIT, "Failed opening MMC drive %s mounted to %s\n", mount_entry->mnt_fsname, resolved_path); } } endmntent(proc_mounts); if (fd < 0) { BD_DEBUG(DBG_MMC | DBG_CRIT, "No MMC drive mounted to %s\n", resolved_path); } } else { BD_DEBUG(DBG_MMC | DBG_CRIT, "Error opening /proc/mounts\n"); } } #endif if (fd >= 0) { MMCDEV *dev = calloc(1, sizeof(MMCDEV)); if (dev) { dev->fd = fd; return dev; } } return NULL; } void device_close(MMCDEV **pp) { if (pp && *pp) { if ((*pp)->fd != -1) { close((*pp)->fd); } X_FREE(*pp); } }