Example #1
0
int search_path(char *result, char *prog, char *exts, char *var)
{
   /* search for a file on the disk, searching PATH if needed */

   char *p;
   int pos;
   strcpy(result,prog);

   if (find_program(result,exts)) {       /* look in current directory */
      return TRUE;
   }

   p=getenv(var);
   if (p!=NULL) {
      while(*p) {
	 while ((*p==' ') || (*p==',') || (*p==';'))
	    p++;
	 if(*p) {
	    pos=0;
	    result[0]=0;
	    while ((*p) && (*p!=' ') && (*p!=',') && (*p!=';')) {
	       result[pos++]=*(p++);
	       result[pos]=0;
	    }
	    append_backslash(result);
	    strcat(result,prog);
	    if (find_program(result,exts))
	       return TRUE;
	 }
      }
   }
   return FALSE;
}
Example #2
0
bool Ext2::check_support() {
	can_create = !find_program("mkfs.ext2").empty();
	can_resize = !find_program("resize2fs").empty();
	can_check = !find_program("e2fsck").empty();
	can_diskusage = !find_program("dumpe2fs").empty();
	can_getlabel = !find_program("e2label").empty();
	can_setlabel = can_getlabel;
}
Example #3
0
/**
 * wait_on_program
 *
 * Arguments: <program_id>
 *
 * Wait for the specified program to complete and exit.
 **/
static int wait_on_program(int argc, char **argv)
{
	struct program *prog;
	int program_id;
	int rc;

	program_id = strtoul(argv[1], NULL, 0);
	if (program_id <= 0) {
		LOG_ERROR("program ID must be a positive integer.");
		return EINVAL;
	}

	prog = find_program(program_id);
	if (!prog) {
		LOG_ERROR("Can't find program with ID %d.", program_id);
		return EINVAL;
	}

	waitpid(prog->pid, &rc, 0);

	/* The program has exitted, but if there was a context loaded on that
	 * process, it will still have the latest counts available to read.
	 */

	remove_program(prog);
	free(prog);

	LOG_INFO("Waited for program %d to complete.", program_id);

	return 0;
}
Example #4
0
/**
 * resume_program
 *
 * Arguments: <program_id>
 *
 * A program started with run_program must be 'resumed' before it actually
 * begins running. This allows us to load a context to the process and
 * start the counters before the program executes any code.
 **/
static int resume_program(int argc, char **argv)
{
	struct program *prog;
	int program_id;
	int rc;

	program_id = strtoul(argv[1], NULL, 0);
	if (program_id <= 0) {
		LOG_ERROR("program ID must be a positive integer.");
		return EINVAL;
	}

	prog = find_program(program_id);
	if (!prog) {
		LOG_ERROR("Can't find program with ID %d.", program_id);
		return EINVAL;
	}

	/* Call ptrace to resume execution of the process. If a context has
	 * been loaded and the counters started, this is where monitoring
	 * is effectively activated.
	 */
	rc = ptrace(PTRACE_DETACH, prog->pid, NULL, 0);
	if (rc) {
		rc = errno;
		LOG_ERROR("Error detaching program %d.\n", prog->id);
		return rc;
	}

	LOG_INFO("Resumed program %d.", program_id);

	return 0;
}
Example #5
0
void pipeline::

set_stage(std::string const& program_name , std::string const& stage_path) {

  program_iterator p_it(find_program(program_name));

  if(p_it != programs_.end()) {

    stage_iterator s_it(find_stage(stage_path));

    if(s_it == stages_.end()) {

      std::shared_ptr<stage> s(std::make_shared<stage>(stage(stage_path)));

      stages_.push_back(s);

      p_it->define_stage(s);
    }

    else {

      std::shared_ptr<stage> s(*s_it);

      p_it->define_stage(s);
    }
  }

  else {

    std::cerr << std::endl
              << "program [" << program_name << "] doesn't exist"
              << std::endl;
  }
}
Example #6
0
void pipeline::

