static void ioctl_emulate_open(int fd, const char *dev_path) { libc_func(fclose, int, FILE *); FILE *f; static char ioctl_path[PATH_MAX]; struct ioctl_fd_info *fdinfo; if (strncmp(dev_path, "/dev/", 5) != 0) return; fdinfo = malloc(sizeof(struct ioctl_fd_info)); fdinfo->tree = NULL; fdinfo->last = NULL; fd_map_add(&ioctl_wrapped_fds, fd, fdinfo); /* check if we have an ioctl tree for this */ snprintf(ioctl_path, sizeof(ioctl_path), "%s/ioctl/%s", getenv("UMOCKDEV_DIR"), dev_path); f = fopen(ioctl_path, "r"); if (f == NULL) return; fdinfo->tree = ioctl_tree_read(f); _fclose(f); if (fdinfo->tree == NULL) { fprintf(stderr, "ERROR: libumockdev-preload: failed to load ioctl record file for %s: empty or invalid format?", dev_path); exit(1); } DBG(DBG_IOCTL, "ioctl_emulate_open fd %i (%s): loaded ioctl tree\n", fd, dev_path); }
static void ioctl_record_open(int fd) { static dev_t record_rdev = (dev_t) - 1; if (fd < 0) return; /* lazily initialize record_rdev */ if (record_rdev == (dev_t) - 1) { const char *dev = getenv("UMOCKDEV_IOCTL_RECORD_DEV"); if (dev != NULL) record_rdev = parse_dev_t(dev, "$UMOCKDEV_IOCTL_RECORD_DEV", 1); else { /* not recording */ record_rdev = 0; } } if (record_rdev == 0) return; /* check if the opened device is the one we want to record */ if (dev_of_fd(fd) != record_rdev) return; /* recording is already in progress? */ if (ioctl_record_fd >= 0) { /* libmtp opens the device multiple times, we can't do that */ /* fprintf(stderr, "umockdev: recording for this device is already ongoing, stopping recording of previous open()\n"); ioctl_record_close(); */ fprintf(stderr, "umockdev: WARNING: ioctl recording for this device is already ongoing on fd %i, but application opened it a second time on fd %i without closing\n", ioctl_record_fd, fd); } ioctl_record_fd = fd; /* lazily open the record file */ if (ioctl_record_log == NULL) { const char *path = getenv("UMOCKDEV_IOCTL_RECORD_FILE"); const char *device_path = getenv("UMOCKDEV_IOCTL_RECORD_DEVICE_PATH"); struct sigaction act_int; if (path == NULL) { fprintf(stderr, "umockdev: $UMOCKDEV_IOCTL_RECORD_FILE not set\n"); exit(1); } if (device_path == NULL) { fprintf(stderr, "umockdev: $UMOCKDEV_IOCTL_RECORD_DEVICE_PATH not set\n"); exit(1); } if (getenv("UMOCKDEV_DIR") != NULL) { fprintf(stderr, "umockdev: $UMOCKDEV_DIR cannot be used while recording\n"); exit(1); } ioctl_record_log = fopen(path, "a+"); if (ioctl_record_log == NULL) { perror("umockdev: failed to open ioctl record file"); exit(1); } /* We record the device node for later loading without specifying * the devpath in umockdev_testbed_load_ioctl. */ fseek(ioctl_record_log, 0, SEEK_END); if (ftell(ioctl_record_log) > 0) { /* We're updating a previous log; don't write the devnode header again, * but check that we're recording the same device as the previous log. */ char *existing_device_path; char c; DBG(DBG_IOCTL, "ioctl_record_open: Updating existing record for path %s\n", path); fseek(ioctl_record_log, 0, SEEK_SET); /* Start by skipping any leading comments */ while ((c = fgetc(ioctl_record_log)) == '#') while (fgetc(ioctl_record_log) != '\n') ; ungetc(c, ioctl_record_log); if (fscanf(ioctl_record_log, "@DEV %ms\n", &existing_device_path) == 1) { /* We have an existing "@DEV /dev/something" directive, check it matches */ DBG(DBG_IOCTL, "ioctl_record_open: recording %s, existing device spec in record %s\n", device_path, existing_device_path); if (strcmp(device_path, existing_device_path) != 0) { fprintf(stderr, "umockdev: attempt to record two different devices to the same ioctl recording\n"); exit(1); } free(existing_device_path); } /* load an already existing log */ fseek(ioctl_record_log, 0, SEEK_SET); ioctl_record = ioctl_tree_read(ioctl_record_log); } else { /* New log, add devnode header */ DBG(DBG_IOCTL, "ioctl_record_open: Starting new record %s\n", path); fprintf(ioctl_record_log, "@DEV %s\n", device_path); } /* ensure that we write the file also on Control-C */ act_int.sa_handler = ioctl_record_sigint_handler; assert(sigemptyset(&act_int.sa_mask) == 0); act_int.sa_flags = 0; assert(sigaction(SIGINT, &act_int, &orig_actint) == 0); DBG(DBG_IOCTL, "ioctl_record_open: starting ioctl recording of fd %i into %s\n", fd, path); } else { DBG(DBG_IOCTL, "ioctl_record_open: ioctl recording is already ongoing, continuing on new fd %i\n", fd); } }
static void ioctl_record_open(int fd) { static dev_t record_rdev = (dev_t) - 1; if (fd < 0) return; /* lazily initialize record_rdev */ if (record_rdev == (dev_t) - 1) { const char *dev = getenv("UMOCKDEV_IOCTL_RECORD_DEV"); if (dev != NULL) { record_rdev = (dev_t) atoi(dev); } else { /* not recording */ record_rdev = 0; } } if (record_rdev == 0) return; /* check if the opened device is the one we want to record */ if (dev_of_fd(fd) != record_rdev) return; /* recording is already in progress? */ if (ioctl_record_fd >= 0) { /* libmtp opens the device multiple times, we can't do that */ /* fprintf(stderr, "umockdev: recording for this device is already ongoing, stopping recording of previous open()\n"); ioctl_record_close(); */ fprintf(stderr, "umockdev: WARNING: ioctl recording for this device is already ongoing on fd %i, but application opened it a second time on fd %i without closing\n", ioctl_record_fd, fd); } ioctl_record_fd = fd; /* lazily open the record file */ if (ioctl_record_log == NULL) { const char *path = getenv("UMOCKDEV_IOCTL_RECORD_FILE"); struct sigaction act_int; if (path == NULL) { fprintf(stderr, "umockdev: $UMOCKDEV_IOCTL_RECORD_FILE not set\n"); exit(1); } if (getenv("UMOCKDEV_DIR") != NULL) { fprintf(stderr, "umockdev: $UMOCKDEV_DIR cannot be used while recording\n"); exit(1); } ioctl_record_log = fopen(path, "a+"); if (ioctl_record_log == NULL) { perror("umockdev: failed to open ioctl record file"); exit(1); } /* load an already existing log */ ioctl_record = ioctl_tree_read(ioctl_record_log); /* ensure that we write the file also on Control-C */ act_int.sa_handler = ioctl_record_sigint_handler; assert(sigemptyset(&act_int.sa_mask) == 0); act_int.sa_flags = 0; assert(sigaction(SIGINT, &act_int, &orig_actint) == 0); DBG("ioctl_record_open: starting ioctl recording of fd %i into %s\n", fd, path); } else { DBG("ioctl_record_open: ioctl recording is already ongoing, continuing on new fd %i\n", fd); } }