blob: 8260ff95ffff19f92d44b45a90e528ce21f24529 [file] [log] [blame]
Dan Willemsen18490112018-05-25 16:30:04 -07001// Copyright 2018 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package build
16
17import (
18 "fmt"
19 "io/ioutil"
20 "os"
21 "path/filepath"
Dan Willemsen417be1f2018-10-30 23:18:54 -070022 "runtime"
Dan Willemsen18490112018-05-25 16:30:04 -070023 "strings"
24
25 "github.com/google/blueprint/microfactory"
26
27 "android/soong/ui/build/paths"
28)
29
30func parsePathDir(dir string) []string {
31 f, err := os.Open(dir)
32 if err != nil {
33 return nil
34 }
35 defer f.Close()
36
37 if s, err := f.Stat(); err != nil || !s.IsDir() {
38 return nil
39 }
40
41 infos, err := f.Readdir(-1)
42 if err != nil {
43 return nil
44 }
45
46 ret := make([]string, 0, len(infos))
47 for _, info := range infos {
48 if m := info.Mode(); !m.IsDir() && m&0111 != 0 {
49 ret = append(ret, info.Name())
50 }
51 }
52 return ret
53}
54
55func SetupPath(ctx Context, config Config) {
56 if config.pathReplaced {
57 return
58 }
59
60 ctx.BeginTrace("path")
61 defer ctx.EndTrace()
62
63 origPath, _ := config.Environment().Get("PATH")
64 myPath := filepath.Join(config.OutDir(), ".path")
65 interposer := myPath + "_interposer"
66
67 var cfg microfactory.Config
68 cfg.Map("android/soong", "build/soong")
69 cfg.TrimPath, _ = filepath.Abs(".")
70 if _, err := microfactory.Build(&cfg, interposer, "android/soong/cmd/path_interposer"); err != nil {
71 ctx.Fatalln("Failed to build path interposer:", err)
72 }
73
74 if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
75 ctx.Fatalln("Failed to write original path:", err)
76 }
77
78 entries, err := paths.LogListener(ctx.Context, interposer+"_log")
79 if err != nil {
80 ctx.Fatalln("Failed to listen for path logs:", err)
81 }
82
83 go func() {
84 for log := range entries {
85 curPid := os.Getpid()
86 for i, proc := range log.Parents {
87 if proc.Pid == curPid {
88 log.Parents = log.Parents[i:]
89 break
90 }
91 }
92 procPrints := []string{
93 "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
94 }
95 if len(log.Parents) > 0 {
96 procPrints = append(procPrints, "Process tree:")
97 for i, proc := range log.Parents {
98 procPrints = append(procPrints, fmt.Sprintf("%s→ %s", strings.Repeat(" ", i), proc.Command))
99 }
100 }
101
102 config := paths.GetConfig(log.Basename)
103 if config.Error {
104 ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
105 for _, line := range procPrints {
106 ctx.Println(line)
107 }
108 } else {
109 ctx.Verbosef("Unknown PATH tool %q used: %#v", log.Basename, log.Args)
110 for _, line := range procPrints {
111 ctx.Verboseln(line)
112 }
113 }
114 }
115 }()
116
117 ensureEmptyDirectoriesExist(ctx, myPath)
118
119 var execs []string
120 for _, pathEntry := range filepath.SplitList(origPath) {
121 if pathEntry == "" {
122 // Ignore the current directory
123 continue
124 }
125 // TODO(dwillemsen): remove path entries under TOP? or anything
126 // that looks like an android source dir? They won't exist on
127 // the build servers, since they're added by envsetup.sh.
128 // (Except for the JDK, which is configured in ui/build/config.go)
129
130 execs = append(execs, parsePathDir(pathEntry)...)
131 }
132
133 allowAllSymlinks := config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS")
134 for _, name := range execs {
135 if !paths.GetConfig(name).Symlink && !allowAllSymlinks {
136 continue
137 }
138
139 err := os.Symlink("../.path_interposer", filepath.Join(myPath, name))
140 // Intentionally ignore existing files -- that means that we
141 // just created it, and the first one should win.
142 if err != nil && !os.IsExist(err) {
143 ctx.Fatalln("Failed to create symlink:", err)
144 }
145 }
146
147 myPath, _ = filepath.Abs(myPath)
Dan Willemsen417be1f2018-10-30 23:18:54 -0700148
149 // Use the toybox prebuilts on linux
150 if runtime.GOOS == "linux" {
151 toyboxPath, _ := filepath.Abs("prebuilts/build-tools/toybox/linux-x86")
152 myPath = toyboxPath + string(os.PathListSeparator) + myPath
153 }
154
Dan Willemsen18490112018-05-25 16:30:04 -0700155 config.Environment().Set("PATH", myPath)
156 config.pathReplaced = true
157}