pike.git / lib / modules / Process.pmod

version» Context lines:

pike.git/lib/modules/Process.pmod:1:   #pike __REAL_VERSION__      constant create_process = __builtin.create_process;      #if constant(__builtin.TraceProcess)   constant TraceProcess = __builtin.TraceProcess;   #endif    - #if defined(__NT__) || defined(__amigaos__) || defined(__OS2__) + #if defined(__NT__)   constant path_separator = ";";   #else   constant path_separator = ":";   #endif      #if constant(Stdio.__HAVE_SEND_FD__)   protected Stdio.File forkd_pipe;   protected create_process forkd_pid;      //! Encoder for data to be sent to @[Tools.Standalone.forkd].
pike.git/lib/modules/Process.pmod:172:       mapping(string:mixed) new_modifiers = (modifiers || ([])) + ([]);       if (new_modifiers->keep_signals) {    // This option is currently not supported with forkd.    m_delete(new_modifiers, "forkd");    }      #if constant(Stdio.__HAVE_SEND_FD__)    // Forkd mode requires send_fd(). -  if (zero_type(new_modifiers->forkd)) new_modifiers->forkd = forkd_default; +  if (undefinedp(new_modifiers->forkd)) +  new_modifiers->forkd = forkd_default;    if (new_modifiers->forkd && assert_forkd()) {    process_fd = Stdio.File();    forkd_pipe->    send_fd(process_fd->pipe(Stdio.PROP_BIDIRECTIONAL|Stdio.PROP_SEND_FD));    while (forkd_pipe->write("\0") < 0)    ;       m_delete(new_modifiers, "forkd");    __callback = m_delete(new_modifiers, "callback");    -  if (zero_type(new_modifiers->uid)) { +  if (undefinedp(new_modifiers->uid)) {    new_modifiers->uid = geteuid(); -  if (zero_type(new_modifiers->gid)) { +  if (undefinedp(new_modifiers->gid)) {    new_modifiers->gid = getegid();    }    if (!new_modifiers->setgroups) {    new_modifiers->setgroups = getgroups();    }    } else if (new_modifiers->noinitgroups) {    if (!new_modifiers->setgroups) {    new_modifiers->setgroups = getgroups();    }    }
pike.git/lib/modules/Process.pmod:223: Inside #if constant(Stdio.__HAVE_SEND_FD__)
   ForkdEncoder(process_fd));    data = sprintf("%4c%s", sizeof(data), data);    // Wait for forkd to acknowledge the process_fd.    if (process_fd->read(4) != "\0\0\0\0") {    process_fd->close();    process_fd = UNDEFINED;    error("Failed to create spawn request.\n");    }    int bytes = process_fd->write(data);    if (bytes != sizeof(data)) { +  int fd_errno = process_fd->errno();    process_fd->close();    process_fd = UNDEFINED; -  error("Failed to write spawn request (%d != %d).\n", -  bytes, sizeof(data)); +  error("Failed to write spawn request (%d != %d, errno: %d, errmsg: %s).\n", +  bytes, sizeof(data), fd_errno, strerror(fd_errno) || "?");    }    process_backend = Pike.SmallBackend();    process_backend->add_file(process_fd);    process_fd->set_nonblocking(got_data, UNDEFINED, got_close);       // Wait for the process to fork (or fail).    while (__status == -1) {    process_backend(3600.0);    }   
pike.git/lib/modules/Process.pmod:292: Inside #if constant(Stdio.__HAVE_SEND_FD__)
   switch(tag) {    case "ERROR":    __result = 255;    __status = 2;    do_close();    error(packet);    break;    case "PID":    __pid = packet;    if (__status == -1) __status = 0; -  if (__callback) __callback(this_object()); +  if (__callback) __callback(this);    break;    case "SIGNAL":    __last_signal = packet;    break;    case "START":    __status = 0; -  if (__callback) __callback(this_object()); +  if (__callback) __callback(this);    break;    case "STOP":    __status = 1; -  if (__callback) __callback(this_object()); +  if (__callback) __callback(this);    break;    case "EXIT":    __result = packet;    __status = 2;    do_close(); -  if (__callback) __callback(this_object()); +  if (__callback) __callback(this);    break;    default:    __result = 255;    __status = 2;    do_close();    error("Unsupported packet from forkd: %O\n", tag);    break;    }    }    }