enable(std::string const& program_name) {

  program_iterator p_it(find_program(program_name));

  if(p_it != programs_.end()) {

    if(p_it->id() != 0) {

      glUseProgram(p_it->id());

      for(auto l_it(links_.begin()) ; l_it != links_.end() ; ++l_it) {

        if(l_it->program_id_ == p_it->id()) uniforms_.load(*l_it);
      }
    }

    else {

      std::cerr << std::endl
                << "program [" << program_name << "] isn't linked"
                << std::endl;
    }    
  }

  else {

    std::cerr << std::endl
              << "program [" << program_name << "] doesn't exists"
              << std::endl;
  }
}
Example #7
0
str
find_program_plus_libsfs (const char *program)
{
  str s = fix_exec_path (program);
  if (!s || !execok (s))
    s = find_program (program);
  return s;
}
Example #8
0
gboolean __scan_usb_lsusb(void)
{
    static gchar *lsusb_path = NULL;
    int usb_device_number = 0;
    FILE *lsusb;
    FILE *temp_lsusb;
    char buffer[512], *temp;

    if (!lsusb_path) {
        if (!(lsusb_path = find_program("lsusb"))) {
            DEBUG("lsusb not found");

            return FALSE;
        }
    }

    temp = g_strdup_printf("%s -v | tr '[]' '()'", lsusb_path);
    if (!(lsusb = popen(temp, "r"))) {
        DEBUG("cannot run %s", lsusb_path);

        g_free(temp);
        return FALSE;
    }

    temp_lsusb = tmpfile();
    if (!temp_lsusb) {
        DEBUG("cannot create temporary file for lsusb");

        return FALSE;
    }

    while (fgets(buffer, sizeof(buffer), lsusb)) {
        fputs(buffer, temp_lsusb);
    }

    pclose(lsusb);

    // rewind file so we can read from it
    fseek(temp_lsusb, 0, SEEK_SET);

    g_free(temp);

    if (usb_list) {
       moreinfo_del_with_prefix("DEV:USB");
	g_free(usb_list);
    }
    usb_list = g_strdup("[USB Devices]\n");

    while (fgets(buffer, sizeof(buffer), temp_lsusb)) {
        if (g_str_has_prefix(buffer, "Bus ")) {
           __scan_usb_lsusb_add_device(buffer, sizeof(buffer), temp_lsusb, ++usb_device_number);
        }
    }
    
    fclose(temp_lsusb);
    
    return usb_device_number > 0;
}
static inline struct gs_program *get_shader_program(struct gs_device *device)
{
	struct gs_program *program = find_program(device);

	if (!program)
		program = gs_program_create(device);

	return program;
}
Example #10
0
static void
__scan_battery_apcupsd(void)
{
    GHashTable  *ups_data;
    FILE	*apcaccess;
    char	buffer[512], *apcaccess_path;
    int		i;

    apcaccess_path = find_program("apcaccess");
    if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) {
      /* first line isn't important */
      if (fgets(buffer, 512, apcaccess)) {
        /* allocate the key, value hash table */
        ups_data = g_hash_table_new(g_str_hash, g_str_equal);

        /* read up all the apcaccess' output, saving it in the key, value hash table */
        while (fgets(buffer, 512, apcaccess)) {
          buffer[9] = '\0';

          g_hash_table_insert(ups_data,
                              g_strdup(g_strstrip(buffer)),
                              g_strdup(g_strstrip(buffer + 10)));
        }

        /* builds the ups info string, respecting the field order as found in ups_fields */
        for (i = 0; i < G_N_ELEMENTS(ups_fields); i++) {
          if (!ups_fields[i].name) {
            /* there's no name: make a group with the key as its name */
            battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key);
          } else {
            /* there's a name: adds a line */
            battery_list = h_strdup_cprintf("%s=%s\n", battery_list,
                                            ups_fields[i].name,
                                            g_hash_table_lookup(ups_data, ups_fields[i].key));
          }
        }

        g_hash_table_destroy(ups_data);
      }

      pclose(apcaccess);
    }
    
    g_free(apcaccess_path);
}
Example #11
0
void pipeline::

add_program(std::string const& name) {

  program_iterator p_it(find_program(name));

  if(p_it == programs_.end()) {

    programs_.push_back(program(name));
  }

  else {

    std::cerr << std::endl
              << "program [" << name << "] already exists"
              << std::endl;
  }
}
// load_program
thread_id
load_program(const char* const* args, int32 argCount, bool traceLoading)
{
	// clone the argument vector so that we can change it
	const char** mutableArgs = new const char*[argCount];
	for (int i = 0; i < argCount; i++)
		mutableArgs[i] = args[i];

	// resolve the program path
	std::string programPath;
	status_t error = find_program(args[0], programPath);
	if (error != B_OK) {
		delete[] mutableArgs;
		return error;
	}
	mutableArgs[0] = programPath.c_str();

	// count environment variables
	int envCount = 0;
	while (environ[envCount] != NULL)
		envCount++;

	// flatten the program args and environment
	char** flatArgs = NULL;
	size_t flatArgsSize;
	error = __flatten_process_args(mutableArgs, argCount, environ, envCount,
		&flatArgs, &flatArgsSize);

	// load the program
	thread_id thread;
	if (error == B_OK) {
		thread = _kern_load_image(flatArgs, flatArgsSize, argCount, envCount,
			B_NORMAL_PRIORITY, (traceLoading ? 0 : B_WAIT_TILL_LOADED), -1, 0);

		free(flatArgs);
	} else
		thread = error;

	delete[] mutableArgs;

	return thread;
}
Example #13
0
void pipeline::

