qemu-config: Add new -add-fd command line option
This option can be used for passing file descriptors on the
command line.  It mirrors the existing add-fd QMP command which
allows an fd to be passed to QEMU via SCM_RIGHTS and added to an
fd set.
This can be combined with commands such as -drive to link file
descriptors in an fd set to a drive:
    qemu-kvm -add-fd fd=3,set=2,opaque="rdwr:/path/to/file"
             -add-fd fd=4,set=2,opaque="rdonly:/path/to/file"
             -drive file=/dev/fdset/2,index=0,media=disk
This example adds dups of fds 3 and 4, and the accompanying opaque
strings to the fd set with ID=2.  qemu_open() already knows how
to handle a filename of this format.  qemu_open() searches the
corresponding fd set for an fd and when it finds a match, QEMU
goes on to use a dup of that fd just like it would have used an
fd that it opened itself.
Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									ebe52b592d
								
							
						
					
					
						commit
						587ed6be0b
					
				@ -653,6 +653,27 @@ QemuOptsList qemu_boot_opts = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static QemuOptsList qemu_add_fd_opts = {
 | 
				
			||||||
 | 
					    .name = "add-fd",
 | 
				
			||||||
 | 
					    .head = QTAILQ_HEAD_INITIALIZER(qemu_add_fd_opts.head),
 | 
				
			||||||
 | 
					    .desc = {
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            .name = "fd",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_NUMBER,
 | 
				
			||||||
 | 
					            .help = "file descriptor of which a duplicate is added to fd set",
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "set",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_NUMBER,
 | 
				
			||||||
 | 
					            .help = "ID of the fd set to add fd to",
 | 
				
			||||||
 | 
					        },{
 | 
				
			||||||
 | 
					            .name = "opaque",
 | 
				
			||||||
 | 
					            .type = QEMU_OPT_STRING,
 | 
				
			||||||
 | 
					            .help = "free-form string used to describe fd",
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        { /* end of list */ }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static QemuOptsList *vm_config_groups[32] = {
 | 
					static QemuOptsList *vm_config_groups[32] = {
 | 
				
			||||||
    &qemu_drive_opts,
 | 
					    &qemu_drive_opts,
 | 
				
			||||||
    &qemu_chardev_opts,
 | 
					    &qemu_chardev_opts,
 | 
				
			||||||
@ -669,6 +690,7 @@ static QemuOptsList *vm_config_groups[32] = {
 | 
				
			|||||||
    &qemu_boot_opts,
 | 
					    &qemu_boot_opts,
 | 
				
			||||||
    &qemu_iscsi_opts,
 | 
					    &qemu_iscsi_opts,
 | 
				
			||||||
    &qemu_sandbox_opts,
 | 
					    &qemu_sandbox_opts,
 | 
				
			||||||
 | 
					    &qemu_add_fd_opts,
 | 
				
			||||||
    NULL,
 | 
					    NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -253,6 +253,14 @@ qemu-system-i386 -drive file=file,index=2,media=disk
 | 
				
			|||||||
qemu-system-i386 -drive file=file,index=3,media=disk
 | 
					qemu-system-i386 -drive file=file,index=3,media=disk
 | 
				
			||||||
@end example
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can open an image using pre-opened file descriptors from an fd set:
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					qemu-system-i386
 | 
				
			||||||
 | 
					-add-fd fd=3,set=2,opaque="rdwr:/path/to/file"
 | 
				
			||||||
 | 
					-add-fd fd=4,set=2,opaque="rdonly:/path/to/file"
 | 
				
			||||||
 | 
					-drive file=/dev/fdset/2,index=0,media=disk
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
You can connect a CDROM to the slave of ide0:
 | 
					You can connect a CDROM to the slave of ide0:
 | 
				
			||||||
@example
 | 
					@example
 | 
				
			||||||
qemu-system-i386 -drive file=file,if=ide,index=1,media=cdrom
 | 
					qemu-system-i386 -drive file=file,if=ide,index=1,media=cdrom
 | 
				
			||||||
@ -285,6 +293,34 @@ qemu-system-i386 -hda a -hdb b
 | 
				
			|||||||
@end example
 | 
					@end example
 | 
				
			||||||
ETEXI
 | 
					ETEXI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEF("add-fd", HAS_ARG, QEMU_OPTION_add_fd,
 | 
				
			||||||
 | 
					    "-add-fd fd=fd,set=set[,opaque=opaque]\n"
 | 
				
			||||||
 | 
					    "                Add 'fd' to fd 'set'\n", QEMU_ARCH_ALL)
 | 
				
			||||||
 | 
					STEXI
 | 
				
			||||||
 | 
					@item -add-fd fd=@var{fd},set=@var{set}[,opaque=@var{opaque}]
 | 
				
			||||||
 | 
					@findex -add-fd
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Add a file descriptor to an fd set.  Valid options are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@table @option
 | 
				
			||||||
 | 
					@item fd=@var{fd}
 | 
				
			||||||
 | 
					This option defines the file descriptor of which a duplicate is added to fd set.
 | 
				
			||||||
 | 
					The file descriptor cannot be stdin, stdout, or stderr.
 | 
				
			||||||
 | 
					@item set=@var{set}
 | 
				
			||||||
 | 
					This option defines the ID of the fd set to add the file descriptor to.
 | 
				
			||||||
 | 
					@item opaque=@var{opaque}
 | 
				
			||||||
 | 
					This option defines a free-form string that can be used to describe @var{fd}.
 | 
				
			||||||
 | 
					@end table
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can open an image using pre-opened file descriptors from an fd set:
 | 
				
			||||||
 | 
					@example
 | 
				
			||||||
 | 
					qemu-system-i386
 | 
				
			||||||
 | 
					-add-fd fd=3,set=2,opaque="rdwr:/path/to/file"
 | 
				
			||||||
 | 
					-add-fd fd=4,set=2,opaque="rdonly:/path/to/file"
 | 
				
			||||||
 | 
					-drive file=/dev/fdset/2,index=0,media=disk
 | 
				
			||||||
 | 
					@end example
 | 
				
			||||||
 | 
					ETEXI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEF("set", HAS_ARG, QEMU_OPTION_set,
 | 
					DEF("set", HAS_ARG, QEMU_OPTION_set,
 | 
				
			||||||
    "-set group.id.arg=value\n"
 | 
					    "-set group.id.arg=value\n"
 | 
				
			||||||
    "                set <arg> parameter for item <id> of type <group>\n"
 | 
					    "                set <arg> parameter for item <id> of type <group>\n"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										94
									
								
								vl.c
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								vl.c
									
									
									
									
									
								
							@ -790,6 +790,78 @@ static int parse_sandbox(QemuOpts *opts, void *opaque)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _WIN32
 | 
				
			||||||
 | 
					static int parse_add_fd(QemuOpts *opts, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int fd, dupfd, flags;
 | 
				
			||||||
 | 
					    int64_t fdset_id;
 | 
				
			||||||
 | 
					    const char *fd_opaque = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd = qemu_opt_get_number(opts, "fd", -1);
 | 
				
			||||||
 | 
					    fdset_id = qemu_opt_get_number(opts, "set", -1);
 | 
				
			||||||
 | 
					    fd_opaque = qemu_opt_get(opts, "opaque");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fd < 0) {
 | 
				
			||||||
 | 
					        qerror_report(ERROR_CLASS_GENERIC_ERROR,
 | 
				
			||||||
 | 
					                      "fd option is required and must be non-negative");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fd <= STDERR_FILENO) {
 | 
				
			||||||
 | 
					        qerror_report(ERROR_CLASS_GENERIC_ERROR,
 | 
				
			||||||
 | 
					                      "fd cannot be a standard I/O stream");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					     * All fds inherited across exec() necessarily have FD_CLOEXEC
 | 
				
			||||||
 | 
					     * clear, while qemu sets FD_CLOEXEC on all other fds used internally.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    flags = fcntl(fd, F_GETFD);
 | 
				
			||||||
 | 
					    if (flags == -1 || (flags & FD_CLOEXEC)) {
 | 
				
			||||||
 | 
					        qerror_report(ERROR_CLASS_GENERIC_ERROR,
 | 
				
			||||||
 | 
					                      "fd is not valid or already in use");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fdset_id < 0) {
 | 
				
			||||||
 | 
					        qerror_report(ERROR_CLASS_GENERIC_ERROR,
 | 
				
			||||||
 | 
					                      "set option is required and must be non-negative");
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef F_DUPFD_CLOEXEC
 | 
				
			||||||
 | 
					    dupfd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					    dupfd = dup(fd);
 | 
				
			||||||
 | 
					    if (dupfd != -1) {
 | 
				
			||||||
 | 
					        qemu_set_cloexec(dupfd);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    if (dupfd == -1) {
 | 
				
			||||||
 | 
					        qerror_report(ERROR_CLASS_GENERIC_ERROR,
 | 
				
			||||||
 | 
					                      "Error duplicating fd: %s", strerror(errno));
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* add the duplicate fd, and optionally the opaque string, to the fd set */
 | 
				
			||||||
 | 
					    monitor_fdset_add_fd(dupfd, true, fdset_id, fd_opaque ? true : false,
 | 
				
			||||||
 | 
					                         fd_opaque, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int cleanup_add_fd(QemuOpts *opts, void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int fd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fd = qemu_opt_get_number(opts, "fd", -1);
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/***********************************************************/
 | 
					/***********************************************************/
 | 
				
			||||||
/* QEMU Block devices */
 | 
					/* QEMU Block devices */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -3309,6 +3381,18 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
                    exit(0);
 | 
					                    exit(0);
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
 | 
					            case QEMU_OPTION_add_fd:
 | 
				
			||||||
 | 
					#ifndef _WIN32
 | 
				
			||||||
 | 
					                opts = qemu_opts_parse(qemu_find_opts("add-fd"), optarg, 0);
 | 
				
			||||||
 | 
					                if (!opts) {
 | 
				
			||||||
 | 
					                    exit(0);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					                error_report("File descriptor passing is disabled on this "
 | 
				
			||||||
 | 
					                             "platform");
 | 
				
			||||||
 | 
					                exit(1);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
            default:
 | 
					            default:
 | 
				
			||||||
                os_parse_cmd_args(popt->index, optarg);
 | 
					                os_parse_cmd_args(popt->index, optarg);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -3320,6 +3404,16 @@ int main(int argc, char **argv, char **envp)
 | 
				
			|||||||
        exit(1);
 | 
					        exit(1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef _WIN32
 | 
				
			||||||
 | 
					    if (qemu_opts_foreach(qemu_find_opts("add-fd"), parse_add_fd, NULL, 1)) {
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (qemu_opts_foreach(qemu_find_opts("add-fd"), cleanup_add_fd, NULL, 1)) {
 | 
				
			||||||
 | 
					        exit(1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (machine == NULL) {
 | 
					    if (machine == NULL) {
 | 
				
			||||||
        fprintf(stderr, "No machine found.\n");
 | 
					        fprintf(stderr, "No machine found.\n");
 | 
				
			||||||
        exit(1);
 | 
					        exit(1);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user