int loop_free(char *loop_dev) { FILE *loop_fp; message(DEBUG, "Called loop_free(%s)\n", loop_dev); if ( is_blk(loop_dev) < 0 ) { message(ERROR, "Loop device is not a valid block device: %s\n", loop_dev); ABORT(255); } if ( ( loop_fp = fopen(loop_dev, "r") ) == NULL ) { // Flawfinder: ignore (only opening read only, and must be a block device) message(VERBOSE, "Could not open loop device %s: %s\n", loop_dev, strerror(errno)); return(-1); } message(DEBUG, "Called disassociate_loop(loop_fp)\n"); message(VERBOSE2, "Disassociating image from loop device\n"); if ( ioctl(fileno(loop_fp), LOOP_CLR_FD, 0) < 0 ) { message(ERROR, "Could not clear loop device %s: (%d) %s\n", loop_dev, errno, strerror(errno)); return(-1); } message(DEBUG, "Returning disassociate_loop(loop_fp) = 0\n"); return(0); }
/* This is the function which is called to display all files and * directories, and it's where the magic happens. We are called with * full stat and extended attributes for each file, so there is no * penalty for displaying anything in those structures. However if we * need other things (eg. checksum) we may have to go back to the * appliance and then there can be a very large penalty. */ static int show_file (const char *dir, const char *name, const struct guestfs_stat *stat, const struct guestfs_xattr_list *xattrs, void *unused) { const char *filetype; CLEANUP_FREE char *path = NULL, *csum = NULL, *link = NULL; /* Display the basic fields. */ output_start_line (); if (is_reg (stat->mode)) filetype = "-"; else if (is_dir (stat->mode)) filetype = "d"; else if (is_chr (stat->mode)) filetype = "c"; else if (is_blk (stat->mode)) filetype = "b"; else if (is_fifo (stat->mode)) filetype = "p"; else if (is_lnk (stat->mode)) filetype = "l"; else if (is_sock (stat->mode)) filetype = "s"; else filetype = "u"; output_string (filetype); output_int64_perms (stat->mode & 07777); output_int64_size (stat->size); /* Display extra fields when enabled. */ if (enable_uids) { output_int64_uid (stat->uid); output_int64_uid (stat->gid); } if (enable_times) { output_int64_time (stat->atime); output_int64_time (stat->mtime); output_int64_time (stat->ctime); } if (enable_extra_stats) { output_int64_dev (stat->dev); output_int64 (stat->ino); output_int64 (stat->nlink); output_int64_dev (stat->rdev); output_int64 (stat->blocks); } /* Disabled for now -- user would definitely want these to be interpreted. if (enable_xattrs) output_xattrs (xattrs); */ path = full_path (dir, name); if (checksum && is_reg (stat->mode)) { csum = guestfs_checksum (g, checksum, path); if (!csum) exit (EXIT_FAILURE); output_string (csum); } output_string (path); if (is_lnk (stat->mode)) /* XXX Fix this for NTFS. */ link = guestfs_readlink (g, path); if (link) output_string_link (link); output_end_line (); return 0; }
int loop_bind(FILE *image_fp, char **loop_dev, int autoclear) { struct loop_info64 lo64 = {0}; int i; message(DEBUG, "Called loop_bind(image_fp, **{loop_dev)\n"); if ( autoclear > 0 ) { lo64.lo_flags = LO_FLAGS_AUTOCLEAR; } lo64.lo_offset = image_offset(image_fp); for( i=0; i < MAX_LOOP_DEVS; i++ ) { char *test_loopdev = strjoin("/dev/loop", int2str(i)); FILE *loop_fp; if ( is_blk(test_loopdev) < 0 ) { message(VERBOSE, "Creating loop device: %s\n", test_loopdev); if ( mknod(test_loopdev, S_IFBLK | 0644, makedev(7, i)) < 0 ) { message(ERROR, "Could not create %s: %s\n", test_loopdev, strerror(errno)); ABORT(255); } } if ( ( loop_fp = fopen(test_loopdev, "r+") ) == NULL ) { // Flawfinder: ignore (not user modifyable) message(VERBOSE, "Could not open loop device %s: %s\n", test_loopdev, strerror(errno)); continue; } message(VERBOSE2, "Attempting to associate image pointer to loop device\n"); if ( ioctl(fileno(loop_fp), LOOP_SET_FD, fileno(image_fp)) < 0 ) { if ( errno == 16 ) { message(VERBOSE3, "Loop device is in use: %s\n", test_loopdev); fclose(loop_fp); continue; } else { message(WARNING, "Could not associate image to loop %s: %s\n", test_loopdev, strerror(errno)); fclose(loop_fp); continue; } } message(VERBOSE, "Found valid loop device: %s\n", test_loopdev); message(VERBOSE2, "Setting loop device flags\n"); if ( ioctl(fileno(loop_fp), LOOP_SET_STATUS64, &lo64) < 0 ) { fprintf(stderr, "ERROR: Failed to set loop flags on loop device: %s\n", strerror(errno)); (void)ioctl(fileno(loop_fp), LOOP_CLR_FD, 0); (void)loop_free(*loop_dev); ABORT(255); } *loop_dev = strdup(test_loopdev); message(VERBOSE, "Using loop device: %s\n", *loop_dev); message(DEBUG, "Returning loop_bind(image_fp) = 0\n"); return(0); } message(ERROR, "No valid loop devices available\n"); ABORT(255); return(-1); }
static void output_file (guestfs_h *g, struct file *file) { const char *filetype; size_t i; CLEANUP_FREE char *link = NULL; if (is_reg (file->stat->st_mode)) filetype = "-"; else if (is_dir (file->stat->st_mode)) filetype = "d"; else if (is_chr (file->stat->st_mode)) filetype = "c"; else if (is_blk (file->stat->st_mode)) filetype = "b"; else if (is_fifo (file->stat->st_mode)) filetype = "p"; else if (is_lnk (file->stat->st_mode)) filetype = "l"; else if (is_sock (file->stat->st_mode)) filetype = "s"; else filetype = "u"; output_string (filetype); output_int64_perms (file->stat->st_mode & 07777); output_int64_size (file->stat->st_size); /* Display extra fields when enabled. */ if (enable_uids) { output_int64_uid (file->stat->st_uid); output_int64_uid (file->stat->st_gid); } if (enable_times) { if (atime) output_int64_time (file->stat->st_atime_sec, file->stat->st_atime_nsec); output_int64_time (file->stat->st_mtime_sec, file->stat->st_mtime_nsec); output_int64_time (file->stat->st_ctime_sec, file->stat->st_ctime_nsec); } if (enable_extra_stats) { output_int64_dev (file->stat->st_dev); output_int64 (file->stat->st_ino); output_int64 (file->stat->st_nlink); output_int64_dev (file->stat->st_rdev); output_int64 (file->stat->st_blocks); } if (file->csum) output_string (file->csum); output_string (file->path); if (is_lnk (file->stat->st_mode)) { /* XXX Fix this for NTFS. */ link = guestfs_readlink (g, file->path); if (link) output_string_link (link); } if (enable_xattrs) { for (i = 0; i < file->xattrs->len; ++i) { output_string (file->xattrs->val[i].attrname); output_binary (file->xattrs->val[i].attrval, file->xattrs->val[i].attrval_len); } } }
int main(int argc, char ** argv) { uid_t uid = geteuid(); if ( argv[1] == NULL || argv[2] == NULL ) { fprintf(stderr, "USAGE: %s [attach/detach] [image/loop]\n", argv[0]); return(1); } message(VERBOSE, "Checking calling user\n"); if ( uid != 0 ) { message(ERROR, "Calling user must be root\n"); ABORT(1); } message(VERBOSE, "Checking command: %s\n", argv[1]); if ( strcmp(argv[1], "attach") == 0 ) { FILE *containerimage_fp; char *containerimage; char *loop_dev; message(VERBOSE, "Preparing to attach container to loop\n"); containerimage = xstrdup(argv[2]); message(VERBOSE, "Evaluating image: %s\n", containerimage); message(VERBOSE, "Checking if container image exists\n"); if ( is_file(containerimage) < 0 ) { message(ERROR, "Container image not found: %s\n", containerimage); ABORT(1); } message(VERBOSE, "Checking if container can be opened read/write\n"); if ( !( containerimage_fp = fopen(containerimage, "r+") ) ) { // Flawfinder: ignore message(ERROR, "Could not open image %s: %s\n", containerimage, strerror(errno)); ABORT(255); } message(DEBUG, "Binding container to loop interface\n"); if ( loop_bind(containerimage_fp, &loop_dev, 0) < 0 ) { message(ERROR, "Could not bind image to loop!\n"); ABORT(255); } printf("%s\n", loop_dev); } else if (strcmp(argv[1], "detach") == 0 ) { char *loop_dev; loop_dev = xstrdup(argv[2]); message(VERBOSE, "Preparing to detach loop: %s\n", loop_dev); message(VERBOSE, "Checking loop device\n"); if ( is_blk(loop_dev) < 0 ) { message(ERROR, "Block device not found: %s\n", loop_dev); ABORT(255); } message(VERBOSE, "Unbinding container image from loop\n"); if ( loop_free(loop_dev) < 0 ) { message(ERROR, "Failed to detach loop device: %s\n", loop_dev); ABORT(255); } } return(0); }