set_link(std::string const& program_name , std::string const& uniform_name) {

  program_iterator p_it(find_program(program_name));

  if(p_it != programs_.end()) {

    if(uniforms_.aviable(uniform_name)) {

      if(p_it->id() != 0) {

        links_.push_back(uniform_link(p_it->id(),uniform_name));
      }

      else {

        std::cerr << std::endl
                  << "program [" << program_name << "] isn't linked"
                  << std::endl;
      }
    }

    else {

      std::cerr << std::endl
                << "uniform [" << uniform_name << "] doesn't exist"
                << std::endl;
    }
  }

  else {

    std::cerr << std::endl
              << "program [" << program_name << "] doesn't exist"
              << std::endl;
  }
}
Example #14
0
void
agent_spawn (bool opt_verbose)
{
  // start agent if needed (sfsagent -c)
  if (!isagentrunning ()) {
    if (opt_verbose)
      warn << "No existing agent found; spawning a new one...\n";
    str sa = find_program ("sfsagent");
    vec<const char *> av;

    av.push_back (sa.cstr ());
    av.push_back ("-c");
    av.push_back (NULL);
    pid_t pid = spawn (av[0], av.base ());
    if (waitpid (pid, NULL, 0) < 0)
      fatal << "Could not spawn a new SFS agent: " <<
	strerror (errno) << "\n";
  }
  else {
    if (opt_verbose)
      warn << "Contacting existing agent...\n";
  }
}
Example #15
0
/**
 * load_context
 *
 * Arguments: <context_id> <event_set_id> <program_id|cpu_id>
 *
 * Call the pfm_load_context system-call to load a perfmon context into the
 * system's performance monitoring unit.
 **/
