static gpgme_error_t spawn_start (gpgme_ctx_t ctx, int synchronous, const char *file, const char *argv[], gpgme_data_t datain, gpgme_data_t dataout, gpgme_data_t dataerr, unsigned int flags) { gpgme_error_t err; const char *tmp_argv[2]; if (ctx->protocol != GPGME_PROTOCOL_SPAWN) return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL); err = _gpgme_op_reset (ctx, synchronous); if (err) return err; if (!argv) { tmp_argv[0] = _gpgme_get_basename (file); tmp_argv[1] = NULL; argv = tmp_argv; } return _gpgme_engine_op_spawn (ctx->engine, file, argv, datain, dataout, dataerr, flags); }
static gpgme_error_t engspawn_start (engine_spawn_t esp, const char *file, const char *argv[], unsigned int flags) { gpgme_error_t err; int i, n; int status; struct spawn_fd_item_s *fd_list; pid_t pid; unsigned int spflags; const char *save_argv0 = NULL; if (!esp || !file || !argv || !argv[0]) return gpg_error (GPG_ERR_INV_VALUE); spflags = 0; if ((flags & GPGME_SPAWN_DETACHED)) spflags |= IOSPAWN_FLAG_DETACHED; if ((flags & GPGME_SPAWN_ALLOW_SET_FG)) spflags |= IOSPAWN_FLAG_ALLOW_SET_FG; err = build_fd_data_map (esp); if (err) return err; n = 0; for (i = 0; esp->fd_data_map[i].data; i++) n++; fd_list = calloc (n+1, sizeof *fd_list); if (!fd_list) return gpg_error_from_syserror (); /* Build the fd list for the child. */ n = 0; for (i = 0; esp->fd_data_map[i].data; i++) { fd_list[n].fd = esp->fd_data_map[i].peer_fd; fd_list[n].dup_to = esp->fd_data_map[i].dup_to; n++; } fd_list[n].fd = -1; fd_list[n].dup_to = -1; if (argv[0] && !*argv[0]) { save_argv0 = argv[0]; argv[0] = _gpgme_get_basename (file); } status = _gpgme_io_spawn (file, (char * const *)argv, spflags, fd_list, NULL, NULL, &pid); if (save_argv0) argv[0] = save_argv0; free (fd_list); if (status == -1) return gpg_error_from_syserror (); for (i = 0; esp->fd_data_map[i].data; i++) { err = add_io_cb (esp, esp->fd_data_map[i].fd, esp->fd_data_map[i].inbound, esp->fd_data_map[i].inbound ? _gpgme_data_inbound_handler : _gpgme_data_outbound_handler, esp->fd_data_map[i].data, &esp->fd_data_map[i].tag); if (err) return err; /* FIXME: kill the child */ } engspawn_io_event (esp, GPGME_EVENT_START, NULL); return 0; }
static gpgme_error_t g13_new (void **engine, const char *file_name, const char *home_dir) { gpgme_error_t err = 0; engine_g13_t g13; const char *pgmname; int argc; const char *argv[5]; char *dft_display = NULL; char dft_ttyname[64]; char *dft_ttytype = NULL; char *optstr; g13 = calloc (1, sizeof *g13); if (!g13) return gpg_error_from_syserror (); g13->status_cb.fd = -1; g13->status_cb.dir = 1; g13->status_cb.tag = 0; g13->status_cb.data = g13; pgmname = file_name ? file_name : _gpgme_get_default_g13_name (); argc = 0; argv[argc++] = _gpgme_get_basename (pgmname); if (home_dir) { argv[argc++] = "--homedir"; argv[argc++] = home_dir; } argv[argc++] = "--server"; argv[argc++] = NULL; err = assuan_new_ext (&g13->assuan_ctx, GPG_ERR_SOURCE_GPGME, &_gpgme_assuan_malloc_hooks, _gpgme_assuan_log_cb, NULL); if (err) goto leave; assuan_ctx_set_system_hooks (g13->assuan_ctx, &_gpgme_assuan_system_hooks); #if USE_DESCRIPTOR_PASSING err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv, NULL, NULL, NULL, ASSUAN_PIPE_CONNECT_FDPASSING); #else err = assuan_pipe_connect (g13->assuan_ctx, pgmname, argv, NULL, NULL, NULL, 0); #endif if (err) goto leave; err = _gpgme_getenv ("DISPLAY", &dft_display); if (err) goto leave; if (dft_display) { if (asprintf (&optstr, "OPTION display=%s", dft_display) < 0) { free (dft_display); err = gpg_error_from_syserror (); goto leave; } free (dft_display); err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); free (optstr); if (err) goto leave; } if (isatty (1)) { int rc; rc = ttyname_r (1, dft_ttyname, sizeof (dft_ttyname)); /* Even though isatty() returns 1, ttyname_r() may fail in many ways, e.g., when /dev/pts is not accessible under chroot. */ if (!rc) { if (asprintf (&optstr, "OPTION ttyname=%s", dft_ttyname) < 0) { err = gpg_error_from_syserror (); goto leave; } err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); free (optstr); if (err) goto leave; err = _gpgme_getenv ("TERM", &dft_ttytype); if (err) goto leave; if (dft_ttytype) { if (asprintf (&optstr, "OPTION ttytype=%s", dft_ttytype) < 0) { free (dft_ttytype); err = gpg_error_from_syserror (); goto leave; } free (dft_ttytype); err = assuan_transact (g13->assuan_ctx, optstr, NULL, NULL, NULL, NULL, NULL, NULL); free (optstr); if (err) goto leave; } } } #ifdef HAVE_W32_SYSTEM /* Under Windows we need to use AllowSetForegroundWindow. Tell g13 to tell us when it needs it. */ if (!err) { err = assuan_transact (g13->assuan_ctx, "OPTION allow-pinentry-notify", NULL, NULL, NULL, NULL, NULL, NULL); if (gpg_err_code (err) == GPG_ERR_UNKNOWN_OPTION) err = 0; /* This is a new feature of g13. */ } #endif /*HAVE_W32_SYSTEM*/ leave: if (err) g13_release (g13); else *engine = g13; return err; }