forked from canonical/snapd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
link.go
151 lines (124 loc) · 4.25 KB
/
link.go
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2014-2016 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package backend
import (
"fmt"
"os"
"path/filepath"
"github.com/snapcore/snapd/boot"
"github.com/snapcore/snapd/logger"
"github.com/snapcore/snapd/progress"
"github.com/snapcore/snapd/snap"
"github.com/snapcore/snapd/wrappers"
)
func updateCurrentSymlinks(info *snap.Info) error {
mountDir := info.MountDir()
currentActiveSymlink := filepath.Join(mountDir, "..", "current")
if err := os.Remove(currentActiveSymlink); err != nil && !os.IsNotExist(err) {
logger.Noticef("Cannot remove %q: %v", currentActiveSymlink, err)
}
dataDir := info.DataDir()
currentDataSymlink := filepath.Join(dataDir, "..", "current")
if err := os.Remove(currentDataSymlink); err != nil && !os.IsNotExist(err) {
logger.Noticef("Cannot remove %q: %v", currentDataSymlink, err)
}
if err := os.MkdirAll(info.DataDir(), 0755); err != nil {
return err
}
if err := os.Symlink(filepath.Base(dataDir), currentDataSymlink); err != nil {
return err
}
return os.Symlink(filepath.Base(mountDir), currentActiveSymlink)
}
// LinkSnap makes the snap available by generating wrappers and setting the current symlinks.
func (b Backend) LinkSnap(info *snap.Info) error {
if err := generateWrappers(info); err != nil {
return err
}
// XXX/TODO: this needs to be a task with proper undo and tests!
if err := boot.SetNextBoot(info); err != nil {
return err
}
return updateCurrentSymlinks(info)
}
func generateWrappers(s *snap.Info) error {
// add the CLI apps from the snap.yaml
if err := wrappers.AddSnapBinaries(s); err != nil {
return err
}
// add the daemons from the snap.yaml
if err := wrappers.AddSnapServices(s, &progress.NullProgress{}); err != nil {
return err
}
// add the desktop files
if err := wrappers.AddSnapDesktopFiles(s); err != nil {
return err
}
return nil
}
func removeGeneratedWrappers(s *snap.Info, meter progress.Meter) error {
err1 := wrappers.RemoveSnapBinaries(s)
if err1 != nil {
logger.Noticef("Cannot remove binaries for %q: %v", s.Name(), err1)
}
err2 := wrappers.RemoveSnapServices(s, meter)
if err2 != nil {
logger.Noticef("Cannot remove services for %q: %v", s.Name(), err2)
}
err3 := wrappers.RemoveSnapDesktopFiles(s)
if err3 != nil {
logger.Noticef("Cannot remove desktop files for %q: %v", s.Name(), err3)
}
return firstErr(err1, err2, err3)
}
// UnlinkSnap makes the snap unavailable to the system removing wrappers and symlinks.
func (b Backend) UnlinkSnap(info *snap.Info, meter progress.Meter) error {
// remove generated services, binaries etc
err1 := removeGeneratedWrappers(info, meter)
// and finally remove current symlinks
err2 := removeCurrentSymlinks(info)
// FIXME: aggregate errors instead
return firstErr(err1, err2)
}
func removeCurrentSymlinks(info snap.PlaceInfo) error {
var err1, err2 error
// the snap "current" symlink
currentActiveSymlink := filepath.Join(info.MountDir(), "..", "current")
err1 = os.Remove(currentActiveSymlink)
if err1 != nil && !os.IsNotExist(err1) {
logger.Noticef("Cannot remove %q: %v", currentActiveSymlink, err1)
} else {
err1 = nil
}
// the data "current" symlink
currentDataSymlink := filepath.Join(info.DataDir(), "..", "current")
err2 = os.Remove(currentDataSymlink)
if err2 != nil && !os.IsNotExist(err2) {
logger.Noticef("Cannot remove %q: %v", currentDataSymlink, err2)
} else {
err2 = nil
}
if err1 != nil && err2 != nil {
return fmt.Errorf("cannot remove snap current symlink: %v and %v", err1, err2)
} else if err1 != nil {
return fmt.Errorf("cannot remove snap current symlink: %v", err1)
} else if err2 != nil {
return fmt.Errorf("cannot remove snap current symlink: %v", err2)
}
return nil
}