Esempio n. 1
0
int main(int argc, char **argv)
{
    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
    type_register_static(&static_prop_type);
    type_register_static(&dynamic_prop_type);
    type_register_static(&hotplug_type);
    type_register_static(&nohotplug_type);
    type_register_static(&nondevice_type);

    g_test_add_func("/qdev/properties/static/default/subprocess",
                    test_static_prop_subprocess);
    g_test_add_func("/qdev/properties/static/default",
                    test_static_prop);

    g_test_add_func("/qdev/properties/static/global/subprocess",
                    test_static_globalprop_subprocess);
    g_test_add_func("/qdev/properties/static/global",
                    test_static_globalprop);

    g_test_add_func("/qdev/properties/dynamic/global/subprocess",
                    test_dynamic_globalprop_subprocess);
    g_test_add_func("/qdev/properties/dynamic/global",
                    test_dynamic_globalprop);

    g_test_add_func("/qdev/properties/dynamic/global/nouser/subprocess",
                    test_dynamic_globalprop_nouser_subprocess);
    g_test_add_func("/qdev/properties/dynamic/global/nouser",
                    test_dynamic_globalprop_nouser);

    g_test_run();

    return 0;
}
Esempio n. 2
0
int main(int argc, char **argv)
{
    int ret;
    TestState ts = { 0 };

    ts.src_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
    ts.dst_tpm_path = g_dir_make_tmp("qemu-tpm-tis-swtpm-test.XXXXXX", NULL);
    ts.uri = g_strdup_printf("unix:%s/migsocket", ts.src_tpm_path);

    module_call_init(MODULE_INIT_QOM);
    g_test_init(&argc, &argv, NULL);

    qtest_add_data_func("/tpm/tis-swtpm/test", &ts, tpm_tis_swtpm_test);
    qtest_add_data_func("/tpm/tis-swtpm-migration/test", &ts,
                        tpm_tis_swtpm_migration_test);
    ret = g_test_run();

    g_rmdir(ts.dst_tpm_path);
    g_free(ts.dst_tpm_path);
    g_rmdir(ts.src_tpm_path);
    g_free(ts.src_tpm_path);
    g_free(ts.uri);

    return ret;
}
Esempio n. 3
0
int main(int argc, char **argv)
{
    QTestState *s = NULL;
    CharDriverState *chr = NULL;
    const char *hugefs = 0;
    char *socket_path = 0;
    char *qemu_cmd = 0;
    char *chr_path = 0;
    int ret;

    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);

    hugefs = init_hugepagefs();
    if (!hugefs) {
        return 0;
    }

    socket_path = g_strdup_printf("/tmp/vhost-%d.sock", getpid());

    /* create char dev and add read handlers */
    qemu_add_opts(&qemu_chardev_opts);
    chr_path = g_strdup_printf("unix:%s,server,nowait", socket_path);
    chr = qemu_chr_new("chr0", chr_path, NULL);
    g_free(chr_path);
    qemu_chr_add_handlers(chr, chr_can_read, chr_read, NULL, chr);

    /* run the main loop thread so the chardev may operate */
    data_mutex = _mutex_new();
    data_cond = _cond_new();
    _thread_new(NULL, thread_function, NULL);

    qemu_cmd = g_strdup_printf(QEMU_CMD, hugefs, socket_path);
    s = qtest_start(qemu_cmd);
    g_free(qemu_cmd);

    qtest_add_func("/vhost-user/read-guest-mem", read_guest_mem);

    ret = g_test_run();

    if (s) {
        qtest_quit(s);
    }

    /* cleanup */
    unlink(socket_path);
    g_free(socket_path);
    _cond_free(data_cond);
    _mutex_free(data_mutex);

    return ret;
}
Esempio n. 4
0
File: vl.c Progetto: RKX1209/unicorn
int machine_initialize(struct uc_struct *uc)
{
    MachineClass *machine_class;
    MachineState *current_machine;

    module_call_init(uc, MODULE_INIT_QOM);
    register_types_object(uc);
    machine_register_types(uc);
    container_register_types(uc);
    cpu_register_types(uc);
    qdev_register_types(uc);

    // Initialize arch specific.
    uc->init_arch(uc);

    module_call_init(uc, MODULE_INIT_MACHINE);
    // this will auto initialize all register objects above.
    machine_class = find_default_machine(uc, uc->arch);
    if (machine_class == NULL) {
        //fprintf(stderr, "No machine specified, and there is no default.\n"
        //        "Use -machine help to list supported machines!\n");
        return -2;
    }

    current_machine = MACHINE(uc, object_new(uc, object_class_get_name(
                                  OBJECT_CLASS(machine_class))));

    current_machine->uc = uc;
    uc->cpu_exec_init_all(uc);

    machine_class->max_cpus = 1;
    configure_accelerator(current_machine);

    qemu_init_cpu_loop(uc);
    qemu_mutex_lock_iothread(uc);

    current_machine->cpu_model = NULL;

    return machine_class->init(uc, current_machine);
}
Esempio n. 5
0
int main(int argc, char **argv)
{
    g_test_init(&argc, &argv, NULL);

    g_test_add_func("/0.15/dispatch_cmd", test_dispatch_cmd);
    g_test_add_func("/0.15/dispatch_cmd_error", test_dispatch_cmd_error);
    g_test_add_func("/0.15/dispatch_cmd_io", test_dispatch_cmd_io);

    module_call_init(MODULE_INIT_QAPI);
    g_test_run();

    return 0;
}
Esempio n. 6
0
int main(int argc, char **argv)
{
    module_call_init(MODULE_INIT_QOM);

    g_test_init(&argc, &argv, NULL);

    g_test_add_func("/io/channel/file", test_io_channel_file);
#ifndef _WIN32
    g_test_add_func("/io/channel/pipe/sync", test_io_channel_pipe_sync);
    g_test_add_func("/io/channel/pipe/async", test_io_channel_pipe_async);
#endif
    return g_test_run();
}
int main(int argc, char **argv)
{
    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
    type_register_static(&dummy_info);

    g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
    g_test_add_func("/qom/proplist/createv", test_dummy_createv);
    g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
    g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);

    return g_test_run();
}
int main(int argc, char **argv)
{
    bool has_ipv4, has_ipv6;

    module_call_init(MODULE_INIT_QOM);
    socket_init();

    g_test_init(&argc, &argv, NULL);

    /* We're creating actual IPv4/6 sockets, so we should
     * check if the host running tests actually supports
     * each protocol to avoid breaking tests on machines
     * with either IPv4 or IPv6 disabled.
     */
    if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) {
        return 1;
    }

    if (has_ipv4) {
        g_test_add_func("/io/channel/socket/ipv4-sync",
                        test_io_channel_ipv4_sync);
        g_test_add_func("/io/channel/socket/ipv4-async",
                        test_io_channel_ipv4_async);
        g_test_add_func("/io/channel/socket/ipv4-fd",
                        test_io_channel_ipv4_fd);
    }
    if (has_ipv6) {
        g_test_add_func("/io/channel/socket/ipv6-sync",
                        test_io_channel_ipv6_sync);
        g_test_add_func("/io/channel/socket/ipv6-async",
                        test_io_channel_ipv6_async);
    }

#ifndef _WIN32
    g_test_add_func("/io/channel/socket/unix-sync",
                    test_io_channel_unix_sync);
    g_test_add_func("/io/channel/socket/unix-async",
                    test_io_channel_unix_async);
    g_test_add_func("/io/channel/socket/unix-fd-pass",
                    test_io_channel_unix_fd_pass);
    g_test_add_func("/io/channel/socket/unix-listen-cleanup",
                    test_io_channel_unix_listen_cleanup);
