blob: 52658ef124e9c8cc7744a9a49567258ad18f12c8 [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"
22 "strings"
23
24 "github.com/google/blueprint/microfactory"
25
26 "android/soong/ui/build/paths"
27)
28
29func parsePathDir(dir string) []string {
30 f, err := os.Open(dir)
31 if err != nil {
32 return nil
33 }
34 defer f.Close()
35
36 if s, err := f.Stat(); err != nil || !s.IsDir() {
37 return nil
38 }
39
40 infos, err := f.Readdir(-1)
41 if err != nil {
42 return nil
43 }
44
45 ret := make([]string, 0, len(infos))
46 for _, info := range infos {
47 if m := info.Mode(); !m.IsDir() && m&0111 != 0 {
48 ret = append(ret, info.Name())
49 }
50 }
51 return ret
52}
53
54func SetupPath(ctx Context, config Config) {
55 if config.pathReplaced {
56 return
57 }
58
59 ctx.BeginTrace("path")
60 defer ctx.EndTrace()
61
62 origPath, _ := config.Environment().Get("PATH")
63 myPath := filepath.Join(config.OutDir(), ".path")
64 interposer := myPath + "_interposer"
65
66 var cfg microfactory.Config
67 cfg.Map("android/soong", "build/soong")
68 cfg.TrimPath, _ = filepath.Abs(".")
69 if _, err := microfactory.Build(&cfg, interposer, "android/soong/cmd/path_interposer"); err != nil {
70 ctx.Fatalln("Failed to build path interposer:", err)
71 }
72
73 if err := ioutil.WriteFile(interposer+"_origpath", []byte(origPath), 0777); err != nil {
74 ctx.Fatalln("Failed to write original path:", err)
75 }
76
77 entries, err := paths.LogListener(ctx.Context, interposer+"_log")
78 if err != nil {
79 ctx.Fatalln("Failed to listen for path logs:", err)
80 }
81
82 go func() {
83 for log := range entries {
84 curPid := os.Getpid()
85 for i, proc := range log.Parents {
86 if proc.Pid == curPid {
87 log.Parents = log.Parents[i:]
88 break
89 }
90 }
91 procPrints := []string{
92 "See https://android.googlesource.com/platform/build/+/master/Changes.md#PATH_Tools for more information.",
93 }
94 if len(log.Parents) > 0 {
95 procPrints = append(procPrints, "Process tree:")
96 for i, proc := range log.Parents {
97 procPrints = append(procPrints, fmt.Sprintf("%s→ %s", strings.Repeat(" ", i), proc.Command))
98 }
99 }
100
101 config := paths.GetConfig(log.Basename)
102 if config.Error {
103 ctx.Printf("Disallowed PATH tool %q used: %#v", log.Basename, log.Args)
104 for _, line := range procPrints {
105 ctx.Println(line)
106 }
107 } else {
108 ctx.Verbosef("Unknown PATH tool %q used: %#v", log.Basename, log.Args)
109 for _, line := range procPrints {
110 ctx.Verboseln(line)
111 }
112 }
113 }
114 }()
115
116 ensureEmptyDirectoriesExist(ctx, myPath)
117
118 var execs []string
119 for _, pathEntry := range filepath.SplitList(origPath) {
120 if pathEntry == "" {
121 // Ignore the current directory
122 continue
123 }
124 // TODO(dwillemsen): remove path entries under TOP? or anything
125 // that looks like an android source dir? They won't exist on
126 // the build servers, since they're added by envsetup.sh.
127 // (Except for the JDK, which is configured in ui/build/config.go)
128
129 execs = append(execs, parsePathDir(pathEntry)...)
130 }
131
132 allowAllSymlinks := config.Environment().IsEnvTrue("TEMPORARY_DISABLE_PATH_RESTRICTIONS")
133 for _, name := range execs {
134 if !paths.GetConfig(name).Symlink && !allowAllSymlinks {
135 continue
136 }
137
138 err := os.Symlink("../.path_interposer", filepath.Join(myPath, name))
139 // Intentionally ignore existing files -- that means that we
140 // just created it, and the first one should win.
141 if err != nil && !os.IsExist(err) {
142 ctx.Fatalln("Failed to create symlink:", err)
143 }
144 }
145
146 myPath, _ = filepath.Abs(myPath)
147 config.Environment().Set("PATH", myPath)
148 config.pathReplaced = true
149}