blob: 1deeaa9061ae1f1458390cf21e102d5800519fdd [file] [log] [blame]
Brad Fitzpatrickbc9748e2015-02-27 19:34:56 -08001// Copyright 2015 The Go 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// The working directory in Plan 9 is effectively per P, so different
6// goroutines and even the same goroutine as it's rescheduled on
7// different Ps can see different working directories.
8//
9// Instead, track a Go process-wide intent of the current working directory,
10// and switch to it at important points.
11
12package syscall
13
14import "sync"
15
16var (
17 wdmu sync.Mutex // guards following
18 wdSet bool
19 wdStr string
20)
21
22func Fixwd() {
23 wdmu.Lock()
24 defer wdmu.Unlock()
25 fixwdLocked()
26}
27
28func fixwdLocked() {
29 if !wdSet {
30 return
31 }
David du Colombier7d3f81a2015-04-11 14:58:42 +020032 // always call chdir when getwd returns an error
33 wd, _ := getwd()
Brad Fitzpatrickbc9748e2015-02-27 19:34:56 -080034 if wd == wdStr {
35 return
36 }
37 if err := chdir(wdStr); err != nil {
38 return
39 }
40}
41
Richard Millera379b7d2018-02-28 14:29:27 +000042func fixwd(paths ...string) {
43 for _, path := range paths {
44 if path != "" && path[0] != '/' && path[0] != '#' {
45 Fixwd()
46 return
47 }
48 }
49}
50
Brad Fitzpatrickbc9748e2015-02-27 19:34:56 -080051// goroutine-specific getwd
52func getwd() (wd string, err error) {
53 fd, err := open(".", O_RDONLY)
54 if err != nil {
55 return "", err
56 }
57 defer Close(fd)
58 return Fd2path(fd)
59}
60
61func Getwd() (wd string, err error) {
62 wdmu.Lock()
63 defer wdmu.Unlock()
64
65 if wdSet {
66 return wdStr, nil
67 }
68 wd, err = getwd()
69 if err != nil {
70 return
71 }
72 wdSet = true
73 wdStr = wd
74 return wd, nil
75}
76
77func Chdir(path string) error {
Richard Millera379b7d2018-02-28 14:29:27 +000078 fixwd(path)
Brad Fitzpatrickbc9748e2015-02-27 19:34:56 -080079 wdmu.Lock()
80 defer wdmu.Unlock()
81
82 if err := chdir(path); err != nil {
83 return err
84 }
85
86 wd, err := getwd()
87 if err != nil {
88 return err
89 }
90 wdSet = true
91 wdStr = wd
92 return nil
93}