#endif /* _WIN32 */

    return g_test_run();
}
Esempio n. 9
0
int main(int argc, char **argv)
{
    module_call_init(MODULE_INIT_QOM);
    g_test_init(&argc, &argv, NULL);

    g_assert(qcrypto_init(NULL) == 0);

    g_test_add_func("/crypto/secret/direct",
                    test_secret_direct);
    g_test_add_func("/crypto/secret/indirect/good",
                    test_secret_indirect_good);
    g_test_add_func("/crypto/secret/indirect/badfile",
                    test_secret_indirect_badfile);
    g_test_add_func("/crypto/secret/indirect/emptyfile",
                    test_secret_indirect_emptyfile);

    g_test_add_func("/crypto/secret/noconv/base64/good",
                    test_secret_noconv_base64_good);
    g_test_add_func("/crypto/secret/noconv/base64/bad",
                    test_secret_noconv_base64_bad);
    g_test_add_func("/crypto/secret/noconv/utf8",
                    test_secret_noconv_utf8);
    g_test_add_func("/crypto/secret/conv/base64/utf8valid",
                    test_secret_conv_base64_utf8valid);
    g_test_add_func("/crypto/secret/conv/base64/utf8invalid",
                    test_secret_conv_base64_utf8invalid);
    g_test_add_func("/crypto/secret/conv/utf8/base64",
                    test_secret_conv_utf8_base64);

    g_test_add_func("/crypto/secret/crypt/raw",
                    test_secret_crypt_raw);
    g_test_add_func("/crypto/secret/crypt/base64",
                    test_secret_crypt_base64);
    g_test_add_func("/crypto/secret/crypt/shortkey",
                    test_secret_crypt_short_key);
    g_test_add_func("/crypto/secret/crypt/shortiv",
                    test_secret_crypt_short_iv);
    g_test_add_func("/crypto/secret/crypt/missingiv",
                    test_secret_crypt_missing_iv);
    g_test_add_func("/crypto/secret/crypt/badiv",
                    test_secret_crypt_bad_iv);

    return g_test_run();
}
Esempio n. 10
0
int main(int argc, char **argv)
{
    g_test_init(&argc, &argv, NULL);

    module_call_init(MODULE_INIT_QOM);
    type_register_static(&dummy_info);
    type_register_static(&dummy_dev_info);
    type_register_static(&dummy_bus_info);
    type_register_static(&dummy_backend_info);

    g_test_add_func("/qom/proplist/createlist", test_dummy_createlist);
    g_test_add_func("/qom/proplist/createv", test_dummy_createv);
    g_test_add_func("/qom/proplist/createcmdline", test_dummy_createcmdl);
    g_test_add_func("/qom/proplist/badenum", test_dummy_badenum);
    g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
    g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
    g_test_add_func("/qom/proplist/class_iterator", test_dummy_class_iterator);
    g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
    g_test_add_func("/qom/resolve/partial", test_qom_partial_path);

    return g_test_run();
}
Esempio n. 11
0
int main(int argc, char **argv)
{
    const char *sopt = "hVvdm:p:l:f:F::b:s:t:";
    const char *method = NULL, *path = NULL;
    const char *log_filepath = NULL;
    const char *pid_filepath;
#ifdef CONFIG_FSFREEZE
    const char *fsfreeze_hook = NULL;
#endif
    const char *state_dir;
#ifdef _WIN32
    const char *service = NULL;
#endif
    const struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "logfile", 1, NULL, 'l' },
        { "pidfile", 1, NULL, 'f' },
#ifdef CONFIG_FSFREEZE
        { "fsfreeze-hook", 2, NULL, 'F' },
#endif
        { "verbose", 0, NULL, 'v' },
        { "method", 1, NULL, 'm' },
        { "path", 1, NULL, 'p' },
        { "daemonize", 0, NULL, 'd' },
        { "blacklist", 1, NULL, 'b' },
#ifdef _WIN32
        { "service", 1, NULL, 's' },
#endif
        { "statedir", 1, NULL, 't' },
        { NULL, 0, NULL, 0 }
    };
    int opt_ind = 0, ch, daemonize = 0, i, j, len;
    GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
    GList *blacklist = NULL;
    GAState *s;

    module_call_init(MODULE_INIT_QAPI);

    init_dfl_pathnames();
    pid_filepath = dfl_pathnames.pidfile;
    state_dir = dfl_pathnames.state_dir;

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 'm':
            method = optarg;
            break;
        case 'p':
            path = optarg;
            break;
        case 'l':
            log_filepath = optarg;
            break;
        case 'f':
            pid_filepath = optarg;
            break;
#ifdef CONFIG_FSFREEZE
        case 'F':
            fsfreeze_hook = optarg ? optarg : QGA_FSFREEZE_HOOK_DEFAULT;
            break;
#endif
        case 't':
             state_dir = optarg;
             break;
        case 'v':
            /* enable all log levels */
            log_level = G_LOG_LEVEL_MASK;
            break;
        case 'V':
            printf("QEMU Guest Agent %s\n", QEMU_VERSION);
            return 0;
        case 'd':
            daemonize = 1;
            break;
        case 'b': {
            if (is_help_option(optarg)) {
                qmp_for_each_command(ga_print_cmd, NULL);
                return 0;
            }
            for (j = 0, i = 0, len = strlen(optarg); i < len; i++) {
                if (optarg[i] == ',') {
                    optarg[i] = 0;
                    blacklist = g_list_append(blacklist, &optarg[j]);
                    j = i + 1;
                }
            }
            if (j < i) {
                blacklist = g_list_append(blacklist, &optarg[j]);
            }
            break;
        }
#ifdef _WIN32
        case 's':
            service = optarg;
            if (strcmp(service, "install") == 0) {
                const char *fixed_state_dir;

                /* If the user passed the "-t" option, we save that state dir
                 * in the service. Otherwise we let the service fetch the state
                 * dir from the environment when it starts.
                 */
                fixed_state_dir = (state_dir == dfl_pathnames.state_dir) ?
                                  NULL :
                                  state_dir;
                if (ga_install_vss_provider()) {
                    return EXIT_FAILURE;
                }
                if (ga_install_service(path, log_filepath, fixed_state_dir)) {
                    return EXIT_FAILURE;
                }
                return 0;
            } else if (strcmp(service, "uninstall") == 0) {
                ga_uninstall_vss_provider();
                return ga_uninstall_service();
            } else {
                printf("Unknown service command.\n");
                return EXIT_FAILURE;
            }
            break;
#endif
        case 'h':
            usage(argv[0]);
            return 0;
        case '?':
            g_print("Unknown option, try '%s --help' for more information.\n",
                    argv[0]);
            return EXIT_FAILURE;
        }
    }

#ifdef _WIN32
    /* On win32 the state directory is application specific (be it the default
     * or a user override). We got past the command line parsing; let's create
     * the directory (with any intermediate directories). If we run into an
     * error later on, we won't try to clean up the directory, it is considered
     * persistent.
     */
    if (g_mkdir_with_parents(state_dir, S_IRWXU) == -1) {
        g_critical("unable to create (an ancestor of) the state directory"
                   " '%s': %s", state_dir, strerror(errno));
        return EXIT_FAILURE;
    }
#endif

    s = g_malloc0(sizeof(GAState));
    s->log_level = log_level;
    s->log_file = stderr;
#ifdef CONFIG_FSFREEZE
    s->fsfreeze_hook = fsfreeze_hook;