static int load_context(int argc, char **argv)
{
	struct context *ctx;
	struct event_set *evt;
	struct program *prog;
	cpu_set_t old_cpu_set;
	int ctx_id, event_set_id, program_id;
	int system_wide, rc;
	int load_pid =  0;

	ctx_id = strtoul(argv[1], NULL, 0);
	event_set_id = strtoul(argv[2], NULL, 0);
	program_id = strtoul(argv[3], NULL, 0);

	if (ctx_id <= 0 || event_set_id < 0 || program_id < 0) {
		LOG_ERROR("context ID, event-set ID, and program/CPU ID must "
			  "be positive integers.");
		return EINVAL;
	}

	/* Find the context, event_set, and program in the global lists. */
	ctx = find_context(ctx_id);
	if (!ctx) {
		LOG_ERROR("Can't find context with ID %d.", ctx_id);
		return EINVAL;
	}

	evt = find_event_set(ctx, event_set_id);
	if (!evt) {
		LOG_ERROR("Can't find event-set with ID %d in context %d.",
			  event_set_id, ctx_id);
		return EINVAL;
	}
	system_wide = ctx->ctx_flags & PFM_FL_SYSTEM_WIDE;
	if (system_wide) {
		if (ctx->cpu >= 0) {
			LOG_ERROR("Trying to load context %d which is already "
				  "loaded on CPU %d.\n", ctx_id, ctx->cpu);
			return EBUSY;
		}

		rc = set_affinity(program_id, &old_cpu_set);
		if (rc) {
			return rc;
		}

		/* Specify the CPU as the PID. */
		load_pid = program_id;
	} else {
		prog = find_program(program_id);
		if (!prog) {
			LOG_ERROR("Can't find program with ID %d.", program_id);
			return EINVAL;
		}
		load_pid = prog->pid;
	}

	rc = pfm_attach(ctx->fd, 0, load_pid);
	if (rc) {
		rc = errno;
		LOG_ERROR("pfm_attach  system call returned "
			  "an error: %d.", rc);
		return rc;
	}

	if (system_wide) {
		/* Keep track of which CPU this context is loaded on. */
		ctx->cpu = program_id;

		revert_affinity(&old_cpu_set);
	}

	LOG_INFO("Loaded context %d, event-set %d onto %s %d.",
		 ctx_id, event_set_id, system_wide ? "cpu" : "program",
		 program_id);

	return 0;
}
Example #16
0
int main(int argc, const char ** argv)
{
    std::string program;
    std::vector<std::string> program_arguments;
    int max_restarts = -1;
    
    {
        program_arguments::parser p;
        
        p.add_option(
            'm',
            "max-restarts",
            "N",
            "Limit the number of restarts",
            max_restarts
        );
        
        p.add_argument("PROGRAM-ARGUMENTS", program_arguments);
        
        p.parse(argc, argv);
    }
    
    if(program_arguments.size() == 0)
    {
        std::cerr<<"Not enough program arguments"<<std::endl;
        return 1;
    }
    
    std::string program_filename;
    if(!find_program(program_arguments[0], program_filename))
    {
        std::cout<<program_arguments[0]<<" file not found"<<std::endl;
        return 1;
    }
    
    bool repeat = false;
    int count_restarts = 0;
    
    do
    {
        repeat = false;
        
        create_process(program_filename, program_arguments);
        
        int child_exit_status = 0;
        if(::wait(&child_exit_status) == -1) return 1;
        
        if(WIFSIGNALED(child_exit_status))
        {
            int signal = WTERMSIG(child_exit_status);
            
            switch(signal)
            {
                case SIGILL:
                case SIGABRT:
                case SIGFPE:
                case SIGSEGV:
                case SIGPIPE:
                    repeat = true;
                    break;
                default:;
            }
        }
    }
    while(repeat && (max_restarts == -1 || ++count_restarts <= max_restarts));
    
    return 0;
}
Example #17
0
void
scan_pci_do(void)
{
    FILE *lspci;
    gchar buffer[256], *buf, *strhash = NULL, *strdevice = NULL;
    gchar *category = NULL, *name = NULL, *icon, *lspci_path, *command_line = NULL;
    gint n = 0, x = 0;
    
    if ((lspci_path = find_program("lspci")) == NULL) {
      goto pci_error;
    } else {
      command_line = g_strdup_printf("%s -v", lspci_path);
    }
    
    if (!_pci_devices) {
      _pci_devices = g_hash_table_new(g_str_hash, g_str_equal);
    }

    buf = g_build_filename(g_get_home_dir(), ".hardinfo", "pci.ids", NULL);
    if (!g_file_test(buf, G_FILE_TEST_EXISTS)) {
      DEBUG("using system-provided PCI IDs");
      g_free(buf);
      if (!(lspci = popen(command_line, "r"))) {
        goto pci_error;
      }
    } else {
      gchar *tmp;
      
      tmp = g_strdup_printf("%s -i '%s'", command_line, buf);
      g_free(buf);
      buf = tmp;
      
      DEBUG("using updated PCI IDs (from %s)", buf);
      if (!(lspci = popen(tmp, "r"))) {
        g_free(buf);
        goto pci_error;
      } else {
        g_free(buf);
      }
    }

    while (fgets(buffer, 256, lspci)) {
	buf = g_strstrip(buffer);

	if (!strncmp(buf, "Flags", 5)) {
	    gint irq = 0, freq = 0, latency = 0, i;
	    gchar **list;
	    gboolean bus_master;

	    buf += 7;

	    bus_master = FALSE;

	    list = g_strsplit(buf, ", ", 10);
	    for (i = 0; i <= 10; i++) {
		if (!list[i])
		    break;

		if (!strncmp(list[i], "IRQ", 3))
		    sscanf(list[i], "IRQ %d", &irq);
		else if (strstr(list[i], "Mhz"))
		    sscanf(list[i], "%dMhz", &freq);
		else if (!strncmp(list[i], "bus master", 10))
		    bus_master = TRUE;
		else if (!strncmp(list[i], "latency", 7))
		    sscanf(list[i], "latency %d", &latency);
	    }
	    g_strfreev(list);

	    if (irq)
		strdevice = h_strdup_cprintf("IRQ=%d\n", strdevice, irq);
	    if (freq)
		strdevice = h_strdup_cprintf("Frequency=%dMHz\n", strdevice, freq);
	    if (latency)
		strdevice = h_strdup_cprintf("Latency=%d\n", strdevice, latency);

	    strdevice = h_strdup_cprintf("Bus Master=%s\n", strdevice, bus_master ? "Yes" : "No");
	} else if (!strncmp(buf, "Kernel modules", 14)) {
	    WALK_UNTIL(' ');
	    WALK_UNTIL(':');
	    buf++;
	    
	    strdevice = h_strdup_cprintf("Kernel modules=%s\n", strdevice, buf);
	} else if (!strncmp(buf, "Subsystem", 9)) {
	    WALK_UNTIL(' ');
	    buf++;
	    const gchar *oem_vendor_url = vendor_get_url(buf);
            if (oem_vendor_url) 
                strdevice = h_strdup_cprintf("OEM Vendor=%s (%s)\n",
                                            strdevice,
                                            vendor_get_name(buf),
                                            oem_vendor_url);
	} else if (!strncmp(buf, "Capabilities", 12)
		   && !strstr(buf, "only to root") && 
		      !strstr(buf, "access denied")) {
	    WALK_UNTIL(' ');
	    WALK_UNTIL(']');
	    buf++;
	    strdevice = h_strdup_cprintf("Capability#%d=%s\n", strdevice, ++x, buf);
	} else if (!strncmp(buf, "Memory at", 9) && strstr(buf, "[size=")) {
	    gint mem;
	    gchar unit;
	    gboolean prefetch;
	    gboolean _32bit;

	    prefetch = strstr(buf, "non-prefetchable") ? FALSE : TRUE;
	    _32bit = strstr(buf, "32-bit") ? TRUE : FALSE;

	    WALK_UNTIL('[');
	    sscanf(buf, "[size=%d%c", &mem, &unit);

	    strdevice = h_strdup_cprintf("Memory#%d=%d%cB (%s%s)\n",
					strdevice, ++x,
					mem,
					(unit == ']') ? ' ' : unit,
					_32bit ? "32-bit, " : "",
					prefetch ? "prefetchable" :
					"non-prefetchable");

	} else if (!strncmp(buf, "I/O ports at", 12)) {
	    guint io_addr, io_size;

	    sscanf(buf, "I/O ports at %x [size=%d]", &io_addr, &io_size);

	    strdevice =
		h_strdup_cprintf("I/O ports at#%d=0x%x - 0x%x\n",
				strdevice, ++x, io_addr,
				io_addr + io_size - 1);
	} else if ((buf[0] >= '0' && buf[0] <= '9') && (buf[4] == ':' || buf[2] == ':')) {
	    gint bus, device, function, domain;
	    gpointer start, end;

	    if (strdevice != NULL && strhash != NULL) {
                moreinfo_add_with_prefix("DEV", strhash, strdevice);
                g_free(strhash);
                g_free(category);
                g_free(name);
	    }

	    if (buf[4] == ':') {
		sscanf(buf, "%x:%x:%x.%d", &domain, &bus, &device, &function);
	    } else {
	    	/* lspci without domain field */
	    	sscanf(buf, "%x:%x.%x", &bus, &device, &function);
	    	domain = 0;
	    }

	    WALK_UNTIL(' ');

	    start = buf;

	    WALK_UNTIL(':');
	    end = buf + 1;
	    *buf = 0;

	    buf = start + 1;
	    category = g_strdup(buf);

	    buf = end;

            if (strstr(category, "RAM memory")) icon = "mem";
            else if (strstr(category, "Multimedia")) icon = "media";
            else if (strstr(category, "USB")) icon = "usb";
            else icon = "pci";
            
	    name = g_strdup(buf);
            g_hash_table_insert(_pci_devices,
                                g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
                                name);

	    strhash = g_strdup_printf("PCI%d", n);
	    strdevice = g_strdup_printf("[Device Information]\n"
					"Name=%s\n"
					"Class=%s\n"
					"Domain=%d\n"
					"Bus, device, function=%d, %d, %d\n",
					name, category, domain, bus,
					device, function);
            
            const gchar *url = vendor_get_url(name);
            if (url) {
                strdevice = h_strdup_cprintf("Vendor=%s (%s)\n",
                                            strdevice,
                                            vendor_get_name(name),
                                            url);
            }
            
            g_hash_table_insert(_pci_devices,
                                g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),
                                g_strdup(name));
            
	    pci_list = h_strdup_cprintf("$PCI%d$%s=%s\n", pci_list, n, category, name);

	    n++;
	}
    }
    
    if (pclose(lspci)) {
pci_error:
        /* error (no pci, perhaps?) */
        pci_list = g_strconcat(pci_list, "No PCI devices found=\n", NULL);
    } else if (strhash) {
	/* insert the last device */
        moreinfo_add_with_prefix("DEV", strhash, strdevice);
        g_free(strhash);
        g_free(category);
        g_free(name);
    }
    
    g_free(lspci_path);
    g_free(command_line);
}
Example #18
0
/**
 * run_program
 *
 * Arguments: <program_id> <program name and arguments>
 *
 * Start the specified program. After fork'ing but before exec'ing, ptrace
 * the child so it will remain suspended until a corresponding resume_program
 * command. We do this so we can load a context for the program before it
 * actually starts running. This logic is taken from the task.c example in
 * the libpfm source code tree.
 **/
