src/bringup/bin/bootsvc/main.cc
// Launch the next process in the boot chain.
// It will receive:
// - stdout & stderr wired up to a debuglog handle
// - A namespace containing:
//   - A /boot directory, connected to the bootfs service hosted by bootsvc
//   - A /svc directory, containing other services hosted by bootsvc, including:
//     - fuchsia.boot.Arguments, which provides boot cmdline arguments
//     - fuchsia.boot.Items, which allows querying for certain ZBI items
//     - fuchsia.boot.{ReadOnly|WriteOnly}Log, which provides debuglog handles
//     - fuchsia.boot.RootJob, which provides root job handles
//     - fuchsia.boot.RootResource, which provides root resource handles
// - A loader that can load libraries from /boot, hosted by bootsvc
//
// If the next process terminates, bootsvc will quit.
Launch the next process in the boot chain.
It will receive:
stdout & stderr wired up to a debuglog handle
A namespace containing:
A /boot directory, connected to the bootfs service hosted by bootsvc
A /svc directory, containing other services hosted by bootsvc, including:
fuchsia.boot.Arguments, which provides boot cmdline arguments
fuchsia.boot.Items, which allows querying for certain ZBI items
fuchsia.boot.{ReadOnly|WriteOnly}Log, which provides debuglog handles
fuchsia.boot.RootJob, which provides root job handles
fuchsia.boot.RootResource, which provides root resource handles
A loader that can load libraries from /boot, hosted by bootsvc