#endif
    g_log_set_default_handler(ga_log, s);
    g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
    ga_enable_logging(s);
    s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
                                                 state_dir);
    s->pstate_filepath = g_strdup_printf("%s/qga.state", state_dir);
    s->frozen = false;

#ifndef _WIN32
    /* check if a previous instance of qemu-ga exited with filesystems' state
     * marked as frozen. this could be a stale value (a non-qemu-ga process
     * or reboot may have since unfrozen them), but better to require an
     * uneeded unfreeze than to risk hanging on start-up
     */
    struct stat st;
    if (stat(s->state_filepath_isfrozen, &st) == -1) {
        /* it's okay if the file doesn't exist, but if we can't access for
         * some other reason, such as permissions, there's a configuration
         * that needs to be addressed. so just bail now before we get into
         * more trouble later
         */
        if (errno != ENOENT) {
            g_critical("unable to access state file at path %s: %s",
                       s->state_filepath_isfrozen, strerror(errno));
            return EXIT_FAILURE;
        }
    } else {
        g_warning("previous instance appears to have exited with frozen"
                  " filesystems. deferring logging/pidfile creation and"
                  " disabling non-fsfreeze-safe commands until"
                  " guest-fsfreeze-thaw is issued, or filesystems are"
                  " manually unfrozen and the file %s is removed",
                  s->state_filepath_isfrozen);
        s->frozen = true;
    }
#endif

    if (ga_is_frozen(s)) {
        if (daemonize) {
            /* delay opening/locking of pidfile till filesystems are unfrozen */
            s->deferred_options.pid_filepath = pid_filepath;
            become_daemon(NULL);
        }
        if (log_filepath) {
            /* delay opening the log file till filesystems are unfrozen */
            s->deferred_options.log_filepath = log_filepath;
        }
        ga_disable_logging(s);
        qmp_for_each_command(ga_disable_non_whitelisted, NULL);
    } else {
        if (daemonize) {
            become_daemon(pid_filepath);
        }
        if (log_filepath) {
            FILE *log_file = ga_open_logfile(log_filepath);
            if (!log_file) {
                g_critical("unable to open specified log file: %s",
                           strerror(errno));
                goto out_bad;
            }
            s->log_file = log_file;
        }
    }

    /* load persistent state from disk */
    if (!read_persistent_state(&s->pstate,
                               s->pstate_filepath,
                               ga_is_frozen(s))) {
        g_critical("failed to load persistent state");
        goto out_bad;
    }

    blacklist = ga_command_blacklist_init(blacklist);
    if (blacklist) {
        s->blacklist = blacklist;
        do {
            g_debug("disabling command: %s", (char *)blacklist->data);
            qmp_disable_command(blacklist->data);
            blacklist = g_list_next(blacklist);
        } while (blacklist);
    }
    s->command_state = ga_command_state_new();
    ga_command_state_init(s, s->command_state);
    ga_command_state_init_all(s->command_state);
    json_message_parser_init(&s->parser, process_event);
    ga_state = s;
#ifndef _WIN32
    if (!register_signal_handlers()) {
        g_critical("failed to register signal handlers");
        goto out_bad;
    }
#endif

    s->main_loop = g_main_loop_new(NULL, false);
    if (!channel_init(ga_state, method, path)) {
        g_critical("failed to initialize guest agent channel");
        goto out_bad;
    }
#ifndef _WIN32
    g_main_loop_run(ga_state->main_loop);
#else
    if (daemonize) {
        SERVICE_TABLE_ENTRY service_table[] = {
            { (char *)QGA_SERVICE_NAME, service_main }, { NULL, NULL } };
        StartServiceCtrlDispatcher(service_table);
    } else {
        g_main_loop_run(ga_state->main_loop);
    }
#endif

    ga_command_state_cleanup_all(ga_state->command_state);
    ga_channel_free(ga_state->channel);

    if (daemonize) {
        unlink(pid_filepath);
    }
    return 0;