static int run_program(int argc, char **argv)
{
	struct program *prog;
	int program_id;
	pid_t pid;
	int rc;

	program_id = strtoul(argv[1], NULL, 0);
	if (program_id <= 0) {
		LOG_ERROR("program ID must be a positive integer.");
		return EINVAL;
	}

	/* Make sure we haven't already started a program with this ID. */
	prog = find_program(program_id);
	if (prog) {
		LOG_ERROR("Program with ID %d already exists.", program_id);
		return EINVAL;
	}

	prog = calloc(1, sizeof(*prog));
	if (!prog) {
		LOG_ERROR("Can't allocate new program structure to run '%s'.",
			  argv[2]);
		return ENOMEM;
	}

	prog->id = program_id;

	pid = fork();
	if (pid == -1) {
		/* Error fork'ing. */
		LOG_ERROR("Unable to fork child process.");
		return EINVAL;

	} else if (!pid) {
		/* Child */

		/* This will cause the program to stop before executing the
		 * first user level instruction. We can only load a context
		 * if the program is in the STOPPED state. This child
		 * process will sit here until we've process a resume_program
		 * command.
		 */
		rc = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
		if (rc) {
			rc = errno;
			LOG_ERROR("Error ptrace'ing '%s': %d", argv[2], rc);
			exit(rc);
		}

		execvp(argv[2], argv + 2);

		rc = errno;
		LOG_ERROR("Error exec'ing '%s': %d", argv[2], rc);
		exit(rc);
	}

	/* Parent */
	prog->pid = pid;
	insert_program(prog);

	/* Wait for the child to exec. */
	waitpid(pid, &rc, WUNTRACED);

	/* Check if process exited early. */
	if (WIFEXITED(rc)) {
		LOG_ERROR("Program '%s' exited too early with status "
			  "%d", argv[2], WEXITSTATUS(rc));
		return WEXITSTATUS(rc);
	}

	LOG_INFO("Started program %d: '%s'.", program_id, argv[2]);

	return 0;
}
Example #19
0
static int win_spawn(const char *cmd, const char **argv, const char **envp,
		     const char *cwd, HANDLE handles[3], int background,
		     int shell)
{
    char *args = make_command_line(shell, cmd, argv);
    char *env = make_environment(envp);
    char *program = shell ? NULL : find_program(cmd);
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    BOOL result;
    DWORD exitcode;
    int i;

    if (!shell) {
	G_debug(3, "win_spawn: program = %s", program);

	if (!program) {
	    G_free(args);
	    G_free(env);
	    return -1;
	}
    }

    G_debug(3, "win_spawn: args = %s", args);

    memset(&si, 0, sizeof(si));
    si.cb = sizeof(si);

    si.dwFlags |= STARTF_USESTDHANDLES;
    si.hStdInput  = handles[0];
    si.hStdOutput = handles[1];
    si.hStdError  = handles[2];

    result = CreateProcess(
	program,	/* lpApplicationName */
	args,		/* lpCommandLine */
	NULL,		/* lpProcessAttributes */
	NULL,		/* lpThreadAttributes */
	1,		/* bInheritHandles */
	0,		/* dwCreationFlags */
	env,		/* lpEnvironment */
	cwd,		/* lpCurrentDirectory */
	&si,		/* lpStartupInfo */
	&pi		/* lpProcessInformation */
	);

    G_free(args);
    G_free(env);
    G_free(program);

    if (!result) {
	G_warning(_("CreateProcess() failed: error = %d"), GetLastError());
	return -1;
    }

    CloseHandle(pi.hThread);

    for (i = 0; i < 3; i++)
	if (handles[i] != INVALID_HANDLE_VALUE)
	    CloseHandle(handles[i]);

    if (!background) {
	WaitForSingleObject(pi.hProcess, INFINITE);
	if (!GetExitCodeProcess(pi.hProcess, &exitcode))
	    return -1;
	CloseHandle(pi.hProcess);
	return (int) exitcode;
    }

    CloseHandle(pi.hProcess);

    return pi.dwProcessId;
}