github.com/rck/u-root@v0.0.0-20180106144920-7eb602e381bb/cmds/init/bgbuild.go (about)

     1  // Copyright 2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Build commands in background processes. This feature certainly makes a
     6  // non-busybox shell feel more realtime.
     7  package main
     8  
     9  import (
    10  	"io/ioutil"
    11  	"log"
    12  	"os"
    13  	"os/exec"
    14  	"runtime"
    15  	"sort"
    16  	"strings"
    17  )
    18  
    19  // Commands are built approximately in order from smallest to largest length of
    20  // the command name. So, two letter commands like `ls` and `cd` will be built
    21  // before `mknod` and `mount`. Generally, shorter commands are used more often
    22  // (that is why they were made short) and are more likely to be used first,
    23  // thus they should be built first.
    24  type cmdSlice []os.FileInfo
    25  
    26  func (p cmdSlice) Len() int {
    27  	return len(p)
    28  }
    29  
    30  func (p cmdSlice) Less(i, j int) bool {
    31  	return len(p[i].Name()) < len(p[j].Name())
    32  }
    33  
    34  func (p cmdSlice) Swap(i, j int) {
    35  	p[i], p[j] = p[j], p[i]
    36  }
    37  
    38  func worker(cmds chan string) {
    39  	for cmdName := range cmds {
    40  		args := []string{"--onlybuild", "--noforce", "--lowpri", cmdName}
    41  		cmd := exec.Command("installcommand", args...)
    42  		if err := cmd.Start(); err != nil {
    43  			log.Println("Cannot start:", err)
    44  			continue
    45  		}
    46  		if err := cmd.Wait(); err != nil {
    47  			log.Println("installcommand error:", err)
    48  		}
    49  	}
    50  }
    51  
    52  func startBgBuild() {
    53  	cmds := make(chan string)
    54  
    55  	// Start a worker for each CPU.
    56  	for i := 0; i < runtime.NumCPU(); i++ {
    57  		go worker(cmds)
    58  	}
    59  
    60  	// Create a slice of commands and order them by the aformentioned
    61  	// heuristic.
    62  	fis, err := ioutil.ReadDir("/buildbin")
    63  	if err != nil {
    64  		log.Print(err)
    65  		return
    66  	}
    67  	sort.Sort(cmdSlice(fis))
    68  
    69  	// Send the command by name to the workers.
    70  	for _, fi := range fis {
    71  		cmds <- fi.Name()
    72  	}
    73  	close(cmds)
    74  }
    75  
    76  func cmdlineContainsFlag(flag string) bool {
    77  	cmdline, err := ioutil.ReadFile("/proc/cmdline")
    78  	if err != nil {
    79  		// Procfs not mounted?
    80  		return false
    81  	}
    82  	args := strings.Split(string(cmdline), " ")
    83  	for _, a := range args {
    84  		if a == flag {
    85  			return true
    86  		}
    87  	}
    88  	return false
    89  }
    90  
    91  func isBgBuildEnabled() bool {
    92  	return cmdlineContainsFlag("uroot.bgbuild")
    93  }