out_bad:
    if (daemonize) {
        unlink(pid_filepath);
    }
    return EXIT_FAILURE;
}
Esempio n. 12
0
int main(int argc, char **argv)
{
    BlockBackend *blk;
    BlockDriverState *bs;
    off_t dev_offset = 0;
    uint16_t nbdflags = 0;
    bool disconnect = false;
    const char *bindto = NULL;
    const char *port = NULL;
    char *sockpath = NULL;
    char *device = NULL;
    off_t fd_size;
    QemuOpts *sn_opts = NULL;
    const char *sn_id_or_name = NULL;
    const char *sopt = "hVb:o:p:rsnP:c:dvk:e:f:tl:x:T:D:";
    struct option lopt[] = {
        { "help", no_argument, NULL, 'h' },
        { "version", no_argument, NULL, 'V' },
        { "bind", required_argument, NULL, 'b' },
        { "port", required_argument, NULL, 'p' },
        { "socket", required_argument, NULL, 'k' },
        { "offset", required_argument, NULL, 'o' },
        { "read-only", no_argument, NULL, 'r' },
        { "partition", required_argument, NULL, 'P' },
        { "connect", required_argument, NULL, 'c' },
        { "disconnect", no_argument, NULL, 'd' },
        { "snapshot", no_argument, NULL, 's' },
        { "load-snapshot", required_argument, NULL, 'l' },
        { "nocache", no_argument, NULL, 'n' },
        { "cache", required_argument, NULL, QEMU_NBD_OPT_CACHE },
        { "aio", required_argument, NULL, QEMU_NBD_OPT_AIO },
        { "discard", required_argument, NULL, QEMU_NBD_OPT_DISCARD },
        { "detect-zeroes", required_argument, NULL,
          QEMU_NBD_OPT_DETECT_ZEROES },
        { "shared", required_argument, NULL, 'e' },
        { "format", required_argument, NULL, 'f' },
        { "persistent", no_argument, NULL, 't' },
        { "verbose", no_argument, NULL, 'v' },
        { "object", required_argument, NULL, QEMU_NBD_OPT_OBJECT },
        { "export-name", required_argument, NULL, 'x' },
        { "description", required_argument, NULL, 'D' },
        { "tls-creds", required_argument, NULL, QEMU_NBD_OPT_TLSCREDS },
        { "image-opts", no_argument, NULL, QEMU_NBD_OPT_IMAGE_OPTS },
        { "trace", required_argument, NULL, 'T' },
        { "fork", no_argument, NULL, QEMU_NBD_OPT_FORK },
        { NULL, 0, NULL, 0 }
    };
    int ch;
    int opt_ind = 0;
    char *end;
    int flags = BDRV_O_RDWR;
    int partition = -1;
    int ret = 0;
    bool seen_cache = false;
    bool seen_discard = false;
    bool seen_aio = false;
    pthread_t client_thread;
    const char *fmt = NULL;
    Error *local_err = NULL;
    BlockdevDetectZeroesOptions detect_zeroes = BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF;
    QDict *options = NULL;
    const char *export_name = NULL;
    const char *export_description = NULL;
    const char *tlscredsid = NULL;
    bool imageOpts = false;
    bool writethrough = true;
    char *trace_file = NULL;
    bool fork_process = false;
    int old_stderr = -1;
    unsigned socket_activation;

    /* The client thread uses SIGTERM to interrupt the server.  A signal
     * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
     */
    struct sigaction sa_sigterm;
    memset(&sa_sigterm, 0, sizeof(sa_sigterm));
    sa_sigterm.sa_handler = termsig_handler;
    sigaction(SIGTERM, &sa_sigterm, NULL);

#ifdef CONFIG_POSIX
    signal(SIGPIPE, SIG_IGN);
#endif

    module_call_init(MODULE_INIT_TRACE);
    qcrypto_init(&error_fatal);

    module_call_init(MODULE_INIT_QOM);
    qemu_add_opts(&qemu_object_opts);
    qemu_add_opts(&qemu_trace_opts);
    qemu_init_exec_dir(argv[0]);

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 's':
            flags |= BDRV_O_SNAPSHOT;
            break;
        case 'n':
            optarg = (char *) "none";
            /* fallthrough */
        case QEMU_NBD_OPT_CACHE:
            if (seen_cache) {
                error_report("-n and --cache can only be specified once");
                exit(EXIT_FAILURE);
            }
            seen_cache = true;
            if (bdrv_parse_cache_mode(optarg, &flags, &writethrough) == -1) {
                error_report("Invalid cache mode `%s'", optarg);
                exit(EXIT_FAILURE);
            }
            break;
        case QEMU_NBD_OPT_AIO:
            if (seen_aio) {
                error_report("--aio can only be specified once");
                exit(EXIT_FAILURE);
            }
            seen_aio = true;
            if (!strcmp(optarg, "native")) {
                flags |= BDRV_O_NATIVE_AIO;
            } else if (!strcmp(optarg, "threads")) {
                /* this is the default */
            } else {
               error_report("invalid aio mode `%s'", optarg);
               exit(EXIT_FAILURE);
            }
            break;
        case QEMU_NBD_OPT_DISCARD:
            if (seen_discard) {
                error_report("--discard can only be specified once");
                exit(EXIT_FAILURE);
            }
            seen_discard = true;
            if (bdrv_parse_discard_flags(optarg, &flags) == -1) {
                error_report("Invalid discard mode `%s'", optarg);
                exit(EXIT_FAILURE);
            }
            break;
        case QEMU_NBD_OPT_DETECT_ZEROES:
            detect_zeroes =
                qapi_enum_parse(BlockdevDetectZeroesOptions_lookup,
                                optarg,
                                BLOCKDEV_DETECT_ZEROES_OPTIONS__MAX,
                                BLOCKDEV_DETECT_ZEROES_OPTIONS_OFF,
                                &local_err);
            if (local_err) {
                error_reportf_err(local_err,
                                  "Failed to parse detect_zeroes mode: ");
                exit(EXIT_FAILURE);
            }
            if (detect_zeroes == BLOCKDEV_DETECT_ZEROES_OPTIONS_UNMAP &&
                !(flags & BDRV_O_UNMAP)) {
                error_report("setting detect-zeroes to unmap is not allowed "
                             "without setting discard operation to unmap");
                exit(EXIT_FAILURE);
            }
            break;
        case 'b':
            bindto = optarg;
            break;
        case 'p':
            port = optarg;
            break;
        case 'o':
                dev_offset = strtoll (optarg, &end, 0);
            if (*end) {
                error_report("Invalid offset `%s'", optarg);
                exit(EXIT_FAILURE);
            }
            if (dev_offset < 0) {
                error_report("Offset must be positive `%s'", optarg);
                exit(EXIT_FAILURE);
            }
            break;
        case 'l':
            if (strstart(optarg, SNAPSHOT_OPT_BASE, NULL)) {
                sn_opts = qemu_opts_parse_noisily(&internal_snapshot_opts,
                                                  optarg, false);
                if (!sn_opts) {
                    error_report("Failed in parsing snapshot param `%s'",
                                 optarg);
                    exit(EXIT_FAILURE);
                }
            } else {
                sn_id_or_name = optarg;
            }
            /* fall through */
        case 'r':
            nbdflags |= NBD_FLAG_READ_ONLY;
            flags &= ~BDRV_O_RDWR;
            break;
        case 'P':
            partition = strtol(optarg, &end, 0);
            if (*end) {
                error_report("Invalid partition `%s'", optarg);
                exit(EXIT_FAILURE);
            }
            if (partition < 1 || partition > 8) {
                error_report("Invalid partition %d", partition);
                exit(EXIT_FAILURE);
            }
            break;
        case 'k':
            sockpath = optarg;
            if (sockpath[0] != '/') {
                error_report("socket path must be absolute");
                exit(EXIT_FAILURE);
            }
            break;
        case 'd':
            disconnect = true;
            break;
        case 'c':
            device = optarg;
            break;
        case 'e':
            shared = strtol(optarg, &end, 0);
            if (*end) {
                error_report("Invalid shared device number '%s'", optarg);
                exit(EXIT_FAILURE);
            }
            if (shared < 1) {
                error_report("Shared device number must be greater than 0");
                exit(EXIT_FAILURE);
            }
            break;
        case 'f':
            fmt = optarg;
            break;
        case 't':
            persistent = 1;
            break;
        case 'x':
            export_name = optarg;
            break;
        case 'D':
            export_description = optarg;
            break;
        case 'v':
            verbose = 1;
            break;
        case 'V':
            version(argv[0]);
            exit(0);
            break;
        case 'h':
            usage(argv[0]);
            exit(0);
            break;
        case '?':
            error_report("Try `%s --help' for more information.", argv[0]);
            exit(EXIT_FAILURE);
        case QEMU_NBD_OPT_OBJECT: {
            QemuOpts *opts;
            opts = qemu_opts_parse_noisily(&qemu_object_opts,
                                           optarg, true);
            if (!opts) {
                exit(EXIT_FAILURE);
            }
        }   break;
        case QEMU_NBD_OPT_TLSCREDS:
            tlscredsid = optarg;
            break;
        case QEMU_NBD_OPT_IMAGE_OPTS:
            imageOpts = true;
            break;
        case 'T':
            g_free(trace_file);
            trace_file = trace_opt_parse(optarg);
            break;
        case QEMU_NBD_OPT_FORK:
            fork_process = true;
            break;
        }
    }

    if ((argc - optind) != 1) {
        error_report("Invalid number of arguments");
        error_printf("Try `%s --help' for more information.\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (qemu_opts_foreach(&qemu_object_opts,
                          user_creatable_add_opts_foreach,
                          NULL, NULL)) {
        exit(EXIT_FAILURE);
    }

    if (!trace_init_backends()) {
        exit(1);
    }
    trace_init_file(trace_file);
    qemu_set_log(LOG_TRACE);

    socket_activation = check_socket_activation();
    if (socket_activation == 0) {
        setup_address_and_port(&bindto, &port);
    } else {
        /* Using socket activation - check user didn't use -p etc. */
        const char *err_msg = socket_activation_validate_opts(device, sockpath,
                                                              bindto, port);
        if (err_msg != NULL) {
            error_report("%s", err_msg);
            exit(EXIT_FAILURE);
        }

        /* qemu-nbd can only listen on a single socket.  */
        if (socket_activation > 1) {
            error_report("qemu-nbd does not support socket activation with %s > 1",
                         "LISTEN_FDS");
            exit(EXIT_FAILURE);
        }
    }

    if (tlscredsid) {
        if (sockpath) {
            error_report("TLS is only supported with IPv4/IPv6");
            exit(EXIT_FAILURE);
        }
        if (device) {
            error_report("TLS is not supported with a host device");
            exit(EXIT_FAILURE);
        }
        if (!export_name) {
            /* Set the default NBD protocol export name, since
             * we *must* use new style protocol for TLS */
            export_name = "";
        }
        tlscreds = nbd_get_tls_creds(tlscredsid, &local_err);
        if (local_err) {
            error_report("Failed to get TLS creds %s",
                         error_get_pretty(local_err));
            exit(EXIT_FAILURE);
        }
    }

    if (disconnect) {
        int nbdfd = open(argv[optind], O_RDWR);
        if (nbdfd < 0) {
            error_report("Cannot open %s: %s", argv[optind],
                         strerror(errno));
            exit(EXIT_FAILURE);
        }
        nbd_disconnect(nbdfd);

        close(nbdfd);

        printf("%s disconnected\n", argv[optind]);

        return 0;
    }

    if ((device && !verbose) || fork_process) {
        int stderr_fd[2];
        pid_t pid;
        int ret;

        if (qemu_pipe(stderr_fd) < 0) {
            error_report("Error setting up communication pipe: %s",
                         strerror(errno));
            exit(EXIT_FAILURE);
        }

        /* Now daemonize, but keep a communication channel open to
         * print errors and exit with the proper status code.
         */
        pid = fork();
        if (pid < 0) {
            error_report("Failed to fork: %s", strerror(errno));
            exit(EXIT_FAILURE);
        } else if (pid == 0) {
            close(stderr_fd[0]);
            ret = qemu_daemon(1, 0);

            /* Temporarily redirect stderr to the parent's pipe...  */
            old_stderr = dup(STDERR_FILENO);
            dup2(stderr_fd[1], STDERR_FILENO);
            if (ret < 0) {
                error_report("Failed to daemonize: %s", strerror(errno));
                exit(EXIT_FAILURE);
            }

            /* ... close the descriptor we inherited and go on.  */
            close(stderr_fd[1]);
        } else {
            bool errors = false;
            char *buf;

            /* In the parent.  Print error messages from the child until
             * it closes the pipe.
             */
            close(stderr_fd[1]);
            buf = g_malloc(1024);
            while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
                errors = true;
                ret = qemu_write_full(STDERR_FILENO, buf, ret);
                if (ret < 0) {
                    exit(EXIT_FAILURE);
                }
            }
            if (ret < 0) {
                error_report("Cannot read from daemon: %s",
                             strerror(errno));
                exit(EXIT_FAILURE);
            }

            /* Usually the daemon should not print any message.
             * Exit with zero status in that case.
             */
            exit(errors);
        }
    }

    if (device != NULL && sockpath == NULL) {
        sockpath = g_malloc(128);
        snprintf(sockpath, 128, SOCKET_PATH, basename(device));
    }

    if (socket_activation == 0) {
        server_ioc = qio_channel_socket_new();
        saddr = nbd_build_socket_address(sockpath, bindto, port);
        if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) {
            object_unref(OBJECT(server_ioc));
            error_report_err(local_err);
            return 1;
        }
    } else {
        /* See comment in check_socket_activation above. */
        assert(socket_activation == 1);
        server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD,
                                               &local_err);
        if (server_ioc == NULL) {
            error_report("Failed to use socket activation: %s",
                         error_get_pretty(local_err));
            exit(EXIT_FAILURE);
        }
    }

    if (qemu_init_main_loop(&local_err)) {
        error_report_err(local_err);
        exit(EXIT_FAILURE);
    }
    bdrv_init();
    atexit(bdrv_close_all);

    srcpath = argv[optind];
    if (imageOpts) {
        QemuOpts *opts;
        if (fmt) {
            error_report("--image-opts and -f are mutually exclusive");
            exit(EXIT_FAILURE);
        }
        opts = qemu_opts_parse_noisily(&file_opts, srcpath, true);
        if (!opts) {
            qemu_opts_reset(&file_opts);
            exit(EXIT_FAILURE);
        }
        options = qemu_opts_to_qdict(opts, NULL);
        qemu_opts_reset(&file_opts);
        blk = blk_new_open(NULL, NULL, options, flags, &local_err);
    } else {
        if (fmt) {
            options = qdict_new();
            qdict_put_str(options, "driver", fmt);
        }
        blk = blk_new_open(srcpath, NULL, options, flags, &local_err);
    }

    if (!blk) {
        error_reportf_err(local_err, "Failed to blk_new_open '%s': ",
                          argv[optind]);
        exit(EXIT_FAILURE);
    }
    bs = blk_bs(blk);

    blk_set_enable_write_cache(blk, !writethrough);

    if (sn_opts) {
        ret = bdrv_snapshot_load_tmp(bs,
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_ID),
                                     qemu_opt_get(sn_opts, SNAPSHOT_OPT_NAME),
                                     &local_err);
    } else if (sn_id_or_name) {
        ret = bdrv_snapshot_load_tmp_by_id_or_name(bs, sn_id_or_name,
                                                   &local_err);
    }
    if (ret < 0) {
        error_reportf_err(local_err, "Failed to load snapshot: ");
        exit(EXIT_FAILURE);
    }

    bs->detect_zeroes = detect_zeroes;
    fd_size = blk_getlength(blk);
    if (fd_size < 0) {
        error_report("Failed to determine the image length: %s",
                     strerror(-fd_size));
        exit(EXIT_FAILURE);
    }

    if (dev_offset >= fd_size) {
        error_report("Offset (%lld) has to be smaller than the image size "
                     "(%lld)",
                     (long long int)dev_offset, (long long int)fd_size);
        exit(EXIT_FAILURE);
    }
    fd_size -= dev_offset;

    if (partition != -1) {
        ret = find_partition(blk, partition, &dev_offset, &fd_size);
        if (ret < 0) {
            error_report("Could not find partition %d: %s", partition,
                         strerror(-ret));
            exit(EXIT_FAILURE);
        }
    }

    exp = nbd_export_new(bs, dev_offset, fd_size, nbdflags, nbd_export_closed,
                         writethrough, NULL, &local_err);
    if (!exp) {
        error_report_err(local_err);
        exit(EXIT_FAILURE);
    }
    if (export_name) {
        nbd_export_set_name(exp, export_name);
        nbd_export_set_description(exp, export_description);
        newproto = true;
    } else if (export_description) {
        error_report("Export description requires an export name");
        exit(EXIT_FAILURE);
    }

    if (device) {
        int ret;

        ret = pthread_create(&client_thread, NULL, nbd_client_thread, device);
        if (ret != 0) {
            error_report("Failed to create client thread: %s", strerror(ret));
            exit(EXIT_FAILURE);
        }
    } else {
        /* Shut up GCC warnings.  */
        memset(&client_thread, 0, sizeof(client_thread));
    }

    nbd_update_server_watch();

    /* now when the initialization is (almost) complete, chdir("/")
     * to free any busy filesystems */
    if (chdir("/") < 0) {
        error_report("Could not chdir to root directory: %s",
                     strerror(errno));
        exit(EXIT_FAILURE);
    }

    if (fork_process) {
        dup2(old_stderr, STDERR_FILENO);
        close(old_stderr);
    }

    state = RUNNING;
    do {
        main_loop_wait(false);
        if (state == TERMINATE) {
            state = TERMINATING;
            nbd_export_close(exp);
            nbd_export_put(exp);
            exp = NULL;
        }
    } while (state != TERMINATED);

    blk_unref(blk);
    if (sockpath) {
        unlink(sockpath);
    }

    qemu_opts_del(sn_opts);

    if (device) {
        void *ret;
        pthread_join(client_thread, &ret);
        exit(ret != NULL);
    } else {
        exit(EXIT_SUCCESS);
    }
}
Esempio n. 13
0
int main(int argc, char **argv)
{
    int ret;

    g_assert(qcrypto_init(NULL) == 0);

    module_call_init(MODULE_INIT_QOM);
    g_test_init(&argc, &argv, NULL);
    setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);

    mkdir(WORKDIR, 0700);

    test_tls_init(KEYFILE);