If the next process terminates, bootsvc will quit.
Launch the next process in the boot chain . It will receive : stdout & stderr wired up to a debuglog handle A namespace containing : A / boot directory connected to the bootfs service hosted by bootsvc A / svc directory containing other services hosted by bootsvc including : fuchsia . boot . Arguments which provides boot cmdline arguments fuchsia . boot . Items which allows querying for certain ZBI items fuchsia . boot . { ReadOnly|WriteOnly } Log which provides debuglog handles fuchsia . boot . RootJob which provides root job handles fuchsia . boot . RootResource which provides root resource handles A loader that can load libraries from / boot hosted by bootsvc If the next process terminates bootsvc will quit .
void LaunchNextProcess(fbl::RefPtr<bootsvc::BootfsService> bootfs,
                       fbl::RefPtr<bootsvc::SvcfsService> svcfs,
                       std::shared_ptr<bootsvc::BootfsLoaderService> loader_svc,
                       const zx::resource& root_rsrc, const zx::debuglog& log, async::Loop& loop,
                       const zx::vmo& bootargs_vmo, const uint64_t bootargs_size) {
  const char* bootsvc_next = getenv("bootsvc.next");
  if (bootsvc_next == nullptr) {
    bootsvc_next =
        "bin/component_manager,"
        "fuchsia-boot:///#meta/root.cm,"
        "--config,"
        "/boot/config/component_manager,"
        "--use-builtin-process-launcher,"
        "--maintain-utc-clock";
  }
  printf("bootsvc: bootsvc.next = %s\n", bootsvc_next);
  fbl::Vector<fbl::String> next_args = bootsvc::SplitString(bootsvc_next, ',');
  zx::vmo program;
  uint64_t file_size;
  const char* next_program = next_args[0].c_str();
  zx_status_t status = bootfs->Open(next_program, true, &program, &file_size);
  ZX_ASSERT_MSG(status == ZX_OK, "bootsvc: failed to open '%s': %s\n", next_program,
                zx_status_get_string(status));
  zx::channel bootfs_conn;
  status = bootfs->CreateRootConnection(&bootfs_conn);
  ZX_ASSERT_MSG(status == ZX_OK, "bootfs conn creation failed: %s\n", zx_status_get_string(status));
  zx::channel svcfs_conn;
  status = svcfs->CreateRootConnection(&svcfs_conn);
  ZX_ASSERT_MSG(status == ZX_OK, "svcfs conn creation failed: %s\n", zx_status_get_string(status));
  const char* nametable[2] = {};
  uint32_t count = 0;
  launchpad_t* lp;
  launchpad_create(0, next_program, &lp);
  {
    zx::status<zx::channel> loader_conn = loader_svc->Connect();
    ZX_ASSERT_MSG(loader_conn.is_ok(), "failed to connect to BootfsLoaderService : %s\n",
                  loader_conn.status_string());
    zx_handle_t old = launchpad_use_loader_service(lp, loader_conn.value().release());
    ZX_ASSERT(old == ZX_HANDLE_INVALID);
  }
  launchpad_load_from_vmo(lp, program.release());
  launchpad_clone(lp, LP_CLONE_DEFAULT_JOB);
  launchpad_add_handle(lp, bootfs_conn.release(), PA_HND(PA_NS_DIR, count));
  nametable[count++] = "/boot";
  launchpad_add_handle(lp, svcfs_conn.release(), PA_HND(PA_NS_DIR, count));
  nametable[count++] = "/svc";
  zx::resource root_rsrc_dup;
  status = root_rsrc.duplicate(ZX_RIGHT_SAME_RIGHTS, &root_rsrc_dup);
  ZX_ASSERT_MSG(status == ZX_OK && root_rsrc_dup.is_valid(), "Failed to duplicate root resource");
  launchpad_add_handle(lp, root_rsrc_dup.release(), PA_HND(PA_RESOURCE, 0));
  int argc = static_cast<int>(next_args.size());
  const char* argv[argc];
  for (int i = 0; i < argc; ++i) {
    argv[i] = next_args[i].c_str();
  }
  launchpad_set_args(lp, argc, argv);
  ZX_ASSERT(count <= std::size(nametable));
  launchpad_set_nametable(lp, count, nametable);
  std::vector<char> env(bootargs_size);
  std::vector<char*> envp;
  status = bootargs_vmo.read(env.data(), 0, bootargs_size);
  ZX_ASSERT_MSG(status == ZX_OK, "failed to read bootargs from vmo: %s",
                zx_status_get_string(status));
  uint64_t last_env_start = 0;
  uint64_t i;
  for (i = 0; i < bootargs_size; i++) {
    if (env[i] == 0) {
      envp.push_back(&env[last_env_start]);
      last_env_start = i + 1;
    }
  }
  envp.push_back(nullptr);
  status = launchpad_set_environ(lp, envp.data());
  if (status != ZX_OK) {
    launchpad_abort(lp, status, "bootsvc: cannot set up environment");
  }
  zx::debuglog log_dup;
  status = log.duplicate(ZX_RIGHT_SAME_RIGHTS, &log_dup);
  if (status != ZX_OK) {
    launchpad_abort(lp, status, "bootsvc: cannot duplicate debuglog handle");
  } else {
    launchpad_add_handle(lp, log_dup.release(), PA_HND(PA_FD, FDIO_FLAG_USE_FOR_STDIO));
  }
  const char* errmsg;
  zx::process proc_handle;
  status = launchpad_go(lp, proc_handle.reset_and_get_address(), &errmsg);
  if (status != ZX_OK) {
    printf("bootsvc: launchpad %s failed: %s: %s\n", next_program, errmsg,
           zx_status_get_string(status));
    return;
  }
  printf("bootsvc: Launched %s\n", next_program);
  zx_signals_t observed;
  zx_status_t termination_result =
      proc_handle.wait_one(ZX_TASK_TERMINATED, zx::time::basic_time::infinite(), &observed);
  if (termination_result != ZX_OK) {
    printf("bootsvc: failure waiting for next process termination %i\n", termination_result);
  }
  loop.Quit();
}
void LaunchNextProcess ( fbl :: RefPtr < bootsvc :: BootfsService > bootfs , fbl :: RefPtr < bootsvc :: SvcfsService > svcfs , std :: shared_ptr < bootsvc :: BootfsLoaderService > loader_svc , const zx :: resource & root_rsrc , const zx :: debuglog & log , async :: Loop & loop , const zx :: vmo & bootargs_vmo , const uint64_t bootargs_size ) { const char * bootsvc_next = getenv ( " " ) ; if ( bootsvc_next == nullptr ) { bootsvc_next = " " " " " " " " " " " " ; } printf ( " \n " , bootsvc_next ) ; fbl :: Vector < fbl :: String > next_args = bootsvc :: SplitString ( bootsvc_next , ' ' ) ; zx :: vmo program ; uint64_t file_size ; const char * next_program = next_args [ 0 ] . c_str ( ) ; zx_status_t status = bootfs -> Open ( next_program , true , & program , & file_size ) ; ZX_ASSERT_MSG ( status == ZX_OK , " \n " , next_program , zx_status_get_string ( status ) ) ; zx :: channel bootfs_conn ; status = bootfs -> CreateRootConnection ( & bootfs_conn ) ; ZX_ASSERT_MSG ( status == ZX_OK , " \n " , zx_status_get_string ( status ) ) ; zx :: channel svcfs_conn ; status = svcfs -> CreateRootConnection ( & svcfs_conn ) ; ZX_ASSERT_MSG ( status == ZX_OK , " \n " , zx_status_get_string ( status ) ) ; const char * nametable [ 2 ] = { } ; uint32_t count = 0 ; launchpad_t * lp ; launchpad_create ( 0 , next_program , & lp ) ; { zx :: status < zx :: channel > loader_conn = loader_svc -> Connect ( ) ; ZX_ASSERT_MSG ( loader_conn . is_ok ( ) , " \n " , loader_conn . status_string ( ) ) ; zx_handle_t old = launchpad_use_loader_service ( lp , loader_conn . value ( ) . release ( ) ) ; ZX_ASSERT ( old == ZX_HANDLE_INVALID ) ; } launchpad_load_from_vmo ( lp , program . release ( ) ) ; launchpad_clone ( lp , LP_CLONE_DEFAULT_JOB ) ; launchpad_add_handle ( lp , bootfs_conn . release ( ) , PA_HND ( PA_NS_DIR , count ) ) ; nametable [ count ++ ] = " " ; launchpad_add_handle ( lp , svcfs_conn . release ( ) , PA_HND ( PA_NS_DIR , count ) ) ; nametable [ count ++ ] = " " ; zx :: resource root_rsrc_dup ; status = root_rsrc . duplicate ( ZX_RIGHT_SAME_RIGHTS , & root_rsrc_dup ) ; ZX_ASSERT_MSG ( status == ZX_OK && root_rsrc_dup . is_valid ( ) , " " ) ; launchpad_add_handle ( lp , root_rsrc_dup . release ( ) , PA_HND ( PA_RESOURCE , 0 ) ) ; int argc = static_cast < int > ( next_args . size ( ) ) ; const char * argv [ argc ] ; for ( int i = 0 ; i < argc ; ++ i ) { argv [ i ] = next_args [ i ] . c_str ( ) ; } launchpad_set_args ( lp , argc , argv ) ; ZX_ASSERT ( count <= std :: size ( nametable ) ) ; launchpad_set_nametable ( lp , count , nametable ) ; std :: vector < char > env ( bootargs_size ) ; std :: vector < char * > envp ; status = bootargs_vmo . read ( env . data ( ) , 0 , bootargs_size ) ; ZX_ASSERT_MSG ( status == ZX_OK , " " , zx_status_get_string ( status ) ) ; uint64_t last_env_start = 0 ; uint64_t i ; for ( i = 0 ; i < bootargs_size ; i ++ ) { if ( env [ i ] == 0 ) { envp . push_back ( & env [ last_env_start ] ) ; last_env_start = i + 1 ; } } envp . push_back ( nullptr ) ; status = launchpad_set_environ ( lp , envp . data ( ) ) ; if ( status != ZX_OK ) { launchpad_abort ( lp , status , " " ) ; } zx :: debuglog log_dup ; status = log . duplicate ( ZX_RIGHT_SAME_RIGHTS , & log_dup ) ; if ( status != ZX_OK ) { launchpad_abort ( lp , status , " " ) ; } else { launchpad_add_handle ( lp , log_dup . release ( ) , PA_HND ( PA_FD , FDIO_FLAG_USE_FOR_STDIO ) ) ; } const char * errmsg ; zx :: process proc_handle ; status = launchpad_go ( lp , proc_handle . reset_and_get_address ( ) , & errmsg ) ; if ( status != ZX_OK ) { printf ( " \n " , next_program , errmsg , zx_status_get_string ( status ) ) ; return ; } printf ( " \n " , next_program ) ; zx_signals_t observed ; zx_status_t termination_result = proc_handle . wait_one ( ZX_TASK_TERMINATED , zx :: time :: basic_time :: infinite ( ) , & observed ) ; if ( termination_result != ZX_OK ) { printf ( " \n " , termination_result ) ; } loop . Quit ( ) ; }
Launch the next process in the boot chain.
Launch the next process in the boot chain .
// Note that arguments are comma-delimited. // Split the bootsvc.next value into 1 or more arguments using ',' as a // delimiter. // Open the executable we will start next /*executable=*/ // Get the bootfs fuchsia.io.Node service channel that we will hand to the // next process in the boot chain. // Use the local loader service backed directly by the primary BOOTFS. // Duplicate the root resource to pass to the next process. // Set up the environment table for launchpad. // wait for termination and then reboot or power off the system // If the next process terminated, quit the main loop.