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 }