-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathsystem_linux.go
More file actions
132 lines (117 loc) · 3.81 KB
/
Copy pathsystem_linux.go
File metadata and controls
132 lines (117 loc) · 3.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//go:build linux
// +build linux
/*
Copyright 2016 Google Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package system
import (
"fmt"
"os"
"path/filepath"
"strconv"
"syscall"
"github.com/google/googet/v2/client"
"github.com/google/googet/v2/goolib"
"github.com/google/googet/v2/oswrap"
"github.com/google/logger"
)
// Install performs a system specfic install given a package extraction directory and a PkgSpec struct.
func Install(dir string, ps *goolib.PkgSpec) error {
in := ps.Install
if in.Path == "" {
return nil
}
logger.Infof("Running install command: %q", in.Path)
out, err := oswrap.Create(filepath.Join(dir, "googet_install.log"))
if err != nil {
return err
}
defer func() {
if err := out.Close(); err != nil {
logger.Error(err)
}
}()
if err := goolib.Exec(filepath.Join(dir, in.Path), in.Args, in.ExitCodes, out); err != nil {
return fmt.Errorf("error running install: %v", err)
}
return nil
}
// Uninstall performs a system specfic uninstall given a package extraction directory and a PkgSpec struct.
func Uninstall(dir string, ps *client.PackageState) error {
un := ps.PackageSpec.Uninstall
if un.Path == "" {
return nil
}
logger.Infof("Running uninstall command: %q", un.Path)
// logging is only useful for failed uninstalls
out, err := oswrap.Create(filepath.Join(dir, "googet_remove.log"))
if err != nil {
return err
}
defer func() {
if err := out.Close(); err != nil {
logger.Error(err)
}
}()
return goolib.Exec(filepath.Join(dir, un.Path), un.Args, un.ExitCodes, out)
}
// InstallableArchs returns a slice of archs supported by this machine.
func InstallableArchs() ([]string, error) {
// Just return all archs as Linux builds are currently just used for testing.
return []string{"noarch", "x86_64", "x86_32", "arm", "arm64"}, nil
}
// AppAssociation returns empty strings and is a stub of the Windows implementation.
func AppAssociation(ps *goolib.PkgSpec, installSource string) (string, string) {
return "", ""
}
// IsAdmin returns nil and is a stub of the Windows implementation
func IsAdmin() error {
return nil
}
// isGooGetRunning checks if the process with the given PID is running and is a googet process.
func isGooGetRunning(pid int) (bool, error) {
// On Linux, we can check /proc/<pid>/exe
exe, err := os.Readlink(fmt.Sprintf("/proc/%d/exe", pid))
if err != nil {
if os.IsNotExist(err) {
return false, nil // Process does not exist
}
return false, err
}
// Check if the executable path contains "googet"
return filepath.Base(exe) == "googet", nil
}
// lock attempts to obtain an exclusive lock on the provided file.
func lock(f *os.File) (func(), error) {
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_EX); err != nil {
return nil, err
}
cleanup := func() {
syscall.Flock(int(f.Fd()), syscall.LOCK_UN)
f.Close()
os.Remove(f.Name())
}
if err := f.Truncate(0); err != nil {
cleanup()
return nil, fmt.Errorf("failed to truncate lockfile: %v", err)
}
if _, err := f.WriteString(strconv.Itoa(os.Getpid())); err != nil {
cleanup()
return nil, fmt.Errorf("failed to write PID to lockfile: %v", err)
}
// Downgrade to shared lock so that other processes can read the PID.
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_SH); err != nil {
cleanup()
return nil, fmt.Errorf("failed to downgrade to shared lock: %v", err)
}
return cleanup, nil
}