# define TEST_CHANNEL(name, caCrt,                                      \
                      serverCrt, clientCrt,                             \
                      expectServerFail, expectClientFail,               \
                      hostname, wildcards)                              \
    struct QIOChannelTLSTestData name = {                               \
        caCrt, caCrt, serverCrt, clientCrt,                             \
        expectServerFail, expectClientFail,                             \
        hostname, wildcards                                             \
    };                                                                  \
    g_test_add_data_func("/qio/channel/tls/" # name,                    \
                         &name, test_io_channel_tls);

    /* A perfect CA, perfect client & perfect server */

    /* Basic:CA:critical */
    TLS_ROOT_REQ(cacertreq,
                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercertreq, cacertreq,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    TLS_CERT_REQ(clientcertreq, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);

    const char *const wildcards[] = {
        "C=UK,CN=qemu*",
        NULL,
    };
    TEST_CHANNEL(basic, cacertreq.filename, servercertreq.filename,
                 clientcertreq.filename, false, false,
                 "qemu.org", wildcards);

    ret = g_test_run();

    test_tls_discard_cert(&clientcertreq);
    test_tls_discard_cert(&servercertreq);
    test_tls_discard_cert(&cacertreq);

    test_tls_cleanup(KEYFILE);
    rmdir(WORKDIR);

    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}
