github.com/stulluk/snapd@v0.0.0-20210611110309-f6d5d5bd24b0/overlord/snapstate/handlers.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2018 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package snapstate
    21  
    22  import (
    23  	"context"
    24  	"encoding/json"
    25  	"fmt"
    26  	"os"
    27  	"path/filepath"
    28  	"sort"
    29  	"strconv"
    30  	"strings"
    31  	"time"
    32  
    33  	"gopkg.in/tomb.v2"
    34  
    35  	"github.com/snapcore/snapd/boot"
    36  	"github.com/snapcore/snapd/cmd/snaplock/runinhibit"
    37  	"github.com/snapcore/snapd/dirs"
    38  	"github.com/snapcore/snapd/features"
    39  	"github.com/snapcore/snapd/i18n"
    40  	"github.com/snapcore/snapd/logger"
    41  	"github.com/snapcore/snapd/osutil"
    42  	"github.com/snapcore/snapd/overlord/auth"
    43  	"github.com/snapcore/snapd/overlord/configstate/config"
    44  	"github.com/snapcore/snapd/overlord/configstate/settings"
    45  	"github.com/snapcore/snapd/overlord/snapstate/backend"
    46  	"github.com/snapcore/snapd/overlord/state"
    47  	"github.com/snapcore/snapd/progress"
    48  	"github.com/snapcore/snapd/release"
    49  	"github.com/snapcore/snapd/snap"
    50  	"github.com/snapcore/snapd/snap/quota"
    51  	"github.com/snapcore/snapd/store"
    52  	"github.com/snapcore/snapd/strutil"
    53  	"github.com/snapcore/snapd/timings"
    54  	"github.com/snapcore/snapd/wrappers"
    55  )
    56  
    57  // SnapServiceOptions is a hook set by servicestate.
    58  var SnapServiceOptions = func(st *state.State, instanceName string, grps map[string]*quota.Group) (opts *wrappers.SnapServiceOptions, err error) {
    59  	panic("internal error: snapstate.SnapServiceOptions is unset")
    60  }
    61  
    62  var EnsureSnapAbsentFromQuotaGroup = func(st *state.State, snap string) error {
    63  	panic("internal error: snapstate.EnsureSnapAbsentFromQuotaGroup is unset")
    64  }
    65  
    66  var SecurityProfilesRemoveLate = func(snapName string, rev snap.Revision, typ snap.Type) error {
    67  	panic("internal error: snapstate.SecurityProfilesRemoveLate is unset")
    68  }
    69  
    70  // TaskSnapSetup returns the SnapSetup with task params hold by or referred to by the task.
    71  func TaskSnapSetup(t *state.Task) (*SnapSetup, error) {
    72  	var snapsup SnapSetup
    73  
    74  	err := t.Get("snap-setup", &snapsup)
    75  	if err != nil && err != state.ErrNoState {
    76  		return nil, err
    77  	}
    78  	if err == nil {
    79  		return &snapsup, nil
    80  	}
    81  
    82  	var id string
    83  	err = t.Get("snap-setup-task", &id)
    84  	if err != nil {
    85  		return nil, err
    86  	}
    87  
    88  	ts := t.State().Task(id)
    89  	if ts == nil {
    90  		return nil, fmt.Errorf("internal error: tasks are being pruned")
    91  	}
    92  	if err := ts.Get("snap-setup", &snapsup); err != nil {
    93  		return nil, err
    94  	}
    95  	return &snapsup, nil
    96  }
    97  
    98  // SetTaskSnapSetup writes the given SnapSetup to the provided task's
    99  // snap-setup-task Task, or to the task itself if the task does not have a
   100  // snap-setup-task (i.e. it _is_ the snap-setup-task)
   101  func SetTaskSnapSetup(t *state.Task, snapsup *SnapSetup) error {
   102  	if t.Has("snap-setup") {
   103  		// this is the snap-setup-task so just write to the task directly
   104  		t.Set("snap-setup", snapsup)
   105  	} else {
   106  		// this task isn't the snap-setup-task, so go get that and write to that
   107  		// one
   108  		var id string
   109  		err := t.Get("snap-setup-task", &id)
   110  		if err != nil {
   111  			return err
   112  		}
   113  
   114  		ts := t.State().Task(id)
   115  		if ts == nil {
   116  			return fmt.Errorf("internal error: tasks are being pruned")
   117  		}
   118  		ts.Set("snap-setup", snapsup)
   119  	}
   120  
   121  	return nil
   122  }
   123  
   124  func snapSetupAndState(t *state.Task) (*SnapSetup, *SnapState, error) {
   125  	snapsup, err := TaskSnapSetup(t)
   126  	if err != nil {
   127  		return nil, nil, err
   128  	}
   129  	var snapst SnapState
   130  	err = Get(t.State(), snapsup.InstanceName(), &snapst)
   131  	if err != nil && err != state.ErrNoState {
   132  		return nil, nil, err
   133  	}
   134  	return snapsup, &snapst, nil
   135  }
   136  
   137  /* State Locking
   138  
   139     do* / undo* handlers should usually lock the state just once with:
   140  
   141  	st.Lock()
   142  	defer st.Unlock()
   143  
   144     For tasks doing slow operations (long i/o, networking operations) it's OK
   145     to unlock the state temporarily:
   146  
   147          st.Unlock()
   148          err := slowIOOp()
   149          st.Lock()
   150          if err != nil {
   151             ...
   152          }
   153  
   154      but if a task Get and then Set the SnapState of a snap it must avoid
   155      releasing the state lock in between, other tasks might have
   156      reasons to update the SnapState independently:
   157  
   158          // DO NOT DO THIS!:
   159          snapst := ...
   160          snapst.Attr = ...
   161          st.Unlock()
   162          ...
   163          st.Lock()
   164          Set(st, snapName, snapst)
   165  
   166      if a task really needs to mix mutating a SnapState and releasing the state
   167      lock it should be serialized at the task runner level, see
   168      SnapManger.blockedTask and TaskRunner.SetBlocked
   169  
   170  */
   171  
   172  const defaultCoreSnapName = "core"
   173  
   174  func defaultBaseSnapsChannel() string {
   175  	channel := os.Getenv("SNAPD_BASES_CHANNEL")
   176  	if channel == "" {
   177  		return "stable"
   178  	}
   179  	return channel
   180  }
   181  
   182  func defaultSnapdSnapsChannel() string {
   183  	channel := os.Getenv("SNAPD_SNAPD_CHANNEL")
   184  	if channel == "" {
   185  		return "stable"
   186  	}
   187  	return channel
   188  }
   189  
   190  func defaultPrereqSnapsChannel() string {
   191  	channel := os.Getenv("SNAPD_PREREQS_CHANNEL")
   192  	if channel == "" {
   193  		return "stable"
   194  	}
   195  	return channel
   196  }
   197  
   198  func linkSnapInFlight(st *state.State, snapName string) (bool, error) {
   199  	for _, chg := range st.Changes() {
   200  		if chg.Status().Ready() {
   201  			continue
   202  		}
   203  		for _, tc := range chg.Tasks() {
   204  			if tc.Status().Ready() {
   205  				continue
   206  			}
   207  			if tc.Kind() == "link-snap" {
   208  				snapsup, err := TaskSnapSetup(tc)
   209  				if err != nil {
   210  					return false, err
   211  				}
   212  				if snapsup.InstanceName() == snapName {
   213  					return true, nil
   214  				}
   215  			}
   216  		}
   217  	}
   218  
   219  	return false, nil
   220  }
   221  
   222  func isInstalled(st *state.State, snapName string) (bool, error) {
   223  	var snapState SnapState
   224  	err := Get(st, snapName, &snapState)
   225  	if err != nil && err != state.ErrNoState {
   226  		return false, err
   227  	}
   228  	return snapState.IsInstalled(), nil
   229  }
   230  
   231  // timeout for tasks to check if the prerequisites are ready
   232  var prerequisitesRetryTimeout = 30 * time.Second
   233  
   234  func (m *SnapManager) doPrerequisites(t *state.Task, _ *tomb.Tomb) error {
   235  	st := t.State()
   236  	st.Lock()
   237  	defer st.Unlock()
   238  
   239  	perfTimings := state.TimingsForTask(t)
   240  	defer perfTimings.Save(st)
   241  
   242  	// check if we need to inject tasks to install core
   243  	snapsup, _, err := snapSetupAndState(t)
   244  	if err != nil {
   245  		return err
   246  	}
   247  
   248  	// os/base/kernel/gadget cannot have prerequisites other
   249  	// than the models default base (or core) which is installed anyway
   250  	switch snapsup.Type {
   251  	case snap.TypeOS, snap.TypeBase, snap.TypeKernel, snap.TypeGadget:
   252  		return nil
   253  	}
   254  	// snapd is special and has no prereqs
   255  	if snapsup.Type == snap.TypeSnapd {
   256  		return nil
   257  	}
   258  
   259  	// we need to make sure we install all prereqs together in one
   260  	// operation
   261  	base := defaultCoreSnapName
   262  	if snapsup.Base != "" {
   263  		base = snapsup.Base
   264  	}
   265  
   266  	if err := m.installPrereqs(t, base, snapsup.Prereq, snapsup.UserID, perfTimings); err != nil {
   267  		return err
   268  	}
   269  
   270  	return nil
   271  }
   272  
   273  func (m *SnapManager) installOneBaseOrRequired(st *state.State, snapName string, requireTypeBase bool, channel string, onInFlight error, userID int) (*state.TaskSet, error) {
   274  	// The core snap provides everything we need for core16.
   275  	coreInstalled, err := isInstalled(st, "core")
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	if snapName == "core16" && coreInstalled {
   280  		return nil, nil
   281  	}
   282  
   283  	// installed already?
   284  	isInstalled, err := isInstalled(st, snapName)
   285  	if err != nil {
   286  		return nil, err
   287  	}
   288  	if isInstalled {
   289  		return nil, nil
   290  	}
   291  	// in progress?
   292  	inFlight, err := linkSnapInFlight(st, snapName)
   293  	if err != nil {
   294  		return nil, err
   295  	}
   296  	if inFlight {
   297  		return nil, onInFlight
   298  	}
   299  
   300  	// not installed, nor queued for install -> install it
   301  	ts, err := Install(context.TODO(), st, snapName, &RevisionOptions{Channel: channel}, userID, Flags{RequireTypeBase: requireTypeBase})
   302  
   303  	// something might have triggered an explicit install while
   304  	// the state was unlocked -> deal with that here by simply
   305  	// retrying the operation.
   306  	if _, ok := err.(*ChangeConflictError); ok {
   307  		return nil, &state.Retry{After: prerequisitesRetryTimeout}
   308  	}
   309  	return ts, err
   310  }
   311  
   312  func (m *SnapManager) installPrereqs(t *state.Task, base string, prereq []string, userID int, tm timings.Measurer) error {
   313  	st := t.State()
   314  
   315  	// We try to install all wanted snaps. If one snap cannot be installed
   316  	// because of change conflicts or similar we retry. Only if all snaps
   317  	// can be installed together we add the tasks to the change.
   318  	var tss []*state.TaskSet
   319  	for _, prereqName := range prereq {
   320  		var onInFlightErr error = nil
   321  		var err error
   322  		var ts *state.TaskSet
   323  		timings.Run(tm, "install-prereq", fmt.Sprintf("install %q", prereqName), func(timings.Measurer) {
   324  			noTypeBaseCheck := false
   325  			ts, err = m.installOneBaseOrRequired(st, prereqName, noTypeBaseCheck, defaultPrereqSnapsChannel(), onInFlightErr, userID)
   326  		})
   327  		if err != nil {
   328  			return prereqError("prerequisite", prereqName, err)
   329  		}
   330  		if ts == nil {
   331  			continue
   332  		}
   333  		tss = append(tss, ts)
   334  	}
   335  
   336  	// for base snaps we need to wait until the change is done
   337  	// (either finished or failed)
   338  	onInFlightErr := &state.Retry{After: prerequisitesRetryTimeout}
   339  
   340  	var tsBase *state.TaskSet
   341  	var err error
   342  	if base != "none" {
   343  		timings.Run(tm, "install-prereq", fmt.Sprintf("install base %q", base), func(timings.Measurer) {
   344  			requireTypeBase := true
   345  			tsBase, err = m.installOneBaseOrRequired(st, base, requireTypeBase, defaultBaseSnapsChannel(), onInFlightErr, userID)
   346  		})
   347  		if err != nil {
   348  			return prereqError("snap base", base, err)
   349  		}
   350  	}
   351  
   352  	// on systems without core or snapd need to install snapd to
   353  	// make interfaces work - LP: 1819318
   354  	var tsSnapd *state.TaskSet
   355  	snapdSnapInstalled, err := isInstalled(st, "snapd")
   356  	if err != nil {
   357  		return err
   358  	}
   359  	coreSnapInstalled, err := isInstalled(st, "core")
   360  	if err != nil {
   361  		return err
   362  	}
   363  	if base != "core" && !snapdSnapInstalled && !coreSnapInstalled {
   364  		timings.Run(tm, "install-prereq", "install snapd", func(timings.Measurer) {
   365  			noTypeBaseCheck := false
   366  			tsSnapd, err = m.installOneBaseOrRequired(st, "snapd", noTypeBaseCheck, defaultSnapdSnapsChannel(), onInFlightErr, userID)
   367  		})
   368  		if err != nil {
   369  			return prereqError("system snap", "snapd", err)
   370  		}
   371  	}
   372  
   373  	chg := t.Change()
   374  	// add all required snaps, no ordering, this will be done in the
   375  	// auto-connect task handler
   376  	for _, ts := range tss {
   377  		ts.JoinLane(st.NewLane())
   378  		chg.AddAll(ts)
   379  	}
   380  	// add the base if needed, prereqs else must wait on this
   381  	if tsBase != nil {
   382  		tsBase.JoinLane(st.NewLane())
   383  		for _, t := range chg.Tasks() {
   384  			t.WaitAll(tsBase)
   385  		}
   386  		chg.AddAll(tsBase)
   387  	}
   388  	// add snapd if needed, everything must wait on this
   389  	if tsSnapd != nil {
   390  		tsSnapd.JoinLane(st.NewLane())
   391  		for _, t := range chg.Tasks() {
   392  			t.WaitAll(tsSnapd)
   393  		}
   394  		chg.AddAll(tsSnapd)
   395  	}
   396  
   397  	// make sure that the new change is committed to the state
   398  	// together with marking this task done
   399  	t.SetStatus(state.DoneStatus)
   400  
   401  	return nil
   402  }
   403  
   404  func prereqError(what, snapName string, err error) error {
   405  	if _, ok := err.(*state.Retry); ok {
   406  		return err
   407  	}
   408  	return fmt.Errorf("cannot install %s %q: %v", what, snapName, err)
   409  }
   410  
   411  func (m *SnapManager) doPrepareSnap(t *state.Task, _ *tomb.Tomb) error {
   412  	st := t.State()
   413  	st.Lock()
   414  	defer st.Unlock()
   415  	snapsup, snapst, err := snapSetupAndState(t)
   416  	if err != nil {
   417  		return err
   418  	}
   419  
   420  	if snapsup.Revision().Unset() {
   421  		// Local revisions start at -1 and go down.
   422  		revision := snapst.LocalRevision()
   423  		if revision.Unset() || revision.N > 0 {
   424  			revision = snap.R(-1)
   425  		} else {
   426  			revision.N--
   427  		}
   428  		if !revision.Local() {
   429  			panic("internal error: invalid local revision built: " + revision.String())
   430  		}
   431  		snapsup.SideInfo.Revision = revision
   432  	}
   433  
   434  	t.Set("snap-setup", snapsup)
   435  	return nil
   436  }
   437  
   438  func (m *SnapManager) undoPrepareSnap(t *state.Task, _ *tomb.Tomb) error {
   439  	st := t.State()
   440  	st.Lock()
   441  	defer st.Unlock()
   442  
   443  	snapsup, err := TaskSnapSetup(t)
   444  	if err != nil {
   445  		return err
   446  	}
   447  
   448  	if snapsup.SideInfo == nil || snapsup.SideInfo.RealName == "" {
   449  		return nil
   450  	}
   451  
   452  	var logMsg []string
   453  	var snapSetup string
   454  	dupSig := []string{"snap-install:"}
   455  	chg := t.Change()
   456  	logMsg = append(logMsg, fmt.Sprintf("change %q: %q", chg.Kind(), chg.Summary()))
   457  	for _, t := range chg.Tasks() {
   458  		// TODO: report only tasks in intersecting lanes?
   459  		tintro := fmt.Sprintf("%s: %s", t.Kind(), t.Status())
   460  		logMsg = append(logMsg, tintro)
   461  		dupSig = append(dupSig, tintro)
   462  		if snapsup, err := TaskSnapSetup(t); err == nil && snapsup.SideInfo != nil {
   463  			snapSetup1 := fmt.Sprintf(" snap-setup: %q (%v) %q", snapsup.SideInfo.RealName, snapsup.SideInfo.Revision, snapsup.SideInfo.Channel)
   464  			if snapSetup1 != snapSetup {
   465  				snapSetup = snapSetup1
   466  				logMsg = append(logMsg, snapSetup)
   467  				dupSig = append(dupSig, fmt.Sprintf(" snap-setup: %q", snapsup.SideInfo.RealName))
   468  			}
   469  		}
   470  		for _, l := range t.Log() {
   471  			// cut of the rfc339 timestamp to ensure duplicate
   472  			// detection works in daisy
   473  			tStampLen := strings.Index(l, " ")
   474  			if tStampLen < 0 {
   475  				continue
   476  			}
   477  			// not tStampLen+1 because the indent is nice
   478  			entry := l[tStampLen:]
   479  			logMsg = append(logMsg, entry)
   480  			dupSig = append(dupSig, entry)
   481  		}
   482  	}
   483  
   484  	var ubuntuCoreTransitionCount int
   485  	err = st.Get("ubuntu-core-transition-retry", &ubuntuCoreTransitionCount)
   486  	if err != nil && err != state.ErrNoState {
   487  		return err
   488  	}
   489  	extra := map[string]string{
   490  		"Channel":  snapsup.Channel,
   491  		"Revision": snapsup.SideInfo.Revision.String(),
   492  	}
   493  	if ubuntuCoreTransitionCount > 0 {
   494  		extra["UbuntuCoreTransitionCount"] = strconv.Itoa(ubuntuCoreTransitionCount)
   495  	}
   496  
   497  	// Only report and error if there is an actual error in the change,
   498  	// we could undo things because the user canceled the change.
   499  	var isErr bool
   500  	for _, tt := range t.Change().Tasks() {
   501  		if tt.Status() == state.ErrorStatus {
   502  			isErr = true
   503  			break
   504  		}
   505  	}
   506  	if isErr && !settings.ProblemReportsDisabled(st) {
   507  		st.Unlock()
   508  		oopsid, err := errtrackerReport(snapsup.SideInfo.RealName, strings.Join(logMsg, "\n"), strings.Join(dupSig, "\n"), extra)
   509  		st.Lock()
   510  		if err == nil {
   511  			logger.Noticef("Reported install problem for %q as %s", snapsup.SideInfo.RealName, oopsid)
   512  		} else {
   513  			logger.Debugf("Cannot report problem: %s", err)
   514  		}
   515  	}
   516  
   517  	return nil
   518  }
   519  
   520  func installInfoUnlocked(st *state.State, snapsup *SnapSetup, deviceCtx DeviceContext) (store.SnapActionResult, error) {
   521  	st.Lock()
   522  	defer st.Unlock()
   523  	opts := &RevisionOptions{Channel: snapsup.Channel, CohortKey: snapsup.CohortKey, Revision: snapsup.Revision()}
   524  	return installInfo(context.TODO(), st, snapsup.InstanceName(), opts, snapsup.UserID, deviceCtx)
   525  }
   526  
   527  // autoRefreshRateLimited returns the rate limit of auto-refreshes or 0 if
   528  // there is no limit.
   529  func autoRefreshRateLimited(st *state.State) (rate int64) {
   530  	tr := config.NewTransaction(st)
   531  
   532  	var rateLimit string
   533  	err := tr.Get("core", "refresh.rate-limit", &rateLimit)
   534  	if err != nil {
   535  		return 0
   536  	}
   537  	// NOTE ParseByteSize errors on negative rates
   538  	val, err := strutil.ParseByteSize(rateLimit)
   539  	if err != nil {
   540  		return 0
   541  	}
   542  	return val
   543  }
   544  
   545  func downloadSnapParams(st *state.State, t *state.Task) (*SnapSetup, StoreService, *auth.UserState, error) {
   546  	snapsup, err := TaskSnapSetup(t)
   547  	if err != nil {
   548  		return nil, nil, nil, err
   549  	}
   550  
   551  	deviceCtx, err := DeviceCtx(st, t, nil)
   552  	if err != nil {
   553  		return nil, nil, nil, err
   554  	}
   555  
   556  	sto := Store(st, deviceCtx)
   557  
   558  	user, err := userFromUserID(st, snapsup.UserID)
   559  	if err != nil {
   560  		return nil, nil, nil, err
   561  	}
   562  
   563  	return snapsup, sto, user, nil
   564  }
   565  
   566  func (m *SnapManager) doDownloadSnap(t *state.Task, tomb *tomb.Tomb) error {
   567  	st := t.State()
   568  	var rate int64
   569  
   570  	st.Lock()
   571  	perfTimings := state.TimingsForTask(t)
   572  	snapsup, theStore, user, err := downloadSnapParams(st, t)
   573  	if snapsup != nil && snapsup.IsAutoRefresh {
   574  		// NOTE rate is never negative
   575  		rate = autoRefreshRateLimited(st)
   576  	}
   577  	st.Unlock()
   578  	if err != nil {
   579  		return err
   580  	}
   581  
   582  	meter := NewTaskProgressAdapterUnlocked(t)
   583  	targetFn := snapsup.MountFile()
   584  
   585  	dlOpts := &store.DownloadOptions{
   586  		IsAutoRefresh: snapsup.IsAutoRefresh,
   587  		RateLimit:     rate,
   588  	}
   589  	if snapsup.DownloadInfo == nil {
   590  		var storeInfo store.SnapActionResult
   591  		// COMPATIBILITY - this task was created from an older version
   592  		// of snapd that did not store the DownloadInfo in the state
   593  		// yet. Therefore do not worry about DeviceContext.
   594  		storeInfo, err = installInfoUnlocked(st, snapsup, nil)
   595  		if err != nil {
   596  			return err
   597  		}
   598  		timings.Run(perfTimings, "download", fmt.Sprintf("download snap %q", snapsup.SnapName()), func(timings.Measurer) {
   599  			err = theStore.Download(tomb.Context(nil), snapsup.SnapName(), targetFn, &storeInfo.DownloadInfo, meter, user, dlOpts)
   600  		})
   601  		snapsup.SideInfo = &storeInfo.SideInfo
   602  	} else {
   603  		timings.Run(perfTimings, "download", fmt.Sprintf("download snap %q", snapsup.SnapName()), func(timings.Measurer) {
   604  			err = theStore.Download(tomb.Context(nil), snapsup.SnapName(), targetFn, snapsup.DownloadInfo, meter, user, dlOpts)
   605  		})
   606  	}
   607  	if err != nil {
   608  		return err
   609  	}
   610  
   611  	snapsup.SnapPath = targetFn
   612  
   613  	// update the snap setup for the follow up tasks
   614  	st.Lock()
   615  	t.Set("snap-setup", snapsup)
   616  	perfTimings.Save(st)
   617  	st.Unlock()
   618  
   619  	return nil
   620  }
   621  
   622  var (
   623  	mountPollInterval = 1 * time.Second
   624  )
   625  
   626  // hasOtherInstances checks whether there are other instances of the snap, be it
   627  // instance keyed or not
   628  func hasOtherInstances(st *state.State, instanceName string) (bool, error) {
   629  	snapName, _ := snap.SplitInstanceName(instanceName)
   630  	var all map[string]*json.RawMessage
   631  	if err := st.Get("snaps", &all); err != nil && err != state.ErrNoState {
   632  		return false, err
   633  	}
   634  	for otherName := range all {
   635  		if otherName == instanceName {
   636  			continue
   637  		}
   638  		if otherSnapName, _ := snap.SplitInstanceName(otherName); otherSnapName == snapName {
   639  			return true, nil
   640  		}
   641  	}
   642  	return false, nil
   643  }
   644  
   645  func (m *SnapManager) doMountSnap(t *state.Task, _ *tomb.Tomb) error {
   646  	st := t.State()
   647  	st.Lock()
   648  	perfTimings := state.TimingsForTask(t)
   649  	snapsup, snapst, err := snapSetupAndState(t)
   650  	st.Unlock()
   651  	if err != nil {
   652  		return err
   653  	}
   654  
   655  	curInfo, err := snapst.CurrentInfo()
   656  	if err != nil && err != ErrNoCurrent {
   657  		return err
   658  	}
   659  
   660  	m.backend.CurrentInfo(curInfo)
   661  
   662  	st.Lock()
   663  	deviceCtx, err := DeviceCtx(t.State(), t, nil)
   664  	st.Unlock()
   665  	if err != nil {
   666  		return err
   667  	}
   668  
   669  	timings.Run(perfTimings, "check-snap", fmt.Sprintf("check snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   670  		err = checkSnap(st, snapsup.SnapPath, snapsup.InstanceName(), snapsup.SideInfo, curInfo, snapsup.Flags, deviceCtx)
   671  	})
   672  	if err != nil {
   673  		return err
   674  	}
   675  
   676  	cleanup := func() {
   677  		st.Lock()
   678  		defer st.Unlock()
   679  
   680  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   681  		if err != nil {
   682  			t.Errorf("cannot cleanup partial setup snap %q: %v", snapsup.InstanceName(), err)
   683  			return
   684  		}
   685  
   686  		// remove snap dir is idempotent so it's ok to always call it in the cleanup path
   687  		if err := m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances); err != nil {
   688  			t.Errorf("cannot cleanup partial setup snap %q: %v", snapsup.InstanceName(), err)
   689  		}
   690  
   691  	}
   692  
   693  	pb := NewTaskProgressAdapterUnlocked(t)
   694  	// TODO Use snapsup.Revision() to obtain the right info to mount
   695  	//      instead of assuming the candidate is the right one.
   696  	var snapType snap.Type
   697  	var installRecord *backend.InstallRecord
   698  	timings.Run(perfTimings, "setup-snap", fmt.Sprintf("setup snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   699  		snapType, installRecord, err = m.backend.SetupSnap(snapsup.SnapPath, snapsup.InstanceName(), snapsup.SideInfo, deviceCtx, pb)
   700  	})
   701  	if err != nil {
   702  		cleanup()
   703  		return err
   704  	}
   705  
   706  	// double check that the snap is mounted
   707  	var readInfoErr error
   708  	for i := 0; i < 10; i++ {
   709  		_, readInfoErr = readInfo(snapsup.InstanceName(), snapsup.SideInfo, errorOnBroken)
   710  		if readInfoErr == nil {
   711  			break
   712  		}
   713  		if _, ok := readInfoErr.(*snap.NotFoundError); !ok {
   714  			break
   715  		}
   716  		// snap not found, seems is not mounted yet
   717  		msg := fmt.Sprintf("expected snap %q revision %v to be mounted but is not", snapsup.InstanceName(), snapsup.Revision())
   718  		readInfoErr = fmt.Errorf("cannot proceed, %s", msg)
   719  		if i == 0 {
   720  			logger.Noticef(msg)
   721  		}
   722  		time.Sleep(mountPollInterval)
   723  	}
   724  	if readInfoErr != nil {
   725  		timings.Run(perfTimings, "undo-setup-snap", fmt.Sprintf("Undo setup of snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   726  			err = m.backend.UndoSetupSnap(snapsup.placeInfo(), snapType, installRecord, deviceCtx, pb)
   727  		})
   728  		if err != nil {
   729  			st.Lock()
   730  			t.Errorf("cannot undo partial setup snap %q: %v", snapsup.InstanceName(), err)
   731  			st.Unlock()
   732  		}
   733  
   734  		cleanup()
   735  		return readInfoErr
   736  	}
   737  
   738  	st.Lock()
   739  	// set snapst type for undoMountSnap
   740  	t.Set("snap-type", snapType)
   741  	if installRecord != nil {
   742  		t.Set("install-record", installRecord)
   743  	}
   744  	st.Unlock()
   745  
   746  	if snapsup.Flags.RemoveSnapPath {
   747  		if err := os.Remove(snapsup.SnapPath); err != nil {
   748  			logger.Noticef("Failed to cleanup %s: %s", snapsup.SnapPath, err)
   749  		}
   750  	}
   751  
   752  	st.Lock()
   753  	perfTimings.Save(st)
   754  	st.Unlock()
   755  
   756  	return nil
   757  }
   758  
   759  func (m *SnapManager) undoMountSnap(t *state.Task, _ *tomb.Tomb) error {
   760  	st := t.State()
   761  	st.Lock()
   762  	snapsup, err := TaskSnapSetup(t)
   763  	st.Unlock()
   764  	if err != nil {
   765  		return err
   766  	}
   767  
   768  	st.Lock()
   769  	deviceCtx, err := DeviceCtx(t.State(), t, nil)
   770  	st.Unlock()
   771  	if err != nil {
   772  		return err
   773  	}
   774  
   775  	st.Lock()
   776  	var typ snap.Type
   777  	err = t.Get("snap-type", &typ)
   778  	st.Unlock()
   779  	// backward compatibility
   780  	if err == state.ErrNoState {
   781  		typ = "app"
   782  	} else if err != nil {
   783  		return err
   784  	}
   785  
   786  	var installRecord backend.InstallRecord
   787  	st.Lock()
   788  	// install-record is optional (e.g. not present in tasks from older snapd)
   789  	err = t.Get("install-record", &installRecord)
   790  	st.Unlock()
   791  	if err != nil && err != state.ErrNoState {
   792  		return err
   793  	}
   794  
   795  	pb := NewTaskProgressAdapterUnlocked(t)
   796  	if err := m.backend.UndoSetupSnap(snapsup.placeInfo(), typ, &installRecord, deviceCtx, pb); err != nil {
   797  		return err
   798  	}
   799  
   800  	st.Lock()
   801  	defer st.Unlock()
   802  
   803  	otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   804  	if err != nil {
   805  		return err
   806  	}
   807  
   808  	return m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances)
   809  }
   810  
   811  // queryDisabledServices uses wrappers.QueryDisabledServices()
   812  //
   813  // Note this function takes a snap info rather than snapst because there are
   814  // situations where we want to call this on non-current snap infos, i.e. in the
   815  // undo handlers, see undoLinkSnap for an example.
   816  func (m *SnapManager) queryDisabledServices(info *snap.Info, pb progress.Meter) ([]string, error) {
   817  	return m.backend.QueryDisabledServices(info, pb)
   818  }
   819  
   820  func (m *SnapManager) doUnlinkCurrentSnap(t *state.Task, _ *tomb.Tomb) error {
   821  	// called only during refresh when a new revision of a snap is being
   822  	// installed
   823  	st := t.State()
   824  	st.Lock()
   825  	defer st.Unlock()
   826  
   827  	snapsup, snapst, err := snapSetupAndState(t)
   828  	if err != nil {
   829  		return err
   830  	}
   831  
   832  	oldInfo, err := snapst.CurrentInfo()
   833  	if err != nil {
   834  		return err
   835  	}
   836  
   837  	tr := config.NewTransaction(st)
   838  	experimentalRefreshAppAwareness, err := features.Flag(tr, features.RefreshAppAwareness)
   839  	if err != nil && !config.IsNoOption(err) {
   840  		return err
   841  	}
   842  
   843  	if experimentalRefreshAppAwareness && !snapsup.Flags.IgnoreRunning {
   844  		// Invoke the hard refresh flow. Upon success the returned lock will be
   845  		// held to prevent snap-run from advancing until UnlinkSnap, executed
   846  		// below, completes.
   847  		lock, err := hardEnsureNothingRunningDuringRefresh(m.backend, st, snapst, oldInfo)
   848  		if err != nil {
   849  			return err
   850  		}
   851  		defer lock.Close()
   852  	}
   853  
   854  	snapst.Active = false
   855  
   856  	// snapd current symlink on the refresh path can only replaced by a
   857  	// symlink to a new revision of the snapd snap, so only do the actual
   858  	// unlink if we're not working on the snapd snap
   859  	if oldInfo.Type() != snap.TypeSnapd {
   860  		// do the final unlink
   861  		linkCtx := backend.LinkContext{
   862  			FirstInstall: false,
   863  			// This task is only used for unlinking a snap during refreshes so we
   864  			// can safely hard-code this condition here.
   865  			RunInhibitHint: runinhibit.HintInhibitedForRefresh,
   866  		}
   867  		err = m.backend.UnlinkSnap(oldInfo, linkCtx, NewTaskProgressAdapterLocked(t))
   868  		if err != nil {
   869  			return err
   870  		}
   871  	}
   872  
   873  	// mark as inactive
   874  	Set(st, snapsup.InstanceName(), snapst)
   875  
   876  	// Notify link snap participants about link changes.
   877  	notifyLinkParticipants(t, snapsup.InstanceName())
   878  	return nil
   879  }
   880  
   881  func (m *SnapManager) undoUnlinkCurrentSnap(t *state.Task, _ *tomb.Tomb) error {
   882  	st := t.State()
   883  	st.Lock()
   884  	defer st.Unlock()
   885  
   886  	perfTimings := state.TimingsForTask(t)
   887  	defer perfTimings.Save(st)
   888  
   889  	snapsup, snapst, err := snapSetupAndState(t)
   890  	if err != nil {
   891  		return err
   892  	}
   893  
   894  	oldInfo, err := snapst.CurrentInfo()
   895  	if err != nil {
   896  		return err
   897  	}
   898  
   899  	deviceCtx, err := DeviceCtx(st, t, nil)
   900  	if err != nil {
   901  		return err
   902  	}
   903  
   904  	snapst.Active = true
   905  	opts, err := SnapServiceOptions(st, snapsup.InstanceName(), nil)
   906  	if err != nil {
   907  		return err
   908  	}
   909  	linkCtx := backend.LinkContext{
   910  		FirstInstall:   false,
   911  		ServiceOptions: opts,
   912  	}
   913  	reboot, err := m.backend.LinkSnap(oldInfo, deviceCtx, linkCtx, perfTimings)
   914  	if err != nil {
   915  		return err
   916  	}
   917  
   918  	// mark as active again
   919  	Set(st, snapsup.InstanceName(), snapst)
   920  
   921  	// Notify link snap participants about link changes.
   922  	notifyLinkParticipants(t, snapsup.InstanceName())
   923  
   924  	// if we just put back a previous a core snap, request a restart
   925  	// so that we switch executing its snapd
   926  	m.maybeRestart(t, oldInfo, reboot, deviceCtx)
   927  	return nil
   928  }
   929  
   930  func (m *SnapManager) doCopySnapData(t *state.Task, _ *tomb.Tomb) error {
   931  	st := t.State()
   932  	st.Lock()
   933  	snapsup, snapst, err := snapSetupAndState(t)
   934  	st.Unlock()
   935  	if err != nil {
   936  		return err
   937  	}
   938  
   939  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
   940  	if err != nil {
   941  		return err
   942  	}
   943  
   944  	oldInfo, err := snapst.CurrentInfo()
   945  	if err != nil && err != ErrNoCurrent {
   946  		return err
   947  	}
   948  
   949  	pb := NewTaskProgressAdapterUnlocked(t)
   950  	if copyDataErr := m.backend.CopySnapData(newInfo, oldInfo, pb); copyDataErr != nil {
   951  		if oldInfo != nil {
   952  			// there is another revision of the snap, cannot remove
   953  			// shared data directory
   954  			return copyDataErr
   955  		}
   956  
   957  		// cleanup shared snap data directory
   958  		st.Lock()
   959  		defer st.Unlock()
   960  
   961  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   962  		if err != nil {
   963  			t.Errorf("cannot undo partial snap %q data copy: %v", snapsup.InstanceName(), err)
   964  			return copyDataErr
   965  		}
   966  		// no other instances of this snap, shared data directory can be
   967  		// removed now too
   968  		if err := m.backend.RemoveSnapDataDir(newInfo, otherInstances); err != nil {
   969  			t.Errorf("cannot undo partial snap %q data copy, failed removing shared directory: %v", snapsup.InstanceName(), err)
   970  		}
   971  		return copyDataErr
   972  	}
   973  	return nil
   974  }
   975  
   976  func (m *SnapManager) undoCopySnapData(t *state.Task, _ *tomb.Tomb) error {
   977  	st := t.State()
   978  	st.Lock()
   979  	snapsup, snapst, err := snapSetupAndState(t)
   980  	st.Unlock()
   981  	if err != nil {
   982  		return err
   983  	}
   984  
   985  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
   986  	if err != nil {
   987  		return err
   988  	}
   989  
   990  	oldInfo, err := snapst.CurrentInfo()
   991  	if err != nil && err != ErrNoCurrent {
   992  		return err
   993  	}
   994  
   995  	pb := NewTaskProgressAdapterUnlocked(t)
   996  	if err := m.backend.UndoCopySnapData(newInfo, oldInfo, pb); err != nil {
   997  		return err
   998  	}
   999  
  1000  	if oldInfo != nil {
  1001  		// there is other revision of this snap, cannot remove shared
  1002  		// directory anyway
  1003  		return nil
  1004  	}
  1005  
  1006  	st.Lock()
  1007  	defer st.Unlock()
  1008  
  1009  	otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  1010  	if err != nil {
  1011  		return err
  1012  	}
  1013  	// no other instances of this snap and no other revisions, shared data
  1014  	// directory can be removed
  1015  	if err := m.backend.RemoveSnapDataDir(newInfo, otherInstances); err != nil {
  1016  		return err
  1017  	}
  1018  	return nil
  1019  }
  1020  
  1021  func (m *SnapManager) cleanupCopySnapData(t *state.Task, _ *tomb.Tomb) error {
  1022  	st := t.State()
  1023  	st.Lock()
  1024  	defer st.Unlock()
  1025  
  1026  	if t.Status() != state.DoneStatus {
  1027  		// it failed
  1028  		return nil
  1029  	}
  1030  
  1031  	_, snapst, err := snapSetupAndState(t)
  1032  	if err != nil {
  1033  		return err
  1034  	}
  1035  
  1036  	info, err := snapst.CurrentInfo()
  1037  	if err != nil {
  1038  		return err
  1039  	}
  1040  
  1041  	m.backend.ClearTrashedData(info)
  1042  
  1043  	return nil
  1044  }
  1045  
  1046  // writeSeqFile writes the sequence file for failover handling
  1047  func writeSeqFile(name string, snapst *SnapState) error {
  1048  	p := filepath.Join(dirs.SnapSeqDir, name+".json")
  1049  	if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
  1050  		return err
  1051  	}
  1052  
  1053  	b, err := json.Marshal(&struct {
  1054  		Sequence []*snap.SideInfo `json:"sequence"`
  1055  		Current  string           `json:"current"`
  1056  	}{
  1057  		Sequence: snapst.Sequence,
  1058  		Current:  snapst.Current.String(),
  1059  	})
  1060  	if err != nil {
  1061  		return err
  1062  	}
  1063  
  1064  	return osutil.AtomicWriteFile(p, b, 0644, 0)
  1065  }
  1066  
  1067  // missingDisabledServices returns a list of services that are present in
  1068  // this snap info and should be disabled as well as a list of disabled
  1069  // services that are currently missing (i.e. they were renamed).
  1070  // present in this snap info.
  1071  // the first arg is the disabled services when the snap was last active
  1072  func missingDisabledServices(svcs []string, info *snap.Info) ([]string, []string, error) {
  1073  	// make a copy of all the previously disabled services that we will remove
  1074  	// from, as well as an empty list to add to for the found services
  1075  	missingSvcs := []string{}
  1076  	foundSvcs := []string{}
  1077  
  1078  	// for all the previously disabled services, check if they are in the
  1079  	// current snap info revision as services or not
  1080  	for _, disabledSvcName := range svcs {
  1081  		// check if the service is an app _and_ is a service
  1082  		if app, ok := info.Apps[disabledSvcName]; ok && app.IsService() {
  1083  			foundSvcs = append(foundSvcs, disabledSvcName)
  1084  		} else {
  1085  			missingSvcs = append(missingSvcs, disabledSvcName)
  1086  		}
  1087  	}
  1088  
  1089  	// sort the lists for easier testing
  1090  	sort.Strings(missingSvcs)
  1091  	sort.Strings(foundSvcs)
  1092  
  1093  	return foundSvcs, missingSvcs, nil
  1094  }
  1095  
  1096  // LinkSnapParticipant is an interface for interacting with snap link/unlink
  1097  // operations.
  1098  //
  1099  // Unlike the interface for a task handler, only one notification method is
  1100  // used. The method notifies a participant that linkage of a snap has changed.
  1101  // This method is invoked in link-snap, unlink-snap, the undo path of those
  1102  // methods and the undo handler for link-snap.
  1103  //
  1104  // In all cases it is invoked after all other operations are completed but
  1105  // before the task completes.
  1106  type LinkSnapParticipant interface {
  1107  	// SnapLinkageChanged is called when a snap is linked or unlinked.
  1108  	// The error is only logged and does not stop the task it is used from.
  1109  	SnapLinkageChanged(st *state.State, instanceName string) error
  1110  }
  1111  
  1112  var linkSnapParticipants []LinkSnapParticipant
  1113  
  1114  // AddLinkSnapParticipant adds a participant in the link/unlink operations.
  1115  func AddLinkSnapParticipant(p LinkSnapParticipant) {
  1116  	linkSnapParticipants = append(linkSnapParticipants, p)
  1117  }
  1118  
  1119  // MockLinkSnapParticipants replaces the list of link snap participants for testing.
  1120  func MockLinkSnapParticipants(ps []LinkSnapParticipant) (restore func()) {
  1121  	old := linkSnapParticipants
  1122  	linkSnapParticipants = ps
  1123  	return func() {
  1124  		linkSnapParticipants = old
  1125  	}
  1126  }
  1127  
  1128  func notifyLinkParticipants(t *state.Task, instanceName string) {
  1129  	st := t.State()
  1130  	for _, p := range linkSnapParticipants {
  1131  		if err := p.SnapLinkageChanged(st, instanceName); err != nil {
  1132  			t.Errorf("%v", err)
  1133  		}
  1134  	}
  1135  }
  1136  
  1137  func (m *SnapManager) doLinkSnap(t *state.Task, _ *tomb.Tomb) (err error) {
  1138  	st := t.State()
  1139  	st.Lock()
  1140  	defer st.Unlock()
  1141  
  1142  	perfTimings := state.TimingsForTask(t)
  1143  	defer perfTimings.Save(st)
  1144  
  1145  	snapsup, snapst, err := snapSetupAndState(t)
  1146  	if err != nil {
  1147  		return err
  1148  	}
  1149  
  1150  	deviceCtx, err := DeviceCtx(st, t, nil)
  1151  	if err != nil {
  1152  		return err
  1153  	}
  1154  
  1155  	oldInfo, err := snapst.CurrentInfo()
  1156  	if err != nil && err != ErrNoCurrent {
  1157  		return err
  1158  	}
  1159  
  1160  	// find if the snap is already installed before we modify snapst below
  1161  	isInstalled := snapst.IsInstalled()
  1162  
  1163  	cand := snapsup.SideInfo
  1164  	m.backend.Candidate(cand)
  1165  
  1166  	oldCandidateIndex := snapst.LastIndex(cand.Revision)
  1167  
  1168  	if oldCandidateIndex < 0 {
  1169  		snapst.Sequence = append(snapst.Sequence, cand)
  1170  	} else if !snapsup.Revert {
  1171  		// remove the old candidate from the sequence, add it at the end
  1172  		copy(snapst.Sequence[oldCandidateIndex:len(snapst.Sequence)-1], snapst.Sequence[oldCandidateIndex+1:])
  1173  		snapst.Sequence[len(snapst.Sequence)-1] = cand
  1174  	}
  1175  
  1176  	oldCurrent := snapst.Current
  1177  	snapst.Current = cand.Revision
  1178  	snapst.Active = true
  1179  	oldChannel := snapst.TrackingChannel
  1180  	if snapsup.Channel != "" {
  1181  		err := snapst.SetTrackingChannel(snapsup.Channel)
  1182  		if err != nil {
  1183  			return err
  1184  		}
  1185  	}
  1186  	oldIgnoreValidation := snapst.IgnoreValidation
  1187  	snapst.IgnoreValidation = snapsup.IgnoreValidation
  1188  	oldTryMode := snapst.TryMode
  1189  	snapst.TryMode = snapsup.TryMode
  1190  	oldDevMode := snapst.DevMode
  1191  	snapst.DevMode = snapsup.DevMode
  1192  	oldJailMode := snapst.JailMode
  1193  	snapst.JailMode = snapsup.JailMode
  1194  	oldClassic := snapst.Classic
  1195  	snapst.Classic = snapsup.Classic
  1196  	oldCohortKey := snapst.CohortKey
  1197  	snapst.CohortKey = snapsup.CohortKey
  1198  	if snapsup.Required { // set only on install and left alone on refresh
  1199  		snapst.Required = true
  1200  	}
  1201  	oldRefreshInhibitedTime := snapst.RefreshInhibitedTime
  1202  	// only set userID if unset or logged out in snapst and if we
  1203  	// actually have an associated user
  1204  	if snapsup.UserID > 0 {
  1205  		var user *auth.UserState
  1206  		if snapst.UserID != 0 {
  1207  			user, err = auth.User(st, snapst.UserID)
  1208  			if err != nil && err != auth.ErrInvalidUser {
  1209  				return err
  1210  			}
  1211  		}
  1212  		if user == nil {
  1213  			// if the original user installing the snap is
  1214  			// no longer available transfer to user who
  1215  			// triggered this change
  1216  			snapst.UserID = snapsup.UserID
  1217  		}
  1218  	}
  1219  	// keep instance key
  1220  	snapst.InstanceKey = snapsup.InstanceKey
  1221  
  1222  	newInfo, err := readInfo(snapsup.InstanceName(), cand, 0)
  1223  	if err != nil {
  1224  		return err
  1225  	}
  1226  
  1227  	// record type
  1228  	snapst.SetType(newInfo.Type())
  1229  
  1230  	pb := NewTaskProgressAdapterLocked(t)
  1231  
  1232  	// Check for D-Bus service conflicts a second time to detect
  1233  	// conflicts within a transaction.
  1234  	if err := checkDBusServiceConflicts(st, newInfo); err != nil {
  1235  		return err
  1236  	}
  1237  
  1238  	opts, err := SnapServiceOptions(st, snapsup.InstanceName(), nil)
  1239  	if err != nil {
  1240  		return err
  1241  	}
  1242  	firstInstall := oldCurrent.Unset()
  1243  	linkCtx := backend.LinkContext{
  1244  		FirstInstall:   firstInstall,
  1245  		ServiceOptions: opts,
  1246  	}
  1247  	// on UC18+, snap tooling comes from the snapd snap so we need generated
  1248  	// mount units to depend on the snapd snap mount units
  1249  	if !deviceCtx.Classic() && deviceCtx.Model().Base() != "" {
  1250  		linkCtx.RequireMountedSnapdSnap = true
  1251  	}
  1252  	reboot, err := m.backend.LinkSnap(newInfo, deviceCtx, linkCtx, perfTimings)
  1253  	// defer a cleanup helper which will unlink the snap if anything fails after
  1254  	// this point
  1255  	defer func() {
  1256  		if err == nil {
  1257  			return
  1258  		}
  1259  		// err is not nil, we need to try and unlink the snap to cleanup after
  1260  		// ourselves
  1261  		var backendErr error
  1262  		if newInfo.Type() == snap.TypeSnapd && !firstInstall {
  1263  			// snapd snap is special in the sense that we always
  1264  			// need the current symlink, so we restore the link to
  1265  			// the old revision
  1266  			_, backendErr = m.backend.LinkSnap(oldInfo, deviceCtx, linkCtx, perfTimings)
  1267  		} else {
  1268  			// snapd during first install and all other snaps
  1269  			backendErr = m.backend.UnlinkSnap(newInfo, linkCtx, pb)
  1270  		}
  1271  		if backendErr != nil {
  1272  			t.Errorf("cannot cleanup failed attempt at making snap %q available to the system: %v", snapsup.InstanceName(), backendErr)
  1273  		}
  1274  		notifyLinkParticipants(t, snapsup.InstanceName())
  1275  	}()
  1276  	if err != nil {
  1277  		return err
  1278  	}
  1279  
  1280  	// Restore configuration of the target revision (if available) on revert
  1281  	if isInstalled {
  1282  		// Make a copy of configuration of current snap revision
  1283  		if err = config.SaveRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1284  			return err
  1285  		}
  1286  	}
  1287  
  1288  	// Restore configuration of the target revision (if available; nothing happens if it's not).
  1289  	// We only do this on reverts (and not on refreshes).
  1290  	if snapsup.Revert {
  1291  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  1292  			return err
  1293  		}
  1294  	}
  1295  
  1296  	if len(snapst.Sequence) == 1 {
  1297  		if err := m.createSnapCookie(st, snapsup.InstanceName()); err != nil {
  1298  			return fmt.Errorf("cannot create snap cookie: %v", err)
  1299  		}
  1300  	}
  1301  	// save for undoLinkSnap
  1302  	t.Set("old-trymode", oldTryMode)
  1303  	t.Set("old-devmode", oldDevMode)
  1304  	t.Set("old-jailmode", oldJailMode)
  1305  	t.Set("old-classic", oldClassic)
  1306  	t.Set("old-ignore-validation", oldIgnoreValidation)
  1307  	t.Set("old-channel", oldChannel)
  1308  	t.Set("old-current", oldCurrent)
  1309  	t.Set("old-candidate-index", oldCandidateIndex)
  1310  	t.Set("old-refresh-inhibited-time", oldRefreshInhibitedTime)
  1311  	t.Set("old-cohort-key", oldCohortKey)
  1312  
  1313  	// Record the fact that the snap was refreshed successfully.
  1314  	snapst.RefreshInhibitedTime = nil
  1315  
  1316  	if cand.SnapID != "" {
  1317  		// write the auxiliary store info
  1318  		aux := &auxStoreInfo{
  1319  			Media:   snapsup.Media,
  1320  			Website: snapsup.Website,
  1321  		}
  1322  		if err := keepAuxStoreInfo(cand.SnapID, aux); err != nil {
  1323  			return err
  1324  		}
  1325  		if len(snapst.Sequence) == 1 {
  1326  			defer func() {
  1327  				if err != nil {
  1328  					// the install is getting undone, and there are no more of this snap
  1329  					// try to remove the aux info we just created
  1330  					discardAuxStoreInfo(cand.SnapID)
  1331  				}
  1332  			}()
  1333  		}
  1334  	}
  1335  
  1336  	// write sequence file for failover helpers
  1337  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1338  		return err
  1339  	}
  1340  
  1341  	// Compatibility with old snapd: check if we have auto-connect task and
  1342  	// if not, inject it after self (link-snap) for snaps that are not core
  1343  	if newInfo.Type() != snap.TypeOS {
  1344  		var hasAutoConnect, hasSetupProfiles bool
  1345  		for _, other := range t.Change().Tasks() {
  1346  			// Check if this is auto-connect task for same snap and we it's part of the change with setup-profiles task
  1347  			if other.Kind() == "auto-connect" || other.Kind() == "setup-profiles" {
  1348  				otherSnapsup, err := TaskSnapSetup(other)
  1349  				if err != nil {
  1350  					return err
  1351  				}
  1352  				if snapsup.InstanceName() == otherSnapsup.InstanceName() {
  1353  					if other.Kind() == "auto-connect" {
  1354  						hasAutoConnect = true
  1355  					} else {
  1356  						hasSetupProfiles = true
  1357  					}
  1358  				}
  1359  			}
  1360  		}
  1361  		if !hasAutoConnect && hasSetupProfiles {
  1362  			InjectAutoConnect(t, snapsup)
  1363  		}
  1364  	}
  1365  
  1366  	// Do at the end so we only preserve the new state if it worked.
  1367  	Set(st, snapsup.InstanceName(), snapst)
  1368  
  1369  	// Notify link snap participants about link changes.
  1370  	notifyLinkParticipants(t, snapsup.InstanceName())
  1371  
  1372  	// Make sure if state commits and snapst is mutated we won't be rerun
  1373  	t.SetStatus(state.DoneStatus)
  1374  
  1375  	// if we just installed a core snap, request a restart
  1376  	// so that we switch executing its snapd.
  1377  	m.maybeRestart(t, newInfo, reboot, deviceCtx)
  1378  
  1379  	return nil
  1380  }
  1381  
  1382  // maybeRestart will schedule a reboot or restart as needed for the
  1383  // just linked snap with info if it's a core or snapd or kernel snap.
  1384  func (m *SnapManager) maybeRestart(t *state.Task, info *snap.Info, rebootRequired bool, deviceCtx DeviceContext) {
  1385  	// Don't restart when preseeding - we will switch to new snapd on
  1386  	// first boot.
  1387  	if m.preseed {
  1388  		return
  1389  	}
  1390  
  1391  	st := t.State()
  1392  
  1393  	if rebootRequired {
  1394  		t.Logf("Requested system restart.")
  1395  		st.RequestRestart(state.RestartSystem)
  1396  		return
  1397  	}
  1398  
  1399  	typ := info.Type()
  1400  
  1401  	// if bp is non-trivial then either we're not on classic, or the snap is
  1402  	// snapd. So daemonRestartReason will always return "" which is what we
  1403  	// want. If that combination stops being true and there's a situation
  1404  	// where a non-trivial bp could return a non-empty reason, use IsTrivial
  1405  	// to check and bail before reaching this far.
  1406  
  1407  	restartReason := daemonRestartReason(st, typ)
  1408  	if restartReason == "" {
  1409  		// no message -> no restart
  1410  		return
  1411  	}
  1412  
  1413  	t.Logf(restartReason)
  1414  	st.RequestRestart(state.RestartDaemon)
  1415  }
  1416  
  1417  func daemonRestartReason(st *state.State, typ snap.Type) string {
  1418  	if !((release.OnClassic && typ == snap.TypeOS) || typ == snap.TypeSnapd) {
  1419  		// not interesting
  1420  		return ""
  1421  	}
  1422  
  1423  	if typ == snap.TypeOS {
  1424  		// ignore error here as we have no way to return to caller
  1425  		snapdSnapInstalled, _ := isInstalled(st, "snapd")
  1426  		if snapdSnapInstalled {
  1427  			// this snap is the base, but snapd is running from the snapd snap
  1428  			return ""
  1429  		}
  1430  		return "Requested daemon restart."
  1431  	}
  1432  
  1433  	return "Requested daemon restart (snapd snap)."
  1434  }
  1435  
  1436  // maybeUndoRemodelBootChanges will check if an undo needs to update the
  1437  // bootloader. This can happen if e.g. a new kernel gets installed. This
  1438  // will switch the bootloader to the new kernel but if the change is later
  1439  // undone we need to switch back to the kernel of the old model.
  1440  func (m *SnapManager) maybeUndoRemodelBootChanges(t *state.Task) error {
  1441  	// get the new and the old model
  1442  	deviceCtx, err := DeviceCtx(t.State(), t, nil)
  1443  	if err != nil {
  1444  		return err
  1445  	}
  1446  	// we only have an old model if we are in a remodel situation
  1447  	if !deviceCtx.ForRemodeling() {
  1448  		return nil
  1449  	}
  1450  	groundDeviceCtx := deviceCtx.GroundContext()
  1451  	oldModel := groundDeviceCtx.Model()
  1452  	newModel := deviceCtx.Model()
  1453  
  1454  	// check type of the snap we are undoing, only kernel/base/core are
  1455  	// relevant
  1456  	snapsup, _, err := snapSetupAndState(t)
  1457  	if err != nil {
  1458  		return err
  1459  	}
  1460  	var newSnapName, snapName string
  1461  	switch snapsup.Type {
  1462  	case snap.TypeKernel:
  1463  		snapName = oldModel.Kernel()
  1464  		newSnapName = newModel.Kernel()
  1465  	case snap.TypeOS, snap.TypeBase:
  1466  		// XXX: add support for "core"
  1467  		snapName = oldModel.Base()
  1468  		newSnapName = newModel.Base()
  1469  	default:
  1470  		return nil
  1471  	}
  1472  	// we can stop if the kernel/base has not changed
  1473  	if snapName == newSnapName {
  1474  		return nil
  1475  	}
  1476  	// we can stop if the snap we are looking at is not a kernel/base
  1477  	// of the new model
  1478  	if snapsup.InstanceName() != newSnapName {
  1479  		return nil
  1480  	}
  1481  	// get info for *old* kernel/base/core and see if we need to reboot
  1482  	// TODO: we may need something like infoForDeviceSnap here
  1483  	var snapst SnapState
  1484  	if err = Get(t.State(), snapName, &snapst); err != nil {
  1485  		return err
  1486  	}
  1487  	info, err := snapst.CurrentInfo()
  1488  	if err != nil && err != ErrNoCurrent {
  1489  		return err
  1490  	}
  1491  	bp := boot.Participant(info, info.Type(), groundDeviceCtx)
  1492  	reboot, err := bp.SetNextBoot()
  1493  	if err != nil {
  1494  		return err
  1495  	}
  1496  
  1497  	// we may just have switch back to the old kernel/base/core so
  1498  	// we may need to restart
  1499  	m.maybeRestart(t, info, reboot, groundDeviceCtx)
  1500  
  1501  	return nil
  1502  }
  1503  
  1504  func (m *SnapManager) undoLinkSnap(t *state.Task, _ *tomb.Tomb) error {
  1505  	st := t.State()
  1506  	st.Lock()
  1507  	defer st.Unlock()
  1508  
  1509  	deviceCtx, err := DeviceCtx(st, t, nil)
  1510  	if err != nil {
  1511  		return err
  1512  	}
  1513  
  1514  	perfTimings := state.TimingsForTask(t)
  1515  	defer perfTimings.Save(st)
  1516  
  1517  	snapsup, snapst, err := snapSetupAndState(t)
  1518  	if err != nil {
  1519  		return err
  1520  	}
  1521  
  1522  	var oldChannel string
  1523  	err = t.Get("old-channel", &oldChannel)
  1524  	if err != nil {
  1525  		return err
  1526  	}
  1527  	var oldIgnoreValidation bool
  1528  	err = t.Get("old-ignore-validation", &oldIgnoreValidation)
  1529  	if err != nil && err != state.ErrNoState {
  1530  		return err
  1531  	}
  1532  	var oldTryMode bool
  1533  	err = t.Get("old-trymode", &oldTryMode)
  1534  	if err != nil {
  1535  		return err
  1536  	}
  1537  	var oldDevMode bool
  1538  	err = t.Get("old-devmode", &oldDevMode)
  1539  	if err != nil {
  1540  		return err
  1541  	}
  1542  	var oldJailMode bool
  1543  	err = t.Get("old-jailmode", &oldJailMode)
  1544  	if err != nil {
  1545  		return err
  1546  	}
  1547  	var oldClassic bool
  1548  	err = t.Get("old-classic", &oldClassic)
  1549  	if err != nil {
  1550  		return err
  1551  	}
  1552  	var oldCurrent snap.Revision
  1553  	err = t.Get("old-current", &oldCurrent)
  1554  	if err != nil {
  1555  		return err
  1556  	}
  1557  	var oldCandidateIndex int
  1558  	if err := t.Get("old-candidate-index", &oldCandidateIndex); err != nil {
  1559  		return err
  1560  	}
  1561  	var oldRefreshInhibitedTime *time.Time
  1562  	if err := t.Get("old-refresh-inhibited-time", &oldRefreshInhibitedTime); err != nil && err != state.ErrNoState {
  1563  		return err
  1564  	}
  1565  	var oldCohortKey string
  1566  	if err := t.Get("old-cohort-key", &oldCohortKey); err != nil && err != state.ErrNoState {
  1567  		return err
  1568  	}
  1569  
  1570  	if len(snapst.Sequence) == 1 {
  1571  		// XXX: shouldn't these two just log and carry on? this is an undo handler...
  1572  		timings.Run(perfTimings, "discard-snap-namespace", fmt.Sprintf("discard the namespace of snap %q", snapsup.InstanceName()), func(tm timings.Measurer) {
  1573  			err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  1574  		})
  1575  		if err != nil {
  1576  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  1577  			return &state.Retry{After: 3 * time.Minute}
  1578  		}
  1579  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  1580  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  1581  		}
  1582  		// try to remove the auxiliary store info
  1583  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  1584  			return fmt.Errorf("cannot remove auxiliary store info: %v", err)
  1585  		}
  1586  	}
  1587  
  1588  	isRevert := snapsup.Revert
  1589  
  1590  	// relinking of the old snap is done in the undo of unlink-current-snap
  1591  	currentIndex := snapst.LastIndex(snapst.Current)
  1592  	if currentIndex < 0 {
  1593  		return fmt.Errorf("internal error: cannot find revision %d in %v for undoing the added revision", snapsup.SideInfo.Revision, snapst.Sequence)
  1594  	}
  1595  
  1596  	if oldCandidateIndex < 0 {
  1597  		snapst.Sequence = append(snapst.Sequence[:currentIndex], snapst.Sequence[currentIndex+1:]...)
  1598  	} else if !isRevert {
  1599  		oldCand := snapst.Sequence[currentIndex]
  1600  		copy(snapst.Sequence[oldCandidateIndex+1:], snapst.Sequence[oldCandidateIndex:])
  1601  		snapst.Sequence[oldCandidateIndex] = oldCand
  1602  	}
  1603  	snapst.Current = oldCurrent
  1604  	snapst.Active = false
  1605  	snapst.TrackingChannel = oldChannel
  1606  	snapst.IgnoreValidation = oldIgnoreValidation
  1607  	snapst.TryMode = oldTryMode
  1608  	snapst.DevMode = oldDevMode
  1609  	snapst.JailMode = oldJailMode
  1610  	snapst.Classic = oldClassic
  1611  	snapst.RefreshInhibitedTime = oldRefreshInhibitedTime
  1612  	snapst.CohortKey = oldCohortKey
  1613  
  1614  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
  1615  	if err != nil {
  1616  		return err
  1617  	}
  1618  
  1619  	// we need to undo potential changes to current snap configuration (e.g. if
  1620  	// modified by post-refresh/install/configure hooks as part of failed
  1621  	// refresh/install) by restoring the configuration of "old current".
  1622  	// similarly, we need to re-save the disabled services if there is a
  1623  	// revision for us to go back to, see comment below for full explanation
  1624  	if len(snapst.Sequence) > 0 {
  1625  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1626  			return err
  1627  		}
  1628  	} else {
  1629  		// in the case of an install we need to clear any config
  1630  		err = config.DeleteSnapConfig(st, snapsup.InstanceName())
  1631  		if err != nil {
  1632  			return err
  1633  		}
  1634  	}
  1635  
  1636  	pb := NewTaskProgressAdapterLocked(t)
  1637  	firstInstall := oldCurrent.Unset()
  1638  	linkCtx := backend.LinkContext{
  1639  		FirstInstall: firstInstall,
  1640  	}
  1641  	var backendErr error
  1642  	if newInfo.Type() == snap.TypeSnapd && !firstInstall {
  1643  		// snapst has been updated and now is the old revision, since
  1644  		// this is not the first install of snapd, it should exist
  1645  		var oldInfo *snap.Info
  1646  		oldInfo, err := snapst.CurrentInfo()
  1647  		if err != nil {
  1648  			return err
  1649  		}
  1650  		// the snapd snap is special in the sense that we need to make
  1651  		// sure that a sensible version is always linked as current,
  1652  		// also we never reboot when updating snapd snap
  1653  		_, backendErr = m.backend.LinkSnap(oldInfo, deviceCtx, linkCtx, perfTimings)
  1654  	} else {
  1655  		// snapd during first install and all other snaps
  1656  		backendErr = m.backend.UnlinkSnap(newInfo, linkCtx, pb)
  1657  	}
  1658  	if backendErr != nil {
  1659  		return backendErr
  1660  	}
  1661  
  1662  	if err := m.maybeUndoRemodelBootChanges(t); err != nil {
  1663  		return err
  1664  	}
  1665  
  1666  	// restart only when snapd was installed for the first time and the rest of
  1667  	// the cleanup is performed by snapd from core;
  1668  	// when reverting a subsequent snapd revision, the restart happens in
  1669  	// undoLinkCurrentSnap() instead
  1670  	if firstInstall && newInfo.Type() == snap.TypeSnapd {
  1671  		const rebootRequired = false
  1672  		m.maybeRestart(t, newInfo, rebootRequired, deviceCtx)
  1673  	}
  1674  
  1675  	// write sequence file for failover helpers
  1676  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1677  		return err
  1678  	}
  1679  	// mark as inactive
  1680  	Set(st, snapsup.InstanceName(), snapst)
  1681  
  1682  	// Notify link snap participants about link changes.
  1683  	notifyLinkParticipants(t, snapsup.InstanceName())
  1684  
  1685  	// Make sure if state commits and snapst is mutated we won't be rerun
  1686  	t.SetStatus(state.UndoneStatus)
  1687  
  1688  	// If we are on classic and have no previous version of core
  1689  	// we may have restarted from a distro package into the core
  1690  	// snap. We need to undo that restart here. Instead of in
  1691  	// doUnlinkCurrentSnap() like we usually do when going from
  1692  	// core snap -> next core snap
  1693  	if release.OnClassic && newInfo.Type() == snap.TypeOS && oldCurrent.Unset() {
  1694  		t.Logf("Requested daemon restart (undo classic initial core install)")
  1695  		st.RequestRestart(state.RestartDaemon)
  1696  	}
  1697  	return nil
  1698  }
  1699  
  1700  type doSwitchFlags struct {
  1701  	switchCurrentChannel bool
  1702  }
  1703  
  1704  // doSwitchSnapChannel switches the snap's tracking channel and/or cohort. It
  1705  // also switches the current channel if appropriate. For use from 'Update'.
  1706  func (m *SnapManager) doSwitchSnapChannel(t *state.Task, _ *tomb.Tomb) error {
  1707  	return m.genericDoSwitchSnap(t, doSwitchFlags{switchCurrentChannel: true})
  1708  }
  1709  
  1710  // doSwitchSnap switches the snap's tracking channel and/or cohort, *without*
  1711  // switching the current snap channel. For use from 'Switch'.
  1712  func (m *SnapManager) doSwitchSnap(t *state.Task, _ *tomb.Tomb) error {
  1713  	return m.genericDoSwitchSnap(t, doSwitchFlags{})
  1714  }
  1715  
  1716  func (m *SnapManager) genericDoSwitchSnap(t *state.Task, flags doSwitchFlags) error {
  1717  	st := t.State()
  1718  	st.Lock()
  1719  	defer st.Unlock()
  1720  
  1721  	snapsup, snapst, err := snapSetupAndState(t)
  1722  	if err != nil {
  1723  		return err
  1724  	}
  1725  
  1726  	// switched the tracked channel
  1727  	if err := snapst.SetTrackingChannel(snapsup.Channel); err != nil {
  1728  		return err
  1729  	}
  1730  	snapst.CohortKey = snapsup.CohortKey
  1731  	if flags.switchCurrentChannel {
  1732  		// optionally support switching the current snap channel too, e.g.
  1733  		// if a snap is in both stable and candidate with the same revision
  1734  		// we can update it here and it will be displayed correctly in the UI
  1735  		if snapsup.SideInfo.Channel != "" {
  1736  			snapst.CurrentSideInfo().Channel = snapsup.Channel
  1737  		}
  1738  	}
  1739  
  1740  	Set(st, snapsup.InstanceName(), snapst)
  1741  	return nil
  1742  }
  1743  
  1744  func (m *SnapManager) doToggleSnapFlags(t *state.Task, _ *tomb.Tomb) error {
  1745  	st := t.State()
  1746  	st.Lock()
  1747  	defer st.Unlock()
  1748  
  1749  	snapsup, snapst, err := snapSetupAndState(t)
  1750  	if err != nil {
  1751  		return err
  1752  	}
  1753  
  1754  	// for now we support toggling only ignore-validation
  1755  	snapst.IgnoreValidation = snapsup.IgnoreValidation
  1756  
  1757  	Set(st, snapsup.InstanceName(), snapst)
  1758  	return nil
  1759  }
  1760  
  1761  // installModeDisabledServices returns what services with
  1762  // "install-mode: disabled" should be disabled. Only services
  1763  // seen for the first time are considered.
  1764  func installModeDisabledServices(st *state.State, snapst *SnapState, currentInfo *snap.Info) (svcsToDisable []string, err error) {
  1765  	enabledByHookSvcs := map[string]bool{}
  1766  	for _, svcName := range snapst.ServicesEnabledByHooks {
  1767  		enabledByHookSvcs[svcName] = true
  1768  	}
  1769  
  1770  	// find what servies the previous snap had
  1771  	prevCurrentSvcs := map[string]bool{}
  1772  	if psi := snapst.previousSideInfo(); psi != nil {
  1773  		var prevCurrentInfo *snap.Info
  1774  		if prevCurrentInfo, err = Info(st, snapst.InstanceName(), psi.Revision); prevCurrentInfo != nil {
  1775  			for _, prevSvc := range prevCurrentInfo.Services() {
  1776  				prevCurrentSvcs[prevSvc.Name] = true
  1777  			}
  1778  		}
  1779  	}
  1780  	// and deal with "install-mode: disable" for all new services
  1781  	// (i.e. not present in previous snap).
  1782  	//
  1783  	// Services that are not new but have "install-mode: disable"
  1784  	// do not need special handling. They are either still disabled
  1785  	// or something has enabled them and then they should stay enabled.
  1786  	for _, svc := range currentInfo.Services() {
  1787  		if svc.InstallMode == "disable" && !enabledByHookSvcs[svc.Name] {
  1788  			if !prevCurrentSvcs[svc.Name] {
  1789  				svcsToDisable = append(svcsToDisable, svc.Name)
  1790  			}
  1791  		}
  1792  	}
  1793  	return svcsToDisable, nil
  1794  }
  1795  
  1796  func (m *SnapManager) startSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1797  	st := t.State()
  1798  	st.Lock()
  1799  	defer st.Unlock()
  1800  
  1801  	perfTimings := state.TimingsForTask(t)
  1802  	defer perfTimings.Save(st)
  1803  
  1804  	snapsup, snapst, err := snapSetupAndState(t)
  1805  	if err != nil {
  1806  		return err
  1807  	}
  1808  	currentInfo, err := snapst.CurrentInfo()
  1809  	if err != nil {
  1810  		return err
  1811  	}
  1812  
  1813  	// check if any previously disabled services are now no longer services and
  1814  	// log messages about that
  1815  	for _, svc := range snapst.LastActiveDisabledServices {
  1816  		app, ok := currentInfo.Apps[svc]
  1817  		if !ok {
  1818  			logger.Noticef("previously disabled service %s no longer exists", svc)
  1819  		} else if !app.IsService() {
  1820  			logger.Noticef("previously disabled service %s is now an app and not a service", svc)
  1821  		}
  1822  	}
  1823  
  1824  	// get the services which should be disabled (not started),
  1825  	// as well as the services which are not present in this revision, but were
  1826  	// present and disabled in a previous one and as such should be kept inside
  1827  	// snapst for persistent storage
  1828  	svcsToDisable, svcsToSave, err := missingDisabledServices(snapst.LastActiveDisabledServices, currentInfo)
  1829  	if err != nil {
  1830  		return err
  1831  	}
  1832  
  1833  	// check what services with "InstallMode: disable" need to be disabled
  1834  	svcsToDisableFromInstallMode, err := installModeDisabledServices(st, snapst, currentInfo)
  1835  	if err != nil {
  1836  		return err
  1837  	}
  1838  	svcsToDisable = append(svcsToDisable, svcsToDisableFromInstallMode...)
  1839  
  1840  	// append services that were disabled by hooks (they should not get re-enabled)
  1841  	svcsToDisable = append(svcsToDisable, snapst.ServicesDisabledByHooks...)
  1842  
  1843  	// save the current last-active-disabled-services before we re-write it in case we
  1844  	// need to undo this
  1845  	t.Set("old-last-active-disabled-services", snapst.LastActiveDisabledServices)
  1846  
  1847  	// commit the missing services to state so when we unlink this revision and
  1848  	// go to a different revision with potentially different service names, the
  1849  	// currently missing service names will be re-disabled if they exist later
  1850  	snapst.LastActiveDisabledServices = svcsToSave
  1851  
  1852  	// reset services tracked by operations from hooks
  1853  	snapst.ServicesDisabledByHooks = nil
  1854  	snapst.ServicesEnabledByHooks = nil
  1855  	Set(st, snapsup.InstanceName(), snapst)
  1856  
  1857  	svcs := currentInfo.Services()
  1858  	if len(svcs) == 0 {
  1859  		return nil
  1860  	}
  1861  
  1862  	startupOrdered, err := snap.SortServices(svcs)
  1863  	if err != nil {
  1864  		return err
  1865  	}
  1866  
  1867  	pb := NewTaskProgressAdapterUnlocked(t)
  1868  
  1869  	st.Unlock()
  1870  	err = m.backend.StartServices(startupOrdered, svcsToDisable, pb, perfTimings)
  1871  	st.Lock()
  1872  
  1873  	return err
  1874  }
  1875  
  1876  func (m *SnapManager) undoStartSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1877  	st := t.State()
  1878  	st.Lock()
  1879  	defer st.Unlock()
  1880  
  1881  	perfTimings := state.TimingsForTask(t)
  1882  	defer perfTimings.Save(st)
  1883  
  1884  	snapsup, snapst, err := snapSetupAndState(t)
  1885  	if err != nil {
  1886  		return err
  1887  	}
  1888  
  1889  	currentInfo, err := snapst.CurrentInfo()
  1890  	if err != nil {
  1891  		return err
  1892  	}
  1893  
  1894  	var oldLastActiveDisabledServices []string
  1895  	if err := t.Get("old-last-active-disabled-services", &oldLastActiveDisabledServices); err != nil && err != state.ErrNoState {
  1896  		return err
  1897  	}
  1898  	snapst.LastActiveDisabledServices = oldLastActiveDisabledServices
  1899  	Set(st, snapsup.InstanceName(), snapst)
  1900  
  1901  	svcs := currentInfo.Services()
  1902  	if len(svcs) == 0 {
  1903  		return nil
  1904  	}
  1905  
  1906  	// XXX: stop reason not set on start task, should we have a new reason for undo?
  1907  	var stopReason snap.ServiceStopReason
  1908  
  1909  	// stop the services
  1910  	err = m.backend.StopServices(svcs, stopReason, progress.Null, perfTimings)
  1911  	if err != nil {
  1912  		return err
  1913  	}
  1914  
  1915  	return nil
  1916  }
  1917  
  1918  func (m *SnapManager) stopSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1919  	st := t.State()
  1920  	st.Lock()
  1921  	defer st.Unlock()
  1922  
  1923  	perfTimings := state.TimingsForTask(t)
  1924  	defer perfTimings.Save(st)
  1925  
  1926  	snapsup, snapst, err := snapSetupAndState(t)
  1927  	if err != nil {
  1928  		return err
  1929  	}
  1930  
  1931  	currentInfo, err := snapst.CurrentInfo()
  1932  	if err != nil {
  1933  		return err
  1934  	}
  1935  	svcs := currentInfo.Services()
  1936  	if len(svcs) == 0 {
  1937  		return nil
  1938  	}
  1939  
  1940  	var stopReason snap.ServiceStopReason
  1941  	if err := t.Get("stop-reason", &stopReason); err != nil && err != state.ErrNoState {
  1942  		return err
  1943  	}
  1944  
  1945  	pb := NewTaskProgressAdapterUnlocked(t)
  1946  	st.Unlock()
  1947  	defer st.Lock()
  1948  
  1949  	// stop the services
  1950  	err = m.backend.StopServices(svcs, stopReason, pb, perfTimings)
  1951  	if err != nil {
  1952  		return err
  1953  	}
  1954  
  1955  	// get the disabled services after we stopped all the services.
  1956  	// this list is not meant to save what services are disabled at any given
  1957  	// time, specifically just what services are disabled while systemd loses
  1958  	// track of the services. this list is also used to determine what services are enabled
  1959  	// when we start services of a new revision of the snap in
  1960  	// start-snap-services handler.
  1961  	disabledServices, err := m.queryDisabledServices(currentInfo, pb)
  1962  	if err != nil {
  1963  		return err
  1964  	}
  1965  
  1966  	st.Lock()
  1967  	defer st.Unlock()
  1968  
  1969  	// for undo
  1970  	t.Set("old-last-active-disabled-services", snapst.LastActiveDisabledServices)
  1971  	// undo could queryDisabledServices, but this avoids it
  1972  	t.Set("disabled-services", disabledServices)
  1973  
  1974  	// add to the disabled services list in snapst services which were disabled
  1975  	// for usage across changes like in reverting and enabling after being
  1976  	// disabled.
  1977  	// we keep what's already in the list in snapst because that list is
  1978  	// services which were previously present in the snap and disabled, but are
  1979  	// no longer present.
  1980  	snapst.LastActiveDisabledServices = append(
  1981  		snapst.LastActiveDisabledServices,
  1982  		disabledServices...,
  1983  	)
  1984  
  1985  	// reset services tracked by operations from hooks
  1986  	snapst.ServicesDisabledByHooks = nil
  1987  	snapst.ServicesEnabledByHooks = nil
  1988  
  1989  	Set(st, snapsup.InstanceName(), snapst)
  1990  
  1991  	return nil
  1992  }
  1993  
  1994  func (m *SnapManager) undoStopSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1995  	st := t.State()
  1996  	st.Lock()
  1997  	defer st.Unlock()
  1998  
  1999  	perfTimings := state.TimingsForTask(t)
  2000  	defer perfTimings.Save(st)
  2001  
  2002  	snapsup, snapst, err := snapSetupAndState(t)
  2003  	if err != nil {
  2004  		return err
  2005  	}
  2006  	currentInfo, err := snapst.CurrentInfo()
  2007  	if err != nil {
  2008  		return err
  2009  	}
  2010  
  2011  	svcs := currentInfo.Services()
  2012  	if len(svcs) == 0 {
  2013  		return nil
  2014  	}
  2015  
  2016  	startupOrdered, err := snap.SortServices(svcs)
  2017  	if err != nil {
  2018  		return err
  2019  	}
  2020  
  2021  	var lastActiveDisabled []string
  2022  	if err := t.Get("old-last-active-disabled-services", &lastActiveDisabled); err != nil && err != state.ErrNoState {
  2023  		return err
  2024  	}
  2025  	snapst.LastActiveDisabledServices = lastActiveDisabled
  2026  	Set(st, snapsup.InstanceName(), snapst)
  2027  
  2028  	var disabledServices []string
  2029  	if err := t.Get("disabled-services", &disabledServices); err != nil && err != state.ErrNoState {
  2030  		return err
  2031  	}
  2032  
  2033  	st.Unlock()
  2034  	err = m.backend.StartServices(startupOrdered, disabledServices, progress.Null, perfTimings)
  2035  	st.Lock()
  2036  	if err != nil {
  2037  		return err
  2038  	}
  2039  
  2040  	return nil
  2041  }
  2042  
  2043  func (m *SnapManager) doUnlinkSnap(t *state.Task, _ *tomb.Tomb) error {
  2044  	// invoked only if snap has a current active revision, during remove or
  2045  	// disable
  2046  	// in case of the snapd snap, we only reach here if disabling or removal
  2047  	// was deemed ok by earlier checks
  2048  
  2049  	st := t.State()
  2050  	st.Lock()
  2051  	defer st.Unlock()
  2052  
  2053  	snapsup, snapst, err := snapSetupAndState(t)
  2054  	if err != nil {
  2055  		return err
  2056  	}
  2057  
  2058  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  2059  	if err != nil {
  2060  		return err
  2061  	}
  2062  
  2063  	// do the final unlink
  2064  	unlinkCtx := backend.LinkContext{
  2065  		FirstInstall: false,
  2066  	}
  2067  	err = m.backend.UnlinkSnap(info, unlinkCtx, NewTaskProgressAdapterLocked(t))
  2068  	if err != nil {
  2069  		return err
  2070  	}
  2071  
  2072  	// mark as inactive
  2073  	snapst.Active = false
  2074  	Set(st, snapsup.InstanceName(), snapst)
  2075  
  2076  	// Notify link snap participants about link changes.
  2077  	notifyLinkParticipants(t, snapsup.InstanceName())
  2078  
  2079  	return err
  2080  }
  2081  
  2082  func (m *SnapManager) undoUnlinkSnap(t *state.Task, _ *tomb.Tomb) error {
  2083  	st := t.State()
  2084  	st.Lock()
  2085  	defer st.Unlock()
  2086  
  2087  	perfTimings := state.TimingsForTask(t)
  2088  	defer perfTimings.Save(st)
  2089  
  2090  	snapsup, snapst, err := snapSetupAndState(t)
  2091  	if err != nil {
  2092  		return err
  2093  	}
  2094  
  2095  	isInstalled := snapst.IsInstalled()
  2096  	if !isInstalled {
  2097  		return fmt.Errorf("internal error: snap %q not installed anymore", snapsup.InstanceName())
  2098  	}
  2099  
  2100  	info, err := snapst.CurrentInfo()
  2101  	if err != nil {
  2102  		return err
  2103  	}
  2104  
  2105  	deviceCtx, err := DeviceCtx(st, t, nil)
  2106  	if err != nil {
  2107  		return err
  2108  	}
  2109  
  2110  	// undo here may be part of failed snap remove change, in which case a later
  2111  	// "clear-snap" task could have been executed and some or all of the
  2112  	// data of this snap could be lost. If that's the case, then we should not
  2113  	// enable the snap back.
  2114  	// XXX: should make an exception for snapd/core?
  2115  	place := snapsup.placeInfo()
  2116  	for _, dir := range []string{place.DataDir(), place.CommonDataDir()} {
  2117  		if exists, _, _ := osutil.DirExists(dir); !exists {
  2118  			t.Logf("cannot link snap %q back, some of its data has already been removed", snapsup.InstanceName())
  2119  			// TODO: mark the snap broken at the SnapState level when we have
  2120  			// such concept.
  2121  			return nil
  2122  		}
  2123  	}
  2124  
  2125  	snapst.Active = true
  2126  	Set(st, snapsup.InstanceName(), snapst)
  2127  
  2128  	opts, err := SnapServiceOptions(st, snapsup.InstanceName(), nil)
  2129  	if err != nil {
  2130  		return err
  2131  	}
  2132  	linkCtx := backend.LinkContext{
  2133  		FirstInstall:   false,
  2134  		ServiceOptions: opts,
  2135  	}
  2136  	reboot, err := m.backend.LinkSnap(info, deviceCtx, linkCtx, perfTimings)
  2137  	if err != nil {
  2138  		return err
  2139  	}
  2140  
  2141  	// Notify link snap participants about link changes.
  2142  	notifyLinkParticipants(t, snapsup.InstanceName())
  2143  
  2144  	// if we just linked back a core snap, request a restart
  2145  	// so that we switch executing its snapd.
  2146  	m.maybeRestart(t, info, reboot, deviceCtx)
  2147  
  2148  	return nil
  2149  }
  2150  
  2151  func (m *SnapManager) doClearSnapData(t *state.Task, _ *tomb.Tomb) error {
  2152  	st := t.State()
  2153  	st.Lock()
  2154  	snapsup, snapst, err := snapSetupAndState(t)
  2155  	st.Unlock()
  2156  	if err != nil {
  2157  		return err
  2158  	}
  2159  
  2160  	st.Lock()
  2161  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  2162  	st.Unlock()
  2163  	if err != nil {
  2164  		return err
  2165  	}
  2166  
  2167  	if err = m.backend.RemoveSnapData(info); err != nil {
  2168  		return err
  2169  	}
  2170  
  2171  	if len(snapst.Sequence) == 1 {
  2172  		// Only remove data common between versions if this is the last version
  2173  		if err = m.backend.RemoveSnapCommonData(info); err != nil {
  2174  			return err
  2175  		}
  2176  
  2177  		st.Lock()
  2178  		defer st.Unlock()
  2179  
  2180  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  2181  		if err != nil {
  2182  			return err
  2183  		}
  2184  		// Snap data directory can be removed now too
  2185  		if err := m.backend.RemoveSnapDataDir(info, otherInstances); err != nil {
  2186  			return err
  2187  		}
  2188  	}
  2189  
  2190  	return nil
  2191  }
  2192  
  2193  func (m *SnapManager) doDiscardSnap(t *state.Task, _ *tomb.Tomb) error {
  2194  	st := t.State()
  2195  	st.Lock()
  2196  	defer st.Unlock()
  2197  
  2198  	snapsup, snapst, err := snapSetupAndState(t)
  2199  	if err != nil {
  2200  		return err
  2201  	}
  2202  
  2203  	deviceCtx, err := DeviceCtx(st, t, nil)
  2204  	if err != nil {
  2205  		return err
  2206  	}
  2207  
  2208  	if snapst.Current == snapsup.Revision() && snapst.Active {
  2209  		return fmt.Errorf("internal error: cannot discard snap %q: still active", snapsup.InstanceName())
  2210  	}
  2211  
  2212  	if len(snapst.Sequence) == 1 {
  2213  		snapst.Sequence = nil
  2214  		snapst.Current = snap.Revision{}
  2215  	} else {
  2216  		newSeq := make([]*snap.SideInfo, 0, len(snapst.Sequence))
  2217  		for _, si := range snapst.Sequence {
  2218  			if si.Revision == snapsup.Revision() {
  2219  				// leave out
  2220  				continue
  2221  			}
  2222  			newSeq = append(newSeq, si)
  2223  		}
  2224  		snapst.Sequence = newSeq
  2225  		if snapst.Current == snapsup.Revision() {
  2226  			snapst.Current = newSeq[len(newSeq)-1].Revision
  2227  		}
  2228  	}
  2229  
  2230  	pb := NewTaskProgressAdapterLocked(t)
  2231  	typ, err := snapst.Type()
  2232  	if err != nil {
  2233  		return err
  2234  	}
  2235  	err = m.backend.RemoveSnapFiles(snapsup.placeInfo(), typ, nil, deviceCtx, pb)
  2236  	if err != nil {
  2237  		t.Errorf("cannot remove snap file %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  2238  		return &state.Retry{After: 3 * time.Minute}
  2239  	}
  2240  	if len(snapst.Sequence) == 0 {
  2241  		// Remove configuration associated with this snap.
  2242  		err = config.DeleteSnapConfig(st, snapsup.InstanceName())
  2243  		if err != nil {
  2244  			return err
  2245  		}
  2246  		err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  2247  		if err != nil {
  2248  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  2249  			return &state.Retry{After: 3 * time.Minute}
  2250  		}
  2251  		err = m.backend.RemoveSnapInhibitLock(snapsup.InstanceName())
  2252  		if err != nil {
  2253  			return err
  2254  		}
  2255  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  2256  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  2257  		}
  2258  
  2259  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  2260  		if err != nil {
  2261  			return err
  2262  		}
  2263  
  2264  		if err := m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances); err != nil {
  2265  			return fmt.Errorf("cannot remove snap directory: %v", err)
  2266  		}
  2267  
  2268  		// try to remove the auxiliary store info
  2269  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  2270  			logger.Noticef("Cannot remove auxiliary store info for %q: %v", snapsup.InstanceName(), err)
  2271  		}
  2272  
  2273  		// XXX: also remove sequence files?
  2274  
  2275  		// remove the snap from any quota groups it may have been in, otherwise
  2276  		// that quota group may get into an inconsistent state
  2277  		if err := EnsureSnapAbsentFromQuotaGroup(st, snapsup.InstanceName()); err != nil {
  2278  			return err
  2279  		}
  2280  	}
  2281  	if err = config.DiscardRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  2282  		return err
  2283  	}
  2284  	if err = SecurityProfilesRemoveLate(snapsup.InstanceName(), snapsup.Revision(), snapsup.Type); err != nil {
  2285  		return err
  2286  	}
  2287  	Set(st, snapsup.InstanceName(), snapst)
  2288  	return nil
  2289  }
  2290  
  2291  /* aliases v2
  2292  
  2293  aliases v2 implementation uses the following tasks:
  2294  
  2295    * for install/refresh/remove/enable/disable etc
  2296  
  2297      - remove-aliases: remove aliases of a snap from disk and mark them pending
  2298  
  2299      - setup-aliases: (re)creates aliases from snap state, mark them as
  2300        not pending
  2301  
  2302      - set-auto-aliases: updates aliases snap state based on the
  2303        snap-declaration and current revision info of the snap
  2304  
  2305    * for refresh & when the snap-declaration aliases change without a
  2306      new revision
  2307  
  2308      - refresh-aliases: updates aliases snap state and updates them on disk too;
  2309        its undo is used generically by other tasks as well
  2310  
  2311      - prune-auto-aliases: used for the special case of automatic
  2312        aliases transferred from one snap to another to prune them from
  2313        the source snaps to avoid conflicts in later operations
  2314  
  2315    * for alias/unalias/prefer:
  2316  
  2317      - alias: creates a manual alias
  2318  
  2319      - unalias: removes a manual alias
  2320  
  2321      - disable-aliases: disable the automatic aliases of a snap and
  2322        removes all manual ones as well
  2323  
  2324      - prefer-aliases: enables the automatic aliases of a snap after
  2325        disabling any other snap conflicting aliases
  2326  
  2327  */
  2328  
  2329  func (m *SnapManager) doSetAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  2330  	st := t.State()
  2331  	st.Lock()
  2332  	defer st.Unlock()
  2333  	snapsup, snapst, err := snapSetupAndState(t)
  2334  	if err != nil {
  2335  		return err
  2336  	}
  2337  	snapName := snapsup.InstanceName()
  2338  	curInfo, err := snapst.CurrentInfo()
  2339  	if err != nil {
  2340  		return err
  2341  	}
  2342  
  2343  	// --unaliased
  2344  	if snapsup.Unaliased {
  2345  		t.Set("old-auto-aliases-disabled", snapst.AutoAliasesDisabled)
  2346  		snapst.AutoAliasesDisabled = true
  2347  	}
  2348  
  2349  	curAliases := snapst.Aliases
  2350  	// TODO: implement --prefer logic
  2351  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  2352  	if err != nil {
  2353  		return err
  2354  	}
  2355  	_, err = checkAliasesConflicts(st, snapName, snapst.AutoAliasesDisabled, newAliases, nil)
  2356  	if err != nil {
  2357  		return err
  2358  	}
  2359  
  2360  	t.Set("old-aliases-v2", curAliases)
  2361  	// noop, except on first install where we need to set this here
  2362  	snapst.AliasesPending = true
  2363  	snapst.Aliases = newAliases
  2364  	Set(st, snapName, snapst)
  2365  	return nil
  2366  }
  2367  
  2368  func (m *SnapManager) doRemoveAliases(t *state.Task, _ *tomb.Tomb) error {
  2369  	st := t.State()
  2370  	st.Lock()
  2371  	defer st.Unlock()
  2372  	snapsup, snapst, err := snapSetupAndState(t)
  2373  	if err != nil {
  2374  		return err
  2375  	}
  2376  	snapName := snapsup.InstanceName()
  2377  
  2378  	err = m.backend.RemoveSnapAliases(snapName)
  2379  	if err != nil {
  2380  		return err
  2381  	}
  2382  
  2383  	snapst.AliasesPending = true
  2384  	Set(st, snapName, snapst)
  2385  	return nil
  2386  }
  2387  
  2388  func (m *SnapManager) doSetupAliases(t *state.Task, _ *tomb.Tomb) error {
  2389  	st := t.State()
  2390  	st.Lock()
  2391  	defer st.Unlock()
  2392  	snapsup, snapst, err := snapSetupAndState(t)
  2393  	if err != nil {
  2394  		return err
  2395  	}
  2396  	snapName := snapsup.InstanceName()
  2397  	curAliases := snapst.Aliases
  2398  
  2399  	_, _, err = applyAliasesChange(snapName, autoDis, nil, snapst.AutoAliasesDisabled, curAliases, m.backend, doApply)
  2400  	if err != nil {
  2401  		return err
  2402  	}
  2403  
  2404  	snapst.AliasesPending = false
  2405  	Set(st, snapName, snapst)
  2406  	return nil
  2407  }
  2408  
  2409  func (m *SnapManager) doRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  2410  	st := t.State()
  2411  	st.Lock()
  2412  	defer st.Unlock()
  2413  	snapsup, snapst, err := snapSetupAndState(t)
  2414  	if err != nil {
  2415  		return err
  2416  	}
  2417  	snapName := snapsup.InstanceName()
  2418  	curInfo, err := snapst.CurrentInfo()
  2419  	if err != nil {
  2420  		return err
  2421  	}
  2422  
  2423  	autoDisabled := snapst.AutoAliasesDisabled
  2424  	curAliases := snapst.Aliases
  2425  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  2426  	if err != nil {
  2427  		return err
  2428  	}
  2429  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  2430  	if err != nil {
  2431  		return err
  2432  	}
  2433  
  2434  	if !snapst.AliasesPending {
  2435  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  2436  			return err
  2437  		}
  2438  	}
  2439  
  2440  	t.Set("old-aliases-v2", curAliases)
  2441  	snapst.Aliases = newAliases
  2442  	Set(st, snapName, snapst)
  2443  	return nil
  2444  }
  2445  
  2446  func (m *SnapManager) undoRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  2447  	st := t.State()
  2448  	st.Lock()
  2449  	defer st.Unlock()
  2450  	var oldAliases map[string]*AliasTarget
  2451  	err := t.Get("old-aliases-v2", &oldAliases)
  2452  	if err == state.ErrNoState {
  2453  		// nothing to do
  2454  		return nil
  2455  	}
  2456  	if err != nil {
  2457  		return err
  2458  	}
  2459  	snapsup, snapst, err := snapSetupAndState(t)
  2460  	if err != nil {
  2461  		return err
  2462  	}
  2463  	snapName := snapsup.InstanceName()
  2464  	curAutoDisabled := snapst.AutoAliasesDisabled
  2465  	autoDisabled := curAutoDisabled
  2466  	if err = t.Get("old-auto-aliases-disabled", &autoDisabled); err != nil && err != state.ErrNoState {
  2467  		return err
  2468  	}
  2469  
  2470  	var otherSnapDisabled map[string]*otherDisabledAliases
  2471  	if err = t.Get("other-disabled-aliases", &otherSnapDisabled); err != nil && err != state.ErrNoState {
  2472  		return err
  2473  	}
  2474  
  2475  	// check if the old states creates conflicts now
  2476  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, oldAliases, nil)
  2477  	if _, ok := err.(*AliasConflictError); ok {
  2478  		// best we can do is reinstate with all aliases disabled
  2479  		t.Errorf("cannot reinstate alias state because of conflicts, disabling: %v", err)
  2480  		oldAliases, _ = disableAliases(oldAliases)
  2481  		autoDisabled = true
  2482  	} else if err != nil {
  2483  		return err
  2484  	}
  2485  
  2486  	if !snapst.AliasesPending {
  2487  		curAliases := snapst.Aliases
  2488  		if _, _, err := applyAliasesChange(snapName, curAutoDisabled, curAliases, autoDisabled, oldAliases, m.backend, doApply); err != nil {
  2489  			return err
  2490  		}
  2491  	}
  2492  
  2493  	snapst.AutoAliasesDisabled = autoDisabled
  2494  	snapst.Aliases = oldAliases
  2495  	newSnapStates := make(map[string]*SnapState, 1+len(otherSnapDisabled))
  2496  	newSnapStates[snapName] = snapst
  2497  
  2498  	// if we disabled other snap aliases try to undo that
  2499  	conflicting := make(map[string]bool, len(otherSnapDisabled))
  2500  	otherCurSnapStates := make(map[string]*SnapState, len(otherSnapDisabled))
  2501  	for otherSnap, otherDisabled := range otherSnapDisabled {
  2502  		var otherSnapState SnapState
  2503  		err := Get(st, otherSnap, &otherSnapState)
  2504  		if err != nil {
  2505  			return err
  2506  		}
  2507  		otherCurInfo, err := otherSnapState.CurrentInfo()
  2508  		if err != nil {
  2509  			return err
  2510  		}
  2511  
  2512  		otherCurSnapStates[otherSnap] = &otherSnapState
  2513  
  2514  		autoDisabled := otherSnapState.AutoAliasesDisabled
  2515  		if otherDisabled.Auto {
  2516  			// automatic aliases of other were disabled, undo that
  2517  			autoDisabled = false
  2518  		}
  2519  		otherAliases := reenableAliases(otherCurInfo, otherSnapState.Aliases, otherDisabled.Manual)
  2520  		// check for conflicts taking into account
  2521  		// re-enabled aliases
  2522  		conflicts, err := checkAliasesConflicts(st, otherSnap, autoDisabled, otherAliases, newSnapStates)
  2523  		if _, ok := err.(*AliasConflictError); ok {
  2524  			conflicting[otherSnap] = true
  2525  			for conflictSnap := range conflicts {
  2526  				conflicting[conflictSnap] = true
  2527  			}
  2528  		} else if err != nil {
  2529  			return err
  2530  		}
  2531  
  2532  		newSnapState := otherSnapState
  2533  		newSnapState.Aliases = otherAliases
  2534  		newSnapState.AutoAliasesDisabled = autoDisabled
  2535  		newSnapStates[otherSnap] = &newSnapState
  2536  	}
  2537  
  2538  	// apply non-conflicting other
  2539  	for otherSnap, otherSnapState := range otherCurSnapStates {
  2540  		if conflicting[otherSnap] {
  2541  			// keep as it was
  2542  			continue
  2543  		}
  2544  		newSnapSt := newSnapStates[otherSnap]
  2545  		if !otherSnapState.AliasesPending {
  2546  			if _, _, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, newSnapSt.AutoAliasesDisabled, newSnapSt.Aliases, m.backend, doApply); err != nil {
  2547  				return err
  2548  			}
  2549  		}
  2550  	}
  2551  
  2552  	for instanceName, snapst := range newSnapStates {
  2553  		if conflicting[instanceName] {
  2554  			// keep as it was
  2555  			continue
  2556  		}
  2557  		Set(st, instanceName, snapst)
  2558  	}
  2559  	return nil
  2560  }
  2561  
  2562  func (m *SnapManager) doPruneAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  2563  	st := t.State()
  2564  	st.Lock()
  2565  	defer st.Unlock()
  2566  	snapsup, snapst, err := snapSetupAndState(t)
  2567  	if err != nil {
  2568  		return err
  2569  	}
  2570  	var which []string
  2571  	err = t.Get("aliases", &which)
  2572  	if err != nil {
  2573  		return err
  2574  	}
  2575  	snapName := snapsup.InstanceName()
  2576  	autoDisabled := snapst.AutoAliasesDisabled
  2577  	curAliases := snapst.Aliases
  2578  
  2579  	newAliases := pruneAutoAliases(curAliases, which)
  2580  
  2581  	if !snapst.AliasesPending {
  2582  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  2583  			return err
  2584  		}
  2585  	}
  2586  
  2587  	t.Set("old-aliases-v2", curAliases)
  2588  	snapst.Aliases = newAliases
  2589  	Set(st, snapName, snapst)
  2590  	return nil
  2591  }
  2592  
  2593  type changedAlias struct {
  2594  	Snap  string `json:"snap"`
  2595  	App   string `json:"app"`
  2596  	Alias string `json:"alias"`
  2597  }
  2598  
  2599  func aliasesTrace(t *state.Task, added, removed []*backend.Alias) error {
  2600  	chg := t.Change()
  2601  	var data map[string]interface{}
  2602  	err := chg.Get("api-data", &data)
  2603  	if err != nil && err != state.ErrNoState {
  2604  		return err
  2605  	}
  2606  	if len(data) == 0 {
  2607  		data = make(map[string]interface{})
  2608  	}
  2609  
  2610  	curAdded, _ := data["aliases-added"].([]interface{})
  2611  	for _, a := range added {
  2612  		snap, app := snap.SplitSnapApp(a.Target)
  2613  		curAdded = append(curAdded, &changedAlias{
  2614  			Snap:  snap,
  2615  			App:   app,
  2616  			Alias: a.Name,
  2617  		})
  2618  	}
  2619  	data["aliases-added"] = curAdded
  2620  
  2621  	curRemoved, _ := data["aliases-removed"].([]interface{})
  2622  	for _, a := range removed {
  2623  		snap, app := snap.SplitSnapApp(a.Target)
  2624  		curRemoved = append(curRemoved, &changedAlias{
  2625  			Snap:  snap,
  2626  			App:   app,
  2627  			Alias: a.Name,
  2628  		})
  2629  	}
  2630  	data["aliases-removed"] = curRemoved
  2631  
  2632  	chg.Set("api-data", data)
  2633  	return nil
  2634  }
  2635  
  2636  func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error {
  2637  	st := t.State()
  2638  	st.Lock()
  2639  	defer st.Unlock()
  2640  	snapsup, snapst, err := snapSetupAndState(t)
  2641  	if err != nil {
  2642  		return err
  2643  	}
  2644  	var target, alias string
  2645  	err = t.Get("target", &target)
  2646  	if err != nil {
  2647  		return err
  2648  	}
  2649  	err = t.Get("alias", &alias)
  2650  	if err != nil {
  2651  		return err
  2652  	}
  2653  
  2654  	snapName := snapsup.InstanceName()
  2655  	curInfo, err := snapst.CurrentInfo()
  2656  	if err != nil {
  2657  		return err
  2658  	}
  2659  
  2660  	autoDisabled := snapst.AutoAliasesDisabled
  2661  	curAliases := snapst.Aliases
  2662  	newAliases, err := manualAlias(curInfo, curAliases, target, alias)
  2663  	if err != nil {
  2664  		return err
  2665  	}
  2666  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  2667  	if err != nil {
  2668  		return err
  2669  	}
  2670  
  2671  	added, removed, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2672  	if err != nil {
  2673  		return err
  2674  	}
  2675  	if err := aliasesTrace(t, added, removed); err != nil {
  2676  		return err
  2677  	}
  2678  
  2679  	t.Set("old-aliases-v2", curAliases)
  2680  	snapst.Aliases = newAliases
  2681  	Set(st, snapName, snapst)
  2682  	return nil
  2683  }
  2684  
  2685  func (m *SnapManager) doDisableAliases(t *state.Task, _ *tomb.Tomb) error {
  2686  	st := t.State()
  2687  	st.Lock()
  2688  	defer st.Unlock()
  2689  	snapsup, snapst, err := snapSetupAndState(t)
  2690  	if err != nil {
  2691  		return err
  2692  	}
  2693  	snapName := snapsup.InstanceName()
  2694  
  2695  	oldAutoDisabled := snapst.AutoAliasesDisabled
  2696  	oldAliases := snapst.Aliases
  2697  	newAliases, _ := disableAliases(oldAliases)
  2698  
  2699  	added, removed, err := applyAliasesChange(snapName, oldAutoDisabled, oldAliases, autoDis, newAliases, m.backend, snapst.AliasesPending)
  2700  	if err != nil {
  2701  		return err
  2702  	}
  2703  	if err := aliasesTrace(t, added, removed); err != nil {
  2704  		return err
  2705  	}
  2706  
  2707  	t.Set("old-auto-aliases-disabled", oldAutoDisabled)
  2708  	snapst.AutoAliasesDisabled = true
  2709  	t.Set("old-aliases-v2", oldAliases)
  2710  	snapst.Aliases = newAliases
  2711  	Set(st, snapName, snapst)
  2712  	return nil
  2713  }
  2714  
  2715  func (m *SnapManager) doUnalias(t *state.Task, _ *tomb.Tomb) error {
  2716  	st := t.State()
  2717  	st.Lock()
  2718  	defer st.Unlock()
  2719  	snapsup, snapst, err := snapSetupAndState(t)
  2720  	if err != nil {
  2721  		return err
  2722  	}
  2723  	var alias string
  2724  	err = t.Get("alias", &alias)
  2725  	if err != nil {
  2726  		return err
  2727  	}
  2728  	snapName := snapsup.InstanceName()
  2729  
  2730  	autoDisabled := snapst.AutoAliasesDisabled
  2731  	oldAliases := snapst.Aliases
  2732  	newAliases, err := manualUnalias(oldAliases, alias)
  2733  	if err != nil {
  2734  		return err
  2735  	}
  2736  
  2737  	added, removed, err := applyAliasesChange(snapName, autoDisabled, oldAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2738  	if err != nil {
  2739  		return err
  2740  	}
  2741  	if err := aliasesTrace(t, added, removed); err != nil {
  2742  		return err
  2743  	}
  2744  
  2745  	t.Set("old-aliases-v2", oldAliases)
  2746  	snapst.Aliases = newAliases
  2747  	Set(st, snapName, snapst)
  2748  	return nil
  2749  }
  2750  
  2751  // otherDisabledAliases is used to track for the benefit of undo what
  2752  // changes were made aka what aliases were disabled of another
  2753  // conflicting snap by prefer logic
  2754  type otherDisabledAliases struct {
  2755  	// Auto records whether prefer had to disable automatic aliases
  2756  	Auto bool `json:"auto,omitempty"`
  2757  	// Manual records which manual aliases were removed by prefer
  2758  	Manual map[string]string `json:"manual,omitempty"`
  2759  }
  2760  
  2761  func (m *SnapManager) doPreferAliases(t *state.Task, _ *tomb.Tomb) error {
  2762  	st := t.State()
  2763  	st.Lock()
  2764  	defer st.Unlock()
  2765  	snapsup, snapst, err := snapSetupAndState(t)
  2766  	if err != nil {
  2767  		return err
  2768  	}
  2769  	instanceName := snapsup.InstanceName()
  2770  
  2771  	if !snapst.AutoAliasesDisabled {
  2772  		// already enabled, nothing to do
  2773  		return nil
  2774  	}
  2775  
  2776  	curAliases := snapst.Aliases
  2777  	aliasConflicts, err := checkAliasesConflicts(st, instanceName, autoEn, curAliases, nil)
  2778  	conflErr, isConflErr := err.(*AliasConflictError)
  2779  	if err != nil && !isConflErr {
  2780  		return err
  2781  	}
  2782  	if isConflErr && conflErr.Conflicts == nil {
  2783  		// it's a snap command namespace conflict, we cannot remedy it
  2784  		return conflErr
  2785  	}
  2786  	// proceed to disable conflicting aliases as needed
  2787  	// before re-enabling instanceName aliases
  2788  
  2789  	otherSnapStates := make(map[string]*SnapState, len(aliasConflicts))
  2790  	otherSnapDisabled := make(map[string]*otherDisabledAliases, len(aliasConflicts))
  2791  	for otherSnap := range aliasConflicts {
  2792  		var otherSnapState SnapState
  2793  		err := Get(st, otherSnap, &otherSnapState)
  2794  		if err != nil {
  2795  			return err
  2796  		}
  2797  
  2798  		otherAliases, disabledManual := disableAliases(otherSnapState.Aliases)
  2799  
  2800  		added, removed, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, autoDis, otherAliases, m.backend, otherSnapState.AliasesPending)
  2801  		if err != nil {
  2802  			return err
  2803  		}
  2804  		if err := aliasesTrace(t, added, removed); err != nil {
  2805  			return err
  2806  		}
  2807  
  2808  		var otherDisabled otherDisabledAliases
  2809  		otherDisabled.Manual = disabledManual
  2810  		otherSnapState.Aliases = otherAliases
  2811  		// disable automatic aliases as needed
  2812  		if !otherSnapState.AutoAliasesDisabled && len(otherAliases) != 0 {
  2813  			// record that we did disable automatic aliases
  2814  			otherDisabled.Auto = true
  2815  			otherSnapState.AutoAliasesDisabled = true
  2816  		}
  2817  		otherSnapDisabled[otherSnap] = &otherDisabled
  2818  		otherSnapStates[otherSnap] = &otherSnapState
  2819  	}
  2820  
  2821  	added, removed, err := applyAliasesChange(instanceName, autoDis, curAliases, autoEn, curAliases, m.backend, snapst.AliasesPending)
  2822  	if err != nil {
  2823  		return err
  2824  	}
  2825  	if err := aliasesTrace(t, added, removed); err != nil {
  2826  		return err
  2827  	}
  2828  
  2829  	for otherSnap, otherSnapState := range otherSnapStates {
  2830  		Set(st, otherSnap, otherSnapState)
  2831  	}
  2832  	if len(otherSnapDisabled) != 0 {
  2833  		t.Set("other-disabled-aliases", otherSnapDisabled)
  2834  	}
  2835  	t.Set("old-auto-aliases-disabled", true)
  2836  	t.Set("old-aliases-v2", curAliases)
  2837  	snapst.AutoAliasesDisabled = false
  2838  	Set(st, instanceName, snapst)
  2839  	return nil
  2840  }
  2841  
  2842  // changeReadyUpToTask returns whether all other change's tasks are Ready.
  2843  func changeReadyUpToTask(task *state.Task) bool {
  2844  	me := task.ID()
  2845  	change := task.Change()
  2846  	for _, task := range change.Tasks() {
  2847  		if me == task.ID() {
  2848  			// ignore self
  2849  			continue
  2850  		}
  2851  		if !task.Status().Ready() {
  2852  			return false
  2853  		}
  2854  	}
  2855  	return true
  2856  }
  2857  
  2858  // refreshedSnaps returns the instance names of the snaps successfully refreshed
  2859  // in the last batch of refreshes before the given (re-refresh) task.
  2860  //
  2861  // It does this by advancing through the given task's change's tasks, keeping
  2862  // track of the instance names from the first SnapSetup in every lane, stopping
  2863  // when finding the given task, and resetting things when finding a different
  2864  // re-refresh task (that indicates the end of a batch that isn't the given one).
  2865  func refreshedSnaps(reTask *state.Task) []string {
  2866  	// NOTE nothing requires reTask to be a check-rerefresh task, nor even to be in
  2867  	// a refresh-ish change, but it doesn't make much sense to call this otherwise.
  2868  	tid := reTask.ID()
  2869  	laneSnaps := map[int]string{}
  2870  	// change.Tasks() preserves the order tasks were added, otherwise it all falls apart
  2871  	for _, task := range reTask.Change().Tasks() {
  2872  		if task.ID() == tid {
  2873  			// we've reached ourselves; we don't care about anything beyond this
  2874  			break
  2875  		}
  2876  		if task.Kind() == "check-rerefresh" {
  2877  			// we've reached a previous check-rerefresh (but not ourselves).
  2878  			// Only snaps in tasks after this point are of interest.
  2879  			laneSnaps = map[int]string{}
  2880  		}
  2881  		lanes := task.Lanes()
  2882  		if len(lanes) != 1 {
  2883  			// can't happen, really
  2884  			continue
  2885  		}
  2886  		lane := lanes[0]
  2887  		if lane == 0 {
  2888  			// not really a lane
  2889  			continue
  2890  		}
  2891  		if task.Status() != state.DoneStatus {
  2892  			// ignore non-successful lane (1)
  2893  			laneSnaps[lane] = ""
  2894  			continue
  2895  		}
  2896  		if _, ok := laneSnaps[lane]; ok {
  2897  			// ignore lanes we've already seen (including ones explicitly ignored in (1))
  2898  			continue
  2899  		}
  2900  		var snapsup SnapSetup
  2901  		if err := task.Get("snap-setup", &snapsup); err != nil {
  2902  			continue
  2903  		}
  2904  		laneSnaps[lane] = snapsup.InstanceName()
  2905  	}
  2906  
  2907  	snapNames := make([]string, 0, len(laneSnaps))
  2908  	for _, name := range laneSnaps {
  2909  		if name == "" {
  2910  			// the lane was unsuccessful
  2911  			continue
  2912  		}
  2913  		snapNames = append(snapNames, name)
  2914  	}
  2915  	return snapNames
  2916  }
  2917  
  2918  // reRefreshSetup holds the necessary details to re-refresh snaps that need it
  2919  type reRefreshSetup struct {
  2920  	UserID int `json:"user-id,omitempty"`
  2921  	*Flags
  2922  }
  2923  
  2924  // reRefreshUpdateMany exists just to make testing simpler
  2925  var reRefreshUpdateMany = updateManyFiltered
  2926  
  2927  // reRefreshFilter is an updateFilter that returns whether the given update
  2928  // needs a re-refresh because of further epoch transitions available.
  2929  func reRefreshFilter(update *snap.Info, snapst *SnapState) bool {
  2930  	cur, err := snapst.CurrentInfo()
  2931  	if err != nil {
  2932  		return false
  2933  	}
  2934  	return !update.Epoch.Equal(&cur.Epoch)
  2935  }
  2936  
  2937  var reRefreshRetryTimeout = time.Second / 2
  2938  
  2939  func (m *SnapManager) doCheckReRefresh(t *state.Task, tomb *tomb.Tomb) error {
  2940  	st := t.State()
  2941  	st.Lock()
  2942  	defer st.Unlock()
  2943  
  2944  	if numHaltTasks := t.NumHaltTasks(); numHaltTasks > 0 {
  2945  		logger.Panicf("Re-refresh task has %d tasks waiting for it.", numHaltTasks)
  2946  	}
  2947  
  2948  	if !changeReadyUpToTask(t) {
  2949  		return &state.Retry{After: reRefreshRetryTimeout, Reason: "pending refreshes"}
  2950  	}
  2951  	snaps := refreshedSnaps(t)
  2952  	if len(snaps) == 0 {
  2953  		// nothing to do (maybe everything failed)
  2954  		return nil
  2955  	}
  2956  
  2957  	var re reRefreshSetup
  2958  	if err := t.Get("rerefresh-setup", &re); err != nil {
  2959  		return err
  2960  	}
  2961  	chg := t.Change()
  2962  	updated, tasksets, err := reRefreshUpdateMany(tomb.Context(nil), st, snaps, re.UserID, reRefreshFilter, re.Flags, chg.ID())
  2963  	if err != nil {
  2964  		return err
  2965  	}
  2966  
  2967  	if len(updated) == 0 {
  2968  		t.Logf("No re-refreshes found.")
  2969  	} else {
  2970  		t.Logf("Found re-refresh for %s.", strutil.Quoted(updated))
  2971  
  2972  		for _, taskset := range tasksets {
  2973  			chg.AddAll(taskset)
  2974  		}
  2975  		st.EnsureBefore(0)
  2976  	}
  2977  	t.SetStatus(state.DoneStatus)
  2978  
  2979  	return nil
  2980  }
  2981  
  2982  func (m *SnapManager) doConditionalAutoRefresh(t *state.Task, tomb *tomb.Tomb) error {
  2983  	st := t.State()
  2984  	st.Lock()
  2985  	defer st.Unlock()
  2986  
  2987  	snaps, err := snapsToRefresh(t)
  2988  	if err != nil {
  2989  		return err
  2990  	}
  2991  
  2992  	if len(snaps) == 0 {
  2993  		logger.Debugf("refresh gating: no snaps to refresh")
  2994  		return nil
  2995  	}
  2996  
  2997  	tss, err := autoRefreshPhase2(context.TODO(), st, snaps)
  2998  	if err != nil {
  2999  		return err
  3000  	}
  3001  
  3002  	// update original auto-refresh change
  3003  	chg := t.Change()
  3004  	for _, ts := range tss {
  3005  		ts.WaitFor(t)
  3006  		chg.AddAll(ts)
  3007  	}
  3008  	t.SetStatus(state.DoneStatus)
  3009  
  3010  	st.EnsureBefore(0)
  3011  	return nil
  3012  }
  3013  
  3014  // InjectTasks makes all the halt tasks of the mainTask wait for extraTasks;
  3015  // extraTasks join the same lane and change as the mainTask.
  3016  func InjectTasks(mainTask *state.Task, extraTasks *state.TaskSet) {
  3017  	lanes := mainTask.Lanes()
  3018  	if len(lanes) == 1 && lanes[0] == 0 {
  3019  		lanes = nil
  3020  	}
  3021  	for _, l := range lanes {
  3022  		extraTasks.JoinLane(l)
  3023  	}
  3024  
  3025  	chg := mainTask.Change()
  3026  	// Change shouldn't normally be nil, except for cases where
  3027  	// this helper is used before tasks are added to a change.
  3028  	if chg != nil {
  3029  		chg.AddAll(extraTasks)
  3030  	}
  3031  
  3032  	// make all halt tasks of the mainTask wait on extraTasks
  3033  	ht := mainTask.HaltTasks()
  3034  	for _, t := range ht {
  3035  		t.WaitAll(extraTasks)
  3036  	}
  3037  
  3038  	// make the extra tasks wait for main task
  3039  	extraTasks.WaitFor(mainTask)
  3040  }
  3041  
  3042  func InjectAutoConnect(mainTask *state.Task, snapsup *SnapSetup) {
  3043  	st := mainTask.State()
  3044  	autoConnect := st.NewTask("auto-connect", fmt.Sprintf(i18n.G("Automatically connect eligible plugs and slots of snap %q"), snapsup.InstanceName()))
  3045  	autoConnect.Set("snap-setup", snapsup)
  3046  	InjectTasks(mainTask, state.NewTaskSet(autoConnect))
  3047  	mainTask.Logf("added auto-connect task")
  3048  }