pike.git/lib/modules/Process.pmod:339: Inside #if constant(Stdio.__HAVE_SEND_FD__)
   }       protected void do_poll(float t)    {    mixed err = catch {    process_backend && process_backend(t);    return;    };    // Filter errors about the backend already running.    if (arrayp(err) && sizeof(err) && -  stringp(err[0]) && has_prefix(err[0], "Backend already ")) return; +  stringp(err[0]) && has_prefix(err[0], "Backend already ")) { +  sleep(t); +  return; +  }    throw(err);    }       protected void do_poll_loop()    {    process_poll = UNDEFINED;    if (!process_backend) return;    do_poll(0.0);    process_poll = call_out(do_poll_loop, 0.1);    }
pike.git/lib/modules/Process.pmod:366: Inside #if constant(Stdio.__HAVE_SEND_FD__)
      int(-1..2) status()    {    do_poll(0.0);    return ::status();    }       int wait()    {    if (process_backend) { -  do_poll(0.0); -  while (__status <= 0) { -  do_poll(3600.0); -  } +  float t = 0.0; +  do { +  do_poll(t); +  if (t < 1.0) t += 0.1; +  } while (__status <= 0);    return __result;    }    return ::wait();    }   #endif /* __HAVE_SEND_FD__ */    -  protected void destroy() { +  protected void _destruct() {    remove_call_out(watcher);    remove_call_out(killer);   #if constant(Stdio.__HAVE_SEND_FD__)    remove_call_out(process_poll);   #endif    }       protected void watcher() {    // It was another sigchld, but not one from our process.    if(status()==0)
pike.git/lib/modules/Process.pmod:434:   //!   //! @param argv   //! Arguments for the new process.   //!   //! @param options   //! Process creation options. See @[Process.Process] for details. May also   //! specify "add_predefines", "add_program_path", or "add_include_path" in   //! order to include these components in command path (module path is   //! included by default.)   //! + //! @param launcher + //! Optional launcher prefix command used to spawn the pike binary. + //! + //! When used this is typically something like + //! @expr{({ "/usr/bin/valgrind" })@}. + //! + //! Defaults to the empty array. + //!   //! @seealso   //! @[Process.Process] - Process spawn_pike(array(string) argv, void|mapping(string:mixed) options) + Process spawn_pike(array(string) argv, void|mapping(string:mixed) options, +  array(string)|void launcher)   {    if (!runpike) {    array(string) res = ({    master()->_pike_file_name,    });    if (master()->_master_file_name)    res+=({"-m"+master()->_master_file_name});    foreach (master()->pike_module_path;;string path)    res+=({"-M" + path});    if(options && options->add_predefines)
pike.git/lib/modules/Process.pmod:473:    }       if (sizeof(res) && !has_value(res[0],"/")   #ifdef __NT__    && !has_value(res[0], "\\")   #endif /* __NT__ */    )    res[0] = search_path(res[0]);    runpike = res;    } -  return Process(runpike + argv, options); +  if (!launcher) launcher = ({}); +  return Process(launcher + runpike + argv, options);   }      //! Easy and lazy way of using @[Process.Process] that runs a process   //! and returns a mapping with the output and exit code without   //! having to make sure you read nonblocking yourself.   //!   //! @param args   //! Either a command line array, as the command_args   //! argument to @[create_process()], or a string that   //! will be splitted into a command line array by   //! calling @[split_quoted_string()] in an operating   //! system dependant mode.   //! @param modifiers   //! It takes all the modifiers @[Process.Process] accepts, with - //! the exception of stdout and stderr. Since the point of this - //! function is to handle those you can not supply your own. + //! the exception of stdout and stderr. Each must be either absent, or + //! a function accepting a string; if present, the functions will be called + //! whenever output is made on the corresponding stream, otherwise the data + //! will be collected and returned in the result mapping.   //! - //! If @expr{modifiers->stdin@} is set to a string it will automaticly be + //! If @expr{modifiers->stdin@} is set to a string it will automatically be   //! converted to a pipe that is fed to stdin of the started process.   //!   //! @seealso   //! @[Process.Process] @[create_process]   //!   //! @returns   //! @mapping   //! @member string "stdout" - //! Everything the process wrote on stdout. + //! Everything the process wrote on stdout, unless a stdout function was + //! provided.   //! @member string "stderr" - //! Everything the process wrote on stderr. + //! Everything the process wrote on stderr, similarly.   //! @member int "exitcode"   //! The process' exitcode.   //! @endmapping   //!   //! @note   //! As the entire output of stderr and stdout is stored in the   //! returned mapping it could potentially grow until memory runs out. - //! It is therefor adviceable to set up rlimits if the output has a - //! potential to be very large. + //! It is therefore advisable to set up rlimits if the output has a + //! potential to be very large, or else provide functions to handle + //! partial data.   //!   //! @example   //! Process.run( ({ "ls", "-l" }) );   //! Process.run( ({ "ls", "-l" }), ([ "cwd":"/etc" ]) );   //! Process.run( "ls -l" );   //! Process.run( "awk -F: '{print $2}'", ([ "stdin":"foo:2\nbar:17\n" ]) );   mapping run(string|array(string) cmd, void|mapping modifiers)   {    string gotstdout="", gotstderr="", stdin_str;    int exitcode;       if(!modifiers)    modifiers = ([]);    -  if(modifiers->stdout || modifiers->stderr) +  if((modifiers->stdout && !callablep(modifiers->stdout)) +  || (modifiers->stderr && !callablep(modifiers->stderr)))    throw( ({ "Can not redirect stdout or stderr in Process.run, "    "please use Process.Process instead.", backtrace() }) );       Stdio.File mystdout = Stdio.File();    Stdio.File mystderr = Stdio.File();    Stdio.File mystdin;       object p;    if(stringp(modifiers->stdin))    {
pike.git/lib/modules/Process.pmod:575: Inside #if 0 //constant(Thread.Thread)
      exitcode = p->wait();    threads->wait();   #else    Pike.SmallBackend backend = Pike.SmallBackend();       mystdout->set_backend (backend);    mystderr->set_backend (backend);       mystdout->set_read_callback( lambda( mixed i, string data) { -  gotstdout += data; +  if (modifiers->stdout) modifiers->stdout(data); +  else gotstdout += data;    } );    mystderr->set_read_callback( lambda( mixed i, string data) { -  gotstderr += data; +  if (modifiers->stderr) modifiers->stderr(data); +  else gotstderr += data;    } );    mystdout->set_close_callback( lambda () {    mystdout->set_read_callback(0);    catch { mystdout->close(); };    mystdout = 0;    });    mystderr->set_close_callback( lambda () {    mystderr->set_read_callback(0);    catch { mystderr->close(); };    mystderr = 0;    });    -  + #if constant(Shuffler)    if (mystdin) {    Shuffler.Shuffler sfr = Shuffler.Shuffler();    sfr->set_backend (backend);    Shuffler.Shuffle sf = sfr->shuffle( mystdin );    sf->add_source(stdin_str);    sf->set_done_callback (lambda () {    catch { mystdin->close(); };    mystdin = 0;    });    sf->start();    } -  + #endif       while( mystdout || mystderr || mystdin )    backend( 1.0 );       exitcode = p->wait();   #endif       return ([ "stdout" : gotstdout,    "stderr" : gotstderr,    "exitcode": exitcode ]);
pike.git/lib/modules/Process.pmod:891:    if(stdin) data->stdin=stdin;    if(stdout) data->stdout=stdout;    if(stderr) data->stderr=stderr;   #if defined(__NT__)    // if the command string command is not quoted, add double quotes to    // make sure it is not modified by create_process    if (sizeof(command) <= 1 ||    command[0] != '\"' || command[sizeof(command)-1] != '\"')    command = "\"" + command + "\"";    return Process(({ "cmd", "/c", command }),data); - #elif defined(__amigaos__) -  return Process(split_quoted_string(command),data); - #else /* !__NT__||__amigaos__ */ + #else /* !__NT__ */    return Process(({ "/bin/sh", "-c", command }),data); - #endif /* __NT__||__amigaos__ */ + #endif /* __NT__ */   }      //! @decl string popen(string command)   //! Executes @[command] as a shell statement ("@expr{/bin/sh -c   //! @[command]@}" for Unix, "@expr{cmd /c @[command]@}" for Windows),   //! waits until it has finished and returns the result as a string.   //!   //! @seealso   //! @[system], @[spawn]   
pike.git/lib/modules/Process.pmod:1008: Inside #if undefined(__NT__) and #if constant(fork) && constant(exece)
      pie=Stdio.File();    pied=pie->pipe();       if(!(pid=fork()))    {    mixed err=catch    {    if(cwd && !cd(cwd))    { -  error( "pike: cannot change cwd to "+cwd+ -  ": "+strerror(errno())+"\n" ); +  error( "pike: cannot change cwd to %O: %s.\n", cwd, +  strerror(errno()) );    }       if (sizeof(fdp)>0 && fdp[0]) fdp[0]->dup2(Stdio.File("stdin"));    if (sizeof(fdp)>1 && fdp[1]) fdp[1]->dup2(Stdio.File("stdout"));    if (sizeof(fdp)>2 && fdp[2]) fdp[2]->dup2(Stdio.File("stderr"));    /* dup2 fdd[3..] here FIXME FIXME */    foreach (fd_to_close, Stdio.File f)    if (objectp(f)) { f->close(); destruct(f); }    pie->close();    destruct(pie);       pied->set_close_on_exec(1);       if (env)    exece(cmd,args||({}),env);    else    exece(cmd,args||({}));    -  error( "pike: failed to exece "+cmd+ -  ": "+strerror(errno())+"\n" ); +  error( "pike: failed to exece %O: %s.\n", cmd, +  strerror(errno()) );    };       pied->write(encode_value(err));    exit(1);    }       foreach (fdp,object f) if (objectp(f)) { f->close(); destruct(f); }       pied->close();    destruct(pied);
pike.git/lib/modules/Process.pmod:1189:    opened += ({ ret });    return ret;    }    else if (objectp(f))    return f;    else    return 0;    };       if (low_daemon(nochdir, noclose) == -1) -  error("Failed to daemonize: " + strerror(errno())+"\n"); +  error("Failed to daemonize: %s.\n", strerror(errno()));    if (!modifiers)    return;       if (modifiers["cwd"])    cd(modifiers["cwd"]);       if (modifiers["stdin"])    getfd(modifiers["stdin"])->dup2(Stdio.stdin);       if (modifiers["stdout"])    getfd(modifiers["stdout"])->dup2(Stdio.stdout);       if (modifiers["stderr"])    getfd(modifiers["stderr"])->dup2(Stdio.stderr);       opened->close();   }   #endif