Esempio n. 14
0
int main(int argc, char **argv)
{
    const char *sopt = "hVvdm:p:l:f:b:s:t:";
    const char *method = NULL, *path = NULL;
    const char *log_filepath = NULL;
    const char *pid_filepath = QGA_PIDFILE_DEFAULT;
    const char *state_dir = QGA_STATEDIR_DEFAULT;
#ifdef _WIN32
    const char *service = NULL;
#endif
    const struct option lopt[] = {
        { "help", 0, NULL, 'h' },
        { "version", 0, NULL, 'V' },
        { "logfile", 1, NULL, 'l' },
        { "pidfile", 1, NULL, 'f' },
        { "verbose", 0, NULL, 'v' },
        { "method", 1, NULL, 'm' },
        { "path", 1, NULL, 'p' },
        { "daemonize", 0, NULL, 'd' },
        { "blacklist", 1, NULL, 'b' },
#ifdef _WIN32
        { "service", 1, NULL, 's' },
#endif
        { "statedir", 1, NULL, 't' },
        { NULL, 0, NULL, 0 }
    };
    int opt_ind = 0, ch, daemonize = 0, i, j, len;
    GLogLevelFlags log_level = G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL;
    GList *blacklist = NULL;
    GAState *s;

    module_call_init(MODULE_INIT_QAPI);

    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
        switch (ch) {
        case 'm':
            method = optarg;
            break;
        case 'p':
            path = optarg;
            break;
        case 'l':
            log_filepath = optarg;
            break;
        case 'f':
            pid_filepath = optarg;
            break;
        case 't':
             state_dir = optarg;
             break;
        case 'v':
            /* enable all log levels */
            log_level = G_LOG_LEVEL_MASK;
            break;
        case 'V':
            printf("QEMU Guest Agent %s\n", QEMU_VERSION);
            return 0;
        case 'd':
            daemonize = 1;
            break;
        case 'b': {
            char **list_head, **list;
            if (is_help_option(optarg)) {
                list_head = list = qmp_get_command_list();
                while (*list != NULL) {
                    printf("%s\n", *list);
                    g_free(*list);
                    list++;
                }
                g_free(list_head);
                return 0;
            }
            for (j = 0, i = 0, len = strlen(optarg); i < len; i++) {
                if (optarg[i] == ',') {
                    optarg[i] = 0;
                    blacklist = g_list_append(blacklist, &optarg[j]);
                    j = i + 1;
                }
            }
            if (j < i) {
                blacklist = g_list_append(blacklist, &optarg[j]);
            }
            break;
        }
#ifdef _WIN32
        case 's':
            service = optarg;
            if (strcmp(service, "install") == 0) {
                return ga_install_service(path, log_filepath);
            } else if (strcmp(service, "uninstall") == 0) {
                return ga_uninstall_service();
            } else {
                printf("Unknown service command.\n");
                return EXIT_FAILURE;
            }
            break;
#endif
        case 'h':
            usage(argv[0]);
            return 0;
        case '?':
            g_print("Unknown option, try '%s --help' for more information.\n",
                    argv[0]);
            return EXIT_FAILURE;
        }
    }

    s = g_malloc0(sizeof(GAState));
    s->log_level = log_level;
    s->log_file = stderr;
    g_log_set_default_handler(ga_log, s);
    g_log_set_fatal_mask(NULL, G_LOG_LEVEL_ERROR);
    ga_enable_logging(s);
    s->state_filepath_isfrozen = g_strdup_printf("%s/qga.state.isfrozen",
                                                 state_dir);
    s->frozen = false;
#ifndef _WIN32
    /* check if a previous instance of qemu-ga exited with filesystems' state
     * marked as frozen. this could be a stale value (a non-qemu-ga process
     * or reboot may have since unfrozen them), but better to require an
     * uneeded unfreeze than to risk hanging on start-up
     */
    struct stat st;
    if (stat(s->state_filepath_isfrozen, &st) == -1) {
        /* it's okay if the file doesn't exist, but if we can't access for
         * some other reason, such as permissions, there's a configuration
         * that needs to be addressed. so just bail now before we get into
         * more trouble later
         */
        if (errno != ENOENT) {
            g_critical("unable to access state file at path %s: %s",
                       s->state_filepath_isfrozen, strerror(errno));
            return EXIT_FAILURE;
        }
    } else {
        g_warning("previous instance appears to have exited with frozen"
                  " filesystems. deferring logging/pidfile creation and"
                  " disabling non-fsfreeze-safe commands until"
                  " guest-fsfreeze-thaw is issued, or filesystems are"
                  " manually unfrozen and the file %s is removed",
                  s->state_filepath_isfrozen);
        s->frozen = true;
    }
#endif

    if (ga_is_frozen(s)) {
        if (daemonize) {
            /* delay opening/locking of pidfile till filesystem are unfrozen */
            s->deferred_options.pid_filepath = pid_filepath;
            become_daemon(NULL);
        }
        if (log_filepath) {
            /* delay opening the log file till filesystems are unfrozen */
            s->deferred_options.log_filepath = log_filepath;
        }
        ga_disable_logging(s);
        ga_disable_non_whitelisted();
    } else {
        if (daemonize) {
            become_daemon(pid_filepath);
        }
        if (log_filepath) {
            FILE *log_file = fopen(log_filepath, "a");
            if (!log_file) {
                g_critical("unable to open specified log file: %s",
                           strerror(errno));
                goto out_bad;
            }
            s->log_file = log_file;
        }
    }

    if (blacklist) {
        s->blacklist = blacklist;
        do {
            g_debug("disabling command: %s", (char *)blacklist->data);
            qmp_disable_command(blacklist->data);
            blacklist = g_list_next(blacklist);
        } while (blacklist);
    }
    s->command_state = ga_command_state_new();
    ga_command_state_init(s, s->command_state);
    ga_command_state_init_all(s->command_state);
    json_message_parser_init(&s->parser, process_event);
    ga_state = s;
#ifndef _WIN32
    if (!register_signal_handlers()) {
        g_critical("failed to register signal handlers");
        goto out_bad;
    }
#endif

    s->main_loop = g_main_loop_new(NULL, false);
    if (!channel_init(ga_state, method, path)) {
        g_critical("failed to initialize guest agent channel");
        goto out_bad;
    }
#ifndef _WIN32
    g_main_loop_run(ga_state->main_loop);
#else
    if (daemonize) {
        SERVICE_TABLE_ENTRY service_table[] = {
            { (char *)QGA_SERVICE_NAME, service_main }, { NULL, NULL } };
        StartServiceCtrlDispatcher(service_table);
    } else {
        g_main_loop_run(ga_state->main_loop);
    }
#endif

    ga_command_state_cleanup_all(ga_state->command_state);
    ga_channel_free(ga_state->channel);

    if (daemonize) {
        unlink(pid_filepath);
    }
    return 0;

out_bad:
    if (daemonize) {
        unlink(pid_filepath);
    }
    return EXIT_FAILURE;
}
Esempio n. 15
0
int main(int argc, char **argv)
{
    int ret;

    module_call_init(MODULE_INIT_QOM);
    g_test_init(&argc, &argv, NULL);
    setenv("GNUTLS_FORCE_FIPS_MODE", "2", 1);

    mkdir(WORKDIR, 0700);

    test_tls_init(KEYFILE);

# define TLS_TEST_REG(name, isServer, caCrt, crt, expectFail)           \
    struct QCryptoTLSCredsTestData name = {                             \
        isServer, caCrt, crt, expectFail                                \
    };                                                                  \
    g_test_add_data_func("/qcrypto/tlscredsx509/" # name,               \
                         &name, test_tls_creds);                        \

    /* A perfect CA, perfect client & perfect server */

    /* Basic:CA:critical */
    TLS_ROOT_REQ(cacertreq,
                 "UK", "qemu CA", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);

    TLS_CERT_REQ(servercertreq, cacertreq,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    TLS_CERT_REQ(clientcertreq, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);

    TLS_TEST_REG(perfectserver, true,
                 cacertreq.filename, servercertreq.filename, false);
    TLS_TEST_REG(perfectclient, false,
                 cacertreq.filename, clientcertreq.filename, false);


    /* Some other CAs which are good */

    /* Basic:CA:critical */
    TLS_ROOT_REQ(cacert1req,
                 "UK", "qemu CA 1", NULL, NULL, NULL, NULL,
                 true, true, true,
                 false, false, 0,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert1req, cacert1req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);

    /* Basic:CA:not-critical */
    TLS_ROOT_REQ(cacert2req,
                 "UK", "qemu CA 2", NULL, NULL, NULL, NULL,
                 true, false, true,
                 false, false, 0,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert2req, cacert2req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);

    /* Key usage:cert-sign:critical */
    TLS_ROOT_REQ(cacert3req,
                 "UK", "qemu CA 3", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert3req, cacert3req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);

    TLS_TEST_REG(goodca1, true,
                 cacert1req.filename, servercert1req.filename, false);
    TLS_TEST_REG(goodca2, true,
                 cacert2req.filename, servercert2req.filename, false);
    TLS_TEST_REG(goodca3, true,
                 cacert3req.filename, servercert3req.filename, false);

    /* Now some bad certs */

    /* Key usage:dig-sig:not-critical */
    TLS_ROOT_REQ(cacert4req,
                 "UK", "qemu CA 4", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, false, GNUTLS_KEY_DIGITAL_SIGNATURE,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert4req, cacert4req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    /* no-basic */
    TLS_ROOT_REQ(cacert5req,
                 "UK", "qemu CA 5", NULL, NULL, NULL, NULL,
                 false, false, false,
                 false, false, 0,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert5req, cacert5req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    /* Key usage:dig-sig:critical */
    TLS_ROOT_REQ(cacert6req,
                 "UK", "qemu CA 6", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_DIGITAL_SIGNATURE,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercert6req, cacert6req,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);

    /* Technically a CA cert with basic constraints
     * key purpose == key signing + non-critical should
     * be rejected. GNUTLS < 3.1 does not reject it and
     * we don't anticipate them changing this behaviour
     */
    TLS_TEST_REG(badca1, true, cacert4req.filename, servercert4req.filename,
                (GNUTLS_VERSION_MAJOR == 3 && GNUTLS_VERSION_MINOR >= 1) ||
                GNUTLS_VERSION_MAJOR > 3);
    TLS_TEST_REG(badca2, true,
                 cacert5req.filename, servercert5req.filename, true);
    TLS_TEST_REG(badca3, true,
                 cacert6req.filename, servercert6req.filename, true);


    /* Various good servers */
    /* no usage or purpose */
    TLS_CERT_REQ(servercert7req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 false, false, NULL, NULL,
                 0, 0);
    /* usage:cert-sign+dig-sig+encipher:critical */
    TLS_CERT_REQ(servercert8req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
                 GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* usage:cert-sign:not-critical */
    TLS_CERT_REQ(servercert9req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, false, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* purpose:server:critical */
    TLS_CERT_REQ(servercert10req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    /* purpose:server:not-critical */
    TLS_CERT_REQ(servercert11req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, false, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    /* purpose:client+server:critical */
    TLS_CERT_REQ(servercert12req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true,
                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
                 0, 0);
    /* purpose:client+server:not-critical */
    TLS_CERT_REQ(servercert13req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, false,
                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
                 0, 0);

    TLS_TEST_REG(goodserver1, true,
                 cacertreq.filename, servercert7req.filename, false);
    TLS_TEST_REG(goodserver2, true,
                 cacertreq.filename, servercert8req.filename, false);
    TLS_TEST_REG(goodserver3, true,
                 cacertreq.filename, servercert9req.filename, false);
    TLS_TEST_REG(goodserver4, true,
                 cacertreq.filename, servercert10req.filename, false);
    TLS_TEST_REG(goodserver5, true,
                 cacertreq.filename, servercert11req.filename, false);
    TLS_TEST_REG(goodserver6, true,
                 cacertreq.filename, servercert12req.filename, false);
    TLS_TEST_REG(goodserver7, true,
                 cacertreq.filename, servercert13req.filename, false);

    /* Bad servers */

    /* usage:cert-sign:critical */
    TLS_CERT_REQ(servercert14req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* purpose:client:critical */
    TLS_CERT_REQ(servercert15req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);
    /* usage: none:critical */
    TLS_CERT_REQ(servercert16req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true, 0,
                 false, false, NULL, NULL,
                 0, 0);

    TLS_TEST_REG(badserver1, true,
                 cacertreq.filename, servercert14req.filename, true);
    TLS_TEST_REG(badserver2, true,
                 cacertreq.filename, servercert15req.filename, true);
    TLS_TEST_REG(badserver3, true,
                 cacertreq.filename, servercert16req.filename, true);



    /* Various good clients */
    /* no usage or purpose */
    TLS_CERT_REQ(clientcert1req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 false, false, NULL, NULL,
                 0, 0);
    /* usage:cert-sign+dig-sig+encipher:critical */
    TLS_CERT_REQ(clientcert2req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT |
                 GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* usage:cert-sign:not-critical */
    TLS_CERT_REQ(clientcert3req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, false, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* purpose:client:critical */
    TLS_CERT_REQ(clientcert4req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);
    /* purpose:client:not-critical */
    TLS_CERT_REQ(clientcert5req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, false, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);
    /* purpose:client+client:critical */
    TLS_CERT_REQ(clientcert6req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true,
                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
                 0, 0);
    /* purpose:client+client:not-critical */
    TLS_CERT_REQ(clientcert7req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, false,
                 GNUTLS_KP_TLS_WWW_CLIENT, GNUTLS_KP_TLS_WWW_SERVER,
                 0, 0);

    TLS_TEST_REG(goodclient1, false,
                 cacertreq.filename, clientcert1req.filename, false);
    TLS_TEST_REG(goodclient2, false,
                 cacertreq.filename, clientcert2req.filename, false);
    TLS_TEST_REG(goodclient3, false,
                 cacertreq.filename, clientcert3req.filename, false);
    TLS_TEST_REG(goodclient4, false,
                 cacertreq.filename, clientcert4req.filename, false);
    TLS_TEST_REG(goodclient5, false,
                 cacertreq.filename, clientcert5req.filename, false);
    TLS_TEST_REG(goodclient6, false,
                 cacertreq.filename, clientcert6req.filename, false);
    TLS_TEST_REG(goodclient7, false,
                 cacertreq.filename, clientcert7req.filename, false);

    /* Bad clients */

    /* usage:cert-sign:critical */
    TLS_CERT_REQ(clientcert8req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    /* purpose:client:critical */
    TLS_CERT_REQ(clientcert9req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 false, false, 0,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    /* usage: none:critical */
    TLS_CERT_REQ(clientcert10req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true, 0,
                 false, false, NULL, NULL,
                 0, 0);

    TLS_TEST_REG(badclient1, false,
                 cacertreq.filename, clientcert8req.filename, true);
    TLS_TEST_REG(badclient2, false,
                 cacertreq.filename, clientcert9req.filename, true);
    TLS_TEST_REG(badclient3, false,
                 cacertreq.filename, clientcert10req.filename, true);



    /* Expired stuff */

    TLS_ROOT_REQ(cacertexpreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, -1);
    TLS_CERT_REQ(servercertexpreq, cacertexpreq,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    TLS_CERT_REQ(servercertexp1req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, -1);
    TLS_CERT_REQ(clientcertexp1req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, -1);

    TLS_TEST_REG(expired1, true,
                 cacertexpreq.filename, servercertexpreq.filename, true);
    TLS_TEST_REG(expired2, true,
                 cacertreq.filename, servercertexp1req.filename, true);
    TLS_TEST_REG(expired3, false,
                 cacertreq.filename, clientcertexp1req.filename, true);


    /* Not activated stuff */

    TLS_ROOT_REQ(cacertnewreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 1, 2);
    TLS_CERT_REQ(servercertnewreq, cacertnewreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    TLS_CERT_REQ(servercertnew1req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 1, 2);
    TLS_CERT_REQ(clientcertnew1req, cacertreq,
                 "UK", "qemu", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 1, 2);

    TLS_TEST_REG(inactive1, true,
                 cacertnewreq.filename, servercertnewreq.filename, true);
    TLS_TEST_REG(inactive2, true,
                 cacertreq.filename, servercertnew1req.filename, true);
    TLS_TEST_REG(inactive3, false,
                 cacertreq.filename, clientcertnew1req.filename, true);

    TLS_ROOT_REQ(cacertrootreq,
                 "UK", "qemu root", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(cacertlevel1areq, cacertrootreq,
                 "UK", "qemu level 1a", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(cacertlevel1breq, cacertrootreq,
                 "UK", "qemu level 1b", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(cacertlevel2areq, cacertlevel1areq,
                 "UK", "qemu level 2a", NULL, NULL, NULL, NULL,
                 true, true, true,
                 true, true, GNUTLS_KEY_KEY_CERT_SIGN,
                 false, false, NULL, NULL,
                 0, 0);
    TLS_CERT_REQ(servercertlevel3areq, cacertlevel2areq,
                 "UK", "qemu.org", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_SERVER, NULL,
                 0, 0);
    TLS_CERT_REQ(clientcertlevel2breq, cacertlevel1breq,
                 "UK", "qemu client level 2b", NULL, NULL, NULL, NULL,
                 true, true, false,
                 true, true,
                 GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
                 true, true, GNUTLS_KP_TLS_WWW_CLIENT, NULL,
                 0, 0);

    gnutls_x509_crt_t certchain[] = {
        cacertrootreq.crt,
        cacertlevel1areq.crt,
        cacertlevel1breq.crt,
        cacertlevel2areq.crt,
    };

    test_tls_write_cert_chain(WORKDIR "cacertchain-ctx.pem",
                              certchain,
                              G_N_ELEMENTS(certchain));

    TLS_TEST_REG(chain1, true,
                 WORKDIR "cacertchain-ctx.pem",
                 servercertlevel3areq.filename, false);
    TLS_TEST_REG(chain2, false,
                 WORKDIR "cacertchain-ctx.pem",
                 clientcertlevel2breq.filename, false);

    /* Some missing certs - first two are fatal, the last
     * is ok
     */
    TLS_TEST_REG(missingca, true,
                 "cacertdoesnotexist.pem",
                 servercert1req.filename, true);
    TLS_TEST_REG(missingserver, true,
                 cacert1req.filename,
                 "servercertdoesnotexist.pem", true);
    TLS_TEST_REG(missingclient, false,
                 cacert1req.filename,
                 "clientcertdoesnotexist.pem", false);

    ret = g_test_run();

    test_tls_discard_cert(&cacertreq);
    test_tls_discard_cert(&cacert1req);
    test_tls_discard_cert(&cacert2req);
    test_tls_discard_cert(&cacert3req);
    test_tls_discard_cert(&cacert4req);
    test_tls_discard_cert(&cacert5req);
    test_tls_discard_cert(&cacert6req);

    test_tls_discard_cert(&servercertreq);
    test_tls_discard_cert(&servercert1req);
    test_tls_discard_cert(&servercert2req);
    test_tls_discard_cert(&servercert3req);
    test_tls_discard_cert(&servercert4req);
    test_tls_discard_cert(&servercert5req);
    test_tls_discard_cert(&servercert6req);
    test_tls_discard_cert(&servercert7req);
    test_tls_discard_cert(&servercert8req);
    test_tls_discard_cert(&servercert9req);
    test_tls_discard_cert(&servercert10req);
    test_tls_discard_cert(&servercert11req);
    test_tls_discard_cert(&servercert12req);
    test_tls_discard_cert(&servercert13req);
    test_tls_discard_cert(&servercert14req);
    test_tls_discard_cert(&servercert15req);
    test_tls_discard_cert(&servercert16req);

    test_tls_discard_cert(&clientcertreq);
    test_tls_discard_cert(&clientcert1req);
    test_tls_discard_cert(&clientcert2req);
    test_tls_discard_cert(&clientcert3req);
    test_tls_discard_cert(&clientcert4req);
    test_tls_discard_cert(&clientcert5req);
    test_tls_discard_cert(&clientcert6req);
    test_tls_discard_cert(&clientcert7req);
    test_tls_discard_cert(&clientcert8req);
    test_tls_discard_cert(&clientcert9req);
    test_tls_discard_cert(&clientcert10req);

    test_tls_discard_cert(&cacertexpreq);
    test_tls_discard_cert(&servercertexpreq);
    test_tls_discard_cert(&servercertexp1req);
    test_tls_discard_cert(&clientcertexp1req);

    test_tls_discard_cert(&cacertnewreq);
    test_tls_discard_cert(&servercertnewreq);
    test_tls_discard_cert(&servercertnew1req);
    test_tls_discard_cert(&clientcertnew1req);

    test_tls_discard_cert(&cacertrootreq);
    test_tls_discard_cert(&cacertlevel1areq);
    test_tls_discard_cert(&cacertlevel1breq);
    test_tls_discard_cert(&cacertlevel2areq);
    test_tls_discard_cert(&servercertlevel3areq);
    test_tls_discard_cert(&clientcertlevel2breq);
    unlink(WORKDIR "cacertchain-ctx.pem");

    test_tls_cleanup(KEYFILE);
    rmdir(WORKDIR);

    return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
}