github.com/freetocompute/snapd@v0.0.0-20210618182524-2fb355d72fd9/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  	oldLastRefreshTime := snapst.LastRefreshTime
  1203  	// only set userID if unset or logged out in snapst and if we
  1204  	// actually have an associated user
  1205  	if snapsup.UserID > 0 {
  1206  		var user *auth.UserState
  1207  		if snapst.UserID != 0 {
  1208  			user, err = auth.User(st, snapst.UserID)
  1209  			if err != nil && err != auth.ErrInvalidUser {
  1210  				return err
  1211  			}
  1212  		}
  1213  		if user == nil {
  1214  			// if the original user installing the snap is
  1215  			// no longer available transfer to user who
  1216  			// triggered this change
  1217  			snapst.UserID = snapsup.UserID
  1218  		}
  1219  	}
  1220  	// keep instance key
  1221  	snapst.InstanceKey = snapsup.InstanceKey
  1222  
  1223  	newInfo, err := readInfo(snapsup.InstanceName(), cand, 0)
  1224  	if err != nil {
  1225  		return err
  1226  	}
  1227  
  1228  	// record type
  1229  	snapst.SetType(newInfo.Type())
  1230  
  1231  	pb := NewTaskProgressAdapterLocked(t)
  1232  
  1233  	// Check for D-Bus service conflicts a second time to detect
  1234  	// conflicts within a transaction.
  1235  	if err := checkDBusServiceConflicts(st, newInfo); err != nil {
  1236  		return err
  1237  	}
  1238  
  1239  	opts, err := SnapServiceOptions(st, snapsup.InstanceName(), nil)
  1240  	if err != nil {
  1241  		return err
  1242  	}
  1243  	firstInstall := oldCurrent.Unset()
  1244  	linkCtx := backend.LinkContext{
  1245  		FirstInstall:   firstInstall,
  1246  		ServiceOptions: opts,
  1247  	}
  1248  	// on UC18+, snap tooling comes from the snapd snap so we need generated
  1249  	// mount units to depend on the snapd snap mount units
  1250  	if !deviceCtx.Classic() && deviceCtx.Model().Base() != "" {
  1251  		linkCtx.RequireMountedSnapdSnap = true
  1252  	}
  1253  	reboot, err := m.backend.LinkSnap(newInfo, deviceCtx, linkCtx, perfTimings)
  1254  	// defer a cleanup helper which will unlink the snap if anything fails after
  1255  	// this point
  1256  	defer func() {
  1257  		if err == nil {
  1258  			return
  1259  		}
  1260  		// err is not nil, we need to try and unlink the snap to cleanup after
  1261  		// ourselves
  1262  		var backendErr error
  1263  		if newInfo.Type() == snap.TypeSnapd && !firstInstall {
  1264  			// snapd snap is special in the sense that we always
  1265  			// need the current symlink, so we restore the link to
  1266  			// the old revision
  1267  			_, backendErr = m.backend.LinkSnap(oldInfo, deviceCtx, linkCtx, perfTimings)
  1268  		} else {
  1269  			// snapd during first install and all other snaps
  1270  			backendErr = m.backend.UnlinkSnap(newInfo, linkCtx, pb)
  1271  		}
  1272  		if backendErr != nil {
  1273  			t.Errorf("cannot cleanup failed attempt at making snap %q available to the system: %v", snapsup.InstanceName(), backendErr)
  1274  		}
  1275  		notifyLinkParticipants(t, snapsup.InstanceName())
  1276  	}()
  1277  	if err != nil {
  1278  		return err
  1279  	}
  1280  
  1281  	// Restore configuration of the target revision (if available) on revert
  1282  	if isInstalled {
  1283  		// Make a copy of configuration of current snap revision
  1284  		if err = config.SaveRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1285  			return err
  1286  		}
  1287  	}
  1288  
  1289  	// Restore configuration of the target revision (if available; nothing happens if it's not).
  1290  	// We only do this on reverts (and not on refreshes).
  1291  	if snapsup.Revert {
  1292  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  1293  			return err
  1294  		}
  1295  	}
  1296  
  1297  	if len(snapst.Sequence) == 1 {
  1298  		if err := m.createSnapCookie(st, snapsup.InstanceName()); err != nil {
  1299  			return fmt.Errorf("cannot create snap cookie: %v", err)
  1300  		}
  1301  	}
  1302  
  1303  	// save for undoLinkSnap
  1304  	t.Set("old-trymode", oldTryMode)
  1305  	t.Set("old-devmode", oldDevMode)
  1306  	t.Set("old-jailmode", oldJailMode)
  1307  	t.Set("old-classic", oldClassic)
  1308  	t.Set("old-ignore-validation", oldIgnoreValidation)
  1309  	t.Set("old-channel", oldChannel)
  1310  	t.Set("old-current", oldCurrent)
  1311  	t.Set("old-candidate-index", oldCandidateIndex)
  1312  	t.Set("old-refresh-inhibited-time", oldRefreshInhibitedTime)
  1313  	t.Set("old-cohort-key", oldCohortKey)
  1314  	t.Set("old-last-refresh-time", oldLastRefreshTime)
  1315  
  1316  	// Record the fact that the snap was refreshed successfully.
  1317  	snapst.RefreshInhibitedTime = nil
  1318  	if !snapsup.Revert {
  1319  		now := timeNow()
  1320  		snapst.LastRefreshTime = &now
  1321  	}
  1322  
  1323  	if cand.SnapID != "" {
  1324  		// write the auxiliary store info
  1325  		aux := &auxStoreInfo{
  1326  			Media:   snapsup.Media,
  1327  			Website: snapsup.Website,
  1328  		}
  1329  		if err := keepAuxStoreInfo(cand.SnapID, aux); err != nil {
  1330  			return err
  1331  		}
  1332  		if len(snapst.Sequence) == 1 {
  1333  			defer func() {
  1334  				if err != nil {
  1335  					// the install is getting undone, and there are no more of this snap
  1336  					// try to remove the aux info we just created
  1337  					discardAuxStoreInfo(cand.SnapID)
  1338  				}
  1339  			}()
  1340  		}
  1341  	}
  1342  
  1343  	// write sequence file for failover helpers
  1344  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1345  		return err
  1346  	}
  1347  
  1348  	// Compatibility with old snapd: check if we have auto-connect task and
  1349  	// if not, inject it after self (link-snap) for snaps that are not core
  1350  	if newInfo.Type() != snap.TypeOS {
  1351  		var hasAutoConnect, hasSetupProfiles bool
  1352  		for _, other := range t.Change().Tasks() {
  1353  			// Check if this is auto-connect task for same snap and we it's part of the change with setup-profiles task
  1354  			if other.Kind() == "auto-connect" || other.Kind() == "setup-profiles" {
  1355  				otherSnapsup, err := TaskSnapSetup(other)
  1356  				if err != nil {
  1357  					return err
  1358  				}
  1359  				if snapsup.InstanceName() == otherSnapsup.InstanceName() {
  1360  					if other.Kind() == "auto-connect" {
  1361  						hasAutoConnect = true
  1362  					} else {
  1363  						hasSetupProfiles = true
  1364  					}
  1365  				}
  1366  			}
  1367  		}
  1368  		if !hasAutoConnect && hasSetupProfiles {
  1369  			InjectAutoConnect(t, snapsup)
  1370  		}
  1371  	}
  1372  
  1373  	// Do at the end so we only preserve the new state if it worked.
  1374  	Set(st, snapsup.InstanceName(), snapst)
  1375  
  1376  	// Notify link snap participants about link changes.
  1377  	notifyLinkParticipants(t, snapsup.InstanceName())
  1378  
  1379  	// Make sure if state commits and snapst is mutated we won't be rerun
  1380  	t.SetStatus(state.DoneStatus)
  1381  
  1382  	// if we just installed a core snap, request a restart
  1383  	// so that we switch executing its snapd.
  1384  	m.maybeRestart(t, newInfo, reboot, deviceCtx)
  1385  
  1386  	return nil
  1387  }
  1388  
  1389  // maybeRestart will schedule a reboot or restart as needed for the
  1390  // just linked snap with info if it's a core or snapd or kernel snap.
  1391  func (m *SnapManager) maybeRestart(t *state.Task, info *snap.Info, rebootRequired bool, deviceCtx DeviceContext) {
  1392  	// Don't restart when preseeding - we will switch to new snapd on
  1393  	// first boot.
  1394  	if m.preseed {
  1395  		return
  1396  	}
  1397  
  1398  	st := t.State()
  1399  
  1400  	if rebootRequired {
  1401  		t.Logf("Requested system restart.")
  1402  		st.RequestRestart(state.RestartSystem)
  1403  		return
  1404  	}
  1405  
  1406  	typ := info.Type()
  1407  
  1408  	// if bp is non-trivial then either we're not on classic, or the snap is
  1409  	// snapd. So daemonRestartReason will always return "" which is what we
  1410  	// want. If that combination stops being true and there's a situation
  1411  	// where a non-trivial bp could return a non-empty reason, use IsTrivial
  1412  	// to check and bail before reaching this far.
  1413  
  1414  	restartReason := daemonRestartReason(st, typ)
  1415  	if restartReason == "" {
  1416  		// no message -> no restart
  1417  		return
  1418  	}
  1419  
  1420  	t.Logf(restartReason)
  1421  	st.RequestRestart(state.RestartDaemon)
  1422  }
  1423  
  1424  func daemonRestartReason(st *state.State, typ snap.Type) string {
  1425  	if !((release.OnClassic && typ == snap.TypeOS) || typ == snap.TypeSnapd) {
  1426  		// not interesting
  1427  		return ""
  1428  	}
  1429  
  1430  	if typ == snap.TypeOS {
  1431  		// ignore error here as we have no way to return to caller
  1432  		snapdSnapInstalled, _ := isInstalled(st, "snapd")
  1433  		if snapdSnapInstalled {
  1434  			// this snap is the base, but snapd is running from the snapd snap
  1435  			return ""
  1436  		}
  1437  		return "Requested daemon restart."
  1438  	}
  1439  
  1440  	return "Requested daemon restart (snapd snap)."
  1441  }
  1442  
  1443  // maybeUndoRemodelBootChanges will check if an undo needs to update the
  1444  // bootloader. This can happen if e.g. a new kernel gets installed. This
  1445  // will switch the bootloader to the new kernel but if the change is later
  1446  // undone we need to switch back to the kernel of the old model.
  1447  func (m *SnapManager) maybeUndoRemodelBootChanges(t *state.Task) error {
  1448  	// get the new and the old model
  1449  	deviceCtx, err := DeviceCtx(t.State(), t, nil)
  1450  	if err != nil {
  1451  		return err
  1452  	}
  1453  	// we only have an old model if we are in a remodel situation
  1454  	if !deviceCtx.ForRemodeling() {
  1455  		return nil
  1456  	}
  1457  	groundDeviceCtx := deviceCtx.GroundContext()
  1458  	oldModel := groundDeviceCtx.Model()
  1459  	newModel := deviceCtx.Model()
  1460  
  1461  	// check type of the snap we are undoing, only kernel/base/core are
  1462  	// relevant
  1463  	snapsup, _, err := snapSetupAndState(t)
  1464  	if err != nil {
  1465  		return err
  1466  	}
  1467  	var newSnapName, snapName string
  1468  	switch snapsup.Type {
  1469  	case snap.TypeKernel:
  1470  		snapName = oldModel.Kernel()
  1471  		newSnapName = newModel.Kernel()
  1472  	case snap.TypeOS, snap.TypeBase:
  1473  		// XXX: add support for "core"
  1474  		snapName = oldModel.Base()
  1475  		newSnapName = newModel.Base()
  1476  	default:
  1477  		return nil
  1478  	}
  1479  	// we can stop if the kernel/base has not changed
  1480  	if snapName == newSnapName {
  1481  		return nil
  1482  	}
  1483  	// we can stop if the snap we are looking at is not a kernel/base
  1484  	// of the new model
  1485  	if snapsup.InstanceName() != newSnapName {
  1486  		return nil
  1487  	}
  1488  	// get info for *old* kernel/base/core and see if we need to reboot
  1489  	// TODO: we may need something like infoForDeviceSnap here
  1490  	var snapst SnapState
  1491  	if err = Get(t.State(), snapName, &snapst); err != nil {
  1492  		return err
  1493  	}
  1494  	info, err := snapst.CurrentInfo()
  1495  	if err != nil && err != ErrNoCurrent {
  1496  		return err
  1497  	}
  1498  	bp := boot.Participant(info, info.Type(), groundDeviceCtx)
  1499  	reboot, err := bp.SetNextBoot()
  1500  	if err != nil {
  1501  		return err
  1502  	}
  1503  
  1504  	// we may just have switch back to the old kernel/base/core so
  1505  	// we may need to restart
  1506  	m.maybeRestart(t, info, reboot, groundDeviceCtx)
  1507  
  1508  	return nil
  1509  }
  1510  
  1511  func (m *SnapManager) undoLinkSnap(t *state.Task, _ *tomb.Tomb) error {
  1512  	st := t.State()
  1513  	st.Lock()
  1514  	defer st.Unlock()
  1515  
  1516  	deviceCtx, err := DeviceCtx(st, t, nil)
  1517  	if err != nil {
  1518  		return err
  1519  	}
  1520  
  1521  	perfTimings := state.TimingsForTask(t)
  1522  	defer perfTimings.Save(st)
  1523  
  1524  	snapsup, snapst, err := snapSetupAndState(t)
  1525  	if err != nil {
  1526  		return err
  1527  	}
  1528  
  1529  	var oldChannel string
  1530  	err = t.Get("old-channel", &oldChannel)
  1531  	if err != nil {
  1532  		return err
  1533  	}
  1534  	var oldIgnoreValidation bool
  1535  	err = t.Get("old-ignore-validation", &oldIgnoreValidation)
  1536  	if err != nil && err != state.ErrNoState {
  1537  		return err
  1538  	}
  1539  	var oldTryMode bool
  1540  	err = t.Get("old-trymode", &oldTryMode)
  1541  	if err != nil {
  1542  		return err
  1543  	}
  1544  	var oldDevMode bool
  1545  	err = t.Get("old-devmode", &oldDevMode)
  1546  	if err != nil {
  1547  		return err
  1548  	}
  1549  	var oldJailMode bool
  1550  	err = t.Get("old-jailmode", &oldJailMode)
  1551  	if err != nil {
  1552  		return err
  1553  	}
  1554  	var oldClassic bool
  1555  	err = t.Get("old-classic", &oldClassic)
  1556  	if err != nil {
  1557  		return err
  1558  	}
  1559  	var oldCurrent snap.Revision
  1560  	err = t.Get("old-current", &oldCurrent)
  1561  	if err != nil {
  1562  		return err
  1563  	}
  1564  	var oldCandidateIndex int
  1565  	if err := t.Get("old-candidate-index", &oldCandidateIndex); err != nil {
  1566  		return err
  1567  	}
  1568  	var oldRefreshInhibitedTime *time.Time
  1569  	if err := t.Get("old-refresh-inhibited-time", &oldRefreshInhibitedTime); err != nil && err != state.ErrNoState {
  1570  		return err
  1571  	}
  1572  	var oldLastRefreshTime *time.Time
  1573  	if err := t.Get("old-last-refresh-time", &oldLastRefreshTime); err != nil && err != state.ErrNoState {
  1574  		return err
  1575  	}
  1576  	var oldCohortKey string
  1577  	if err := t.Get("old-cohort-key", &oldCohortKey); err != nil && err != state.ErrNoState {
  1578  		return err
  1579  	}
  1580  
  1581  	if len(snapst.Sequence) == 1 {
  1582  		// XXX: shouldn't these two just log and carry on? this is an undo handler...
  1583  		timings.Run(perfTimings, "discard-snap-namespace", fmt.Sprintf("discard the namespace of snap %q", snapsup.InstanceName()), func(tm timings.Measurer) {
  1584  			err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  1585  		})
  1586  		if err != nil {
  1587  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  1588  			return &state.Retry{After: 3 * time.Minute}
  1589  		}
  1590  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  1591  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  1592  		}
  1593  		// try to remove the auxiliary store info
  1594  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  1595  			return fmt.Errorf("cannot remove auxiliary store info: %v", err)
  1596  		}
  1597  	}
  1598  
  1599  	isRevert := snapsup.Revert
  1600  
  1601  	// relinking of the old snap is done in the undo of unlink-current-snap
  1602  	currentIndex := snapst.LastIndex(snapst.Current)
  1603  	if currentIndex < 0 {
  1604  		return fmt.Errorf("internal error: cannot find revision %d in %v for undoing the added revision", snapsup.SideInfo.Revision, snapst.Sequence)
  1605  	}
  1606  
  1607  	if oldCandidateIndex < 0 {
  1608  		snapst.Sequence = append(snapst.Sequence[:currentIndex], snapst.Sequence[currentIndex+1:]...)
  1609  	} else if !isRevert {
  1610  		oldCand := snapst.Sequence[currentIndex]
  1611  		copy(snapst.Sequence[oldCandidateIndex+1:], snapst.Sequence[oldCandidateIndex:])
  1612  		snapst.Sequence[oldCandidateIndex] = oldCand
  1613  	}
  1614  	snapst.Current = oldCurrent
  1615  	snapst.Active = false
  1616  	snapst.TrackingChannel = oldChannel
  1617  	snapst.IgnoreValidation = oldIgnoreValidation
  1618  	snapst.TryMode = oldTryMode
  1619  	snapst.DevMode = oldDevMode
  1620  	snapst.JailMode = oldJailMode
  1621  	snapst.Classic = oldClassic
  1622  	snapst.RefreshInhibitedTime = oldRefreshInhibitedTime
  1623  	snapst.LastRefreshTime = oldLastRefreshTime
  1624  	snapst.CohortKey = oldCohortKey
  1625  
  1626  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
  1627  	if err != nil {
  1628  		return err
  1629  	}
  1630  
  1631  	// we need to undo potential changes to current snap configuration (e.g. if
  1632  	// modified by post-refresh/install/configure hooks as part of failed
  1633  	// refresh/install) by restoring the configuration of "old current".
  1634  	// similarly, we need to re-save the disabled services if there is a
  1635  	// revision for us to go back to, see comment below for full explanation
  1636  	if len(snapst.Sequence) > 0 {
  1637  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1638  			return err
  1639  		}
  1640  	} else {
  1641  		// in the case of an install we need to clear any config
  1642  		err = config.DeleteSnapConfig(st, snapsup.InstanceName())
  1643  		if err != nil {
  1644  			return err
  1645  		}
  1646  	}
  1647  
  1648  	pb := NewTaskProgressAdapterLocked(t)
  1649  	firstInstall := oldCurrent.Unset()
  1650  	linkCtx := backend.LinkContext{
  1651  		FirstInstall: firstInstall,
  1652  	}
  1653  	var backendErr error
  1654  	if newInfo.Type() == snap.TypeSnapd && !firstInstall {
  1655  		// snapst has been updated and now is the old revision, since
  1656  		// this is not the first install of snapd, it should exist
  1657  		var oldInfo *snap.Info
  1658  		oldInfo, err := snapst.CurrentInfo()
  1659  		if err != nil {
  1660  			return err
  1661  		}
  1662  		// the snapd snap is special in the sense that we need to make
  1663  		// sure that a sensible version is always linked as current,
  1664  		// also we never reboot when updating snapd snap
  1665  		_, backendErr = m.backend.LinkSnap(oldInfo, deviceCtx, linkCtx, perfTimings)
  1666  	} else {
  1667  		// snapd during first install and all other snaps
  1668  		backendErr = m.backend.UnlinkSnap(newInfo, linkCtx, pb)
  1669  	}
  1670  	if backendErr != nil {
  1671  		return backendErr
  1672  	}
  1673  
  1674  	if err := m.maybeUndoRemodelBootChanges(t); err != nil {
  1675  		return err
  1676  	}
  1677  
  1678  	// restart only when snapd was installed for the first time and the rest of
  1679  	// the cleanup is performed by snapd from core;
  1680  	// when reverting a subsequent snapd revision, the restart happens in
  1681  	// undoLinkCurrentSnap() instead
  1682  	if firstInstall && newInfo.Type() == snap.TypeSnapd {
  1683  		const rebootRequired = false
  1684  		m.maybeRestart(t, newInfo, rebootRequired, deviceCtx)
  1685  	}
  1686  
  1687  	// write sequence file for failover helpers
  1688  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1689  		return err
  1690  	}
  1691  	// mark as inactive
  1692  	Set(st, snapsup.InstanceName(), snapst)
  1693  
  1694  	// Notify link snap participants about link changes.
  1695  	notifyLinkParticipants(t, snapsup.InstanceName())
  1696  
  1697  	// Make sure if state commits and snapst is mutated we won't be rerun
  1698  	t.SetStatus(state.UndoneStatus)
  1699  
  1700  	// If we are on classic and have no previous version of core
  1701  	// we may have restarted from a distro package into the core
  1702  	// snap. We need to undo that restart here. Instead of in
  1703  	// doUnlinkCurrentSnap() like we usually do when going from
  1704  	// core snap -> next core snap
  1705  	if release.OnClassic && newInfo.Type() == snap.TypeOS && oldCurrent.Unset() {
  1706  		t.Logf("Requested daemon restart (undo classic initial core install)")
  1707  		st.RequestRestart(state.RestartDaemon)
  1708  	}
  1709  	return nil
  1710  }
  1711  
  1712  type doSwitchFlags struct {
  1713  	switchCurrentChannel bool
  1714  }
  1715  
  1716  // doSwitchSnapChannel switches the snap's tracking channel and/or cohort. It
  1717  // also switches the current channel if appropriate. For use from 'Update'.
  1718  func (m *SnapManager) doSwitchSnapChannel(t *state.Task, _ *tomb.Tomb) error {
  1719  	return m.genericDoSwitchSnap(t, doSwitchFlags{switchCurrentChannel: true})
  1720  }
  1721  
  1722  // doSwitchSnap switches the snap's tracking channel and/or cohort, *without*
  1723  // switching the current snap channel. For use from 'Switch'.
  1724  func (m *SnapManager) doSwitchSnap(t *state.Task, _ *tomb.Tomb) error {
  1725  	return m.genericDoSwitchSnap(t, doSwitchFlags{})
  1726  }
  1727  
  1728  func (m *SnapManager) genericDoSwitchSnap(t *state.Task, flags doSwitchFlags) error {
  1729  	st := t.State()
  1730  	st.Lock()
  1731  	defer st.Unlock()
  1732  
  1733  	snapsup, snapst, err := snapSetupAndState(t)
  1734  	if err != nil {
  1735  		return err
  1736  	}
  1737  
  1738  	// switched the tracked channel
  1739  	if err := snapst.SetTrackingChannel(snapsup.Channel); err != nil {
  1740  		return err
  1741  	}
  1742  	snapst.CohortKey = snapsup.CohortKey
  1743  	if flags.switchCurrentChannel {
  1744  		// optionally support switching the current snap channel too, e.g.
  1745  		// if a snap is in both stable and candidate with the same revision
  1746  		// we can update it here and it will be displayed correctly in the UI
  1747  		if snapsup.SideInfo.Channel != "" {
  1748  			snapst.CurrentSideInfo().Channel = snapsup.Channel
  1749  		}
  1750  	}
  1751  
  1752  	Set(st, snapsup.InstanceName(), snapst)
  1753  	return nil
  1754  }
  1755  
  1756  func (m *SnapManager) doToggleSnapFlags(t *state.Task, _ *tomb.Tomb) error {
  1757  	st := t.State()
  1758  	st.Lock()
  1759  	defer st.Unlock()
  1760  
  1761  	snapsup, snapst, err := snapSetupAndState(t)
  1762  	if err != nil {
  1763  		return err
  1764  	}
  1765  
  1766  	// for now we support toggling only ignore-validation
  1767  	snapst.IgnoreValidation = snapsup.IgnoreValidation
  1768  
  1769  	Set(st, snapsup.InstanceName(), snapst)
  1770  	return nil
  1771  }
  1772  
  1773  // installModeDisabledServices returns what services with
  1774  // "install-mode: disabled" should be disabled. Only services
  1775  // seen for the first time are considered.
  1776  func installModeDisabledServices(st *state.State, snapst *SnapState, currentInfo *snap.Info) (svcsToDisable []string, err error) {
  1777  	enabledByHookSvcs := map[string]bool{}
  1778  	for _, svcName := range snapst.ServicesEnabledByHooks {
  1779  		enabledByHookSvcs[svcName] = true
  1780  	}
  1781  
  1782  	// find what servies the previous snap had
  1783  	prevCurrentSvcs := map[string]bool{}
  1784  	if psi := snapst.previousSideInfo(); psi != nil {
  1785  		var prevCurrentInfo *snap.Info
  1786  		if prevCurrentInfo, err = Info(st, snapst.InstanceName(), psi.Revision); prevCurrentInfo != nil {
  1787  			for _, prevSvc := range prevCurrentInfo.Services() {
  1788  				prevCurrentSvcs[prevSvc.Name] = true
  1789  			}
  1790  		}
  1791  	}
  1792  	// and deal with "install-mode: disable" for all new services
  1793  	// (i.e. not present in previous snap).
  1794  	//
  1795  	// Services that are not new but have "install-mode: disable"
  1796  	// do not need special handling. They are either still disabled
  1797  	// or something has enabled them and then they should stay enabled.
  1798  	for _, svc := range currentInfo.Services() {
  1799  		if svc.InstallMode == "disable" && !enabledByHookSvcs[svc.Name] {
  1800  			if !prevCurrentSvcs[svc.Name] {
  1801  				svcsToDisable = append(svcsToDisable, svc.Name)
  1802  			}
  1803  		}
  1804  	}
  1805  	return svcsToDisable, nil
  1806  }
  1807  
  1808  func (m *SnapManager) startSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1809  	st := t.State()
  1810  	st.Lock()
  1811  	defer st.Unlock()
  1812  
  1813  	perfTimings := state.TimingsForTask(t)
  1814  	defer perfTimings.Save(st)
  1815  
  1816  	snapsup, snapst, err := snapSetupAndState(t)
  1817  	if err != nil {
  1818  		return err
  1819  	}
  1820  	currentInfo, err := snapst.CurrentInfo()
  1821  	if err != nil {
  1822  		return err
  1823  	}
  1824  
  1825  	// check if any previously disabled services are now no longer services and
  1826  	// log messages about that
  1827  	for _, svc := range snapst.LastActiveDisabledServices {
  1828  		app, ok := currentInfo.Apps[svc]
  1829  		if !ok {
  1830  			logger.Noticef("previously disabled service %s no longer exists", svc)
  1831  		} else if !app.IsService() {
  1832  			logger.Noticef("previously disabled service %s is now an app and not a service", svc)
  1833  		}
  1834  	}
  1835  
  1836  	// get the services which should be disabled (not started),
  1837  	// as well as the services which are not present in this revision, but were
  1838  	// present and disabled in a previous one and as such should be kept inside
  1839  	// snapst for persistent storage
  1840  	svcsToDisable, svcsToSave, err := missingDisabledServices(snapst.LastActiveDisabledServices, currentInfo)
  1841  	if err != nil {
  1842  		return err
  1843  	}
  1844  
  1845  	// check what services with "InstallMode: disable" need to be disabled
  1846  	svcsToDisableFromInstallMode, err := installModeDisabledServices(st, snapst, currentInfo)
  1847  	if err != nil {
  1848  		return err
  1849  	}
  1850  	svcsToDisable = append(svcsToDisable, svcsToDisableFromInstallMode...)
  1851  
  1852  	// append services that were disabled by hooks (they should not get re-enabled)
  1853  	svcsToDisable = append(svcsToDisable, snapst.ServicesDisabledByHooks...)
  1854  
  1855  	// save the current last-active-disabled-services before we re-write it in case we
  1856  	// need to undo this
  1857  	t.Set("old-last-active-disabled-services", snapst.LastActiveDisabledServices)
  1858  
  1859  	// commit the missing services to state so when we unlink this revision and
  1860  	// go to a different revision with potentially different service names, the
  1861  	// currently missing service names will be re-disabled if they exist later
  1862  	snapst.LastActiveDisabledServices = svcsToSave
  1863  
  1864  	// reset services tracked by operations from hooks
  1865  	snapst.ServicesDisabledByHooks = nil
  1866  	snapst.ServicesEnabledByHooks = nil
  1867  	Set(st, snapsup.InstanceName(), snapst)
  1868  
  1869  	svcs := currentInfo.Services()
  1870  	if len(svcs) == 0 {
  1871  		return nil
  1872  	}
  1873  
  1874  	startupOrdered, err := snap.SortServices(svcs)
  1875  	if err != nil {
  1876  		return err
  1877  	}
  1878  
  1879  	pb := NewTaskProgressAdapterUnlocked(t)
  1880  
  1881  	st.Unlock()
  1882  	err = m.backend.StartServices(startupOrdered, svcsToDisable, pb, perfTimings)
  1883  	st.Lock()
  1884  
  1885  	return err
  1886  }
  1887  
  1888  func (m *SnapManager) undoStartSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1889  	st := t.State()
  1890  	st.Lock()
  1891  	defer st.Unlock()
  1892  
  1893  	perfTimings := state.TimingsForTask(t)
  1894  	defer perfTimings.Save(st)
  1895  
  1896  	snapsup, snapst, err := snapSetupAndState(t)
  1897  	if err != nil {
  1898  		return err
  1899  	}
  1900  
  1901  	currentInfo, err := snapst.CurrentInfo()
  1902  	if err != nil {
  1903  		return err
  1904  	}
  1905  
  1906  	var oldLastActiveDisabledServices []string
  1907  	if err := t.Get("old-last-active-disabled-services", &oldLastActiveDisabledServices); err != nil && err != state.ErrNoState {
  1908  		return err
  1909  	}
  1910  	snapst.LastActiveDisabledServices = oldLastActiveDisabledServices
  1911  	Set(st, snapsup.InstanceName(), snapst)
  1912  
  1913  	svcs := currentInfo.Services()
  1914  	if len(svcs) == 0 {
  1915  		return nil
  1916  	}
  1917  
  1918  	// XXX: stop reason not set on start task, should we have a new reason for undo?
  1919  	var stopReason snap.ServiceStopReason
  1920  
  1921  	// stop the services
  1922  	st.Unlock()
  1923  	err = m.backend.StopServices(svcs, stopReason, progress.Null, perfTimings)
  1924  	st.Lock()
  1925  	if err != nil {
  1926  		return err
  1927  	}
  1928  
  1929  	return nil
  1930  }
  1931  
  1932  func (m *SnapManager) stopSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1933  	st := t.State()
  1934  	st.Lock()
  1935  	defer st.Unlock()
  1936  
  1937  	perfTimings := state.TimingsForTask(t)
  1938  	defer perfTimings.Save(st)
  1939  
  1940  	snapsup, snapst, err := snapSetupAndState(t)
  1941  	if err != nil {
  1942  		return err
  1943  	}
  1944  
  1945  	currentInfo, err := snapst.CurrentInfo()
  1946  	if err != nil {
  1947  		return err
  1948  	}
  1949  	svcs := currentInfo.Services()
  1950  	if len(svcs) == 0 {
  1951  		return nil
  1952  	}
  1953  
  1954  	var stopReason snap.ServiceStopReason
  1955  	if err := t.Get("stop-reason", &stopReason); err != nil && err != state.ErrNoState {
  1956  		return err
  1957  	}
  1958  
  1959  	pb := NewTaskProgressAdapterUnlocked(t)
  1960  	st.Unlock()
  1961  	defer st.Lock()
  1962  
  1963  	// stop the services
  1964  	err = m.backend.StopServices(svcs, stopReason, pb, perfTimings)
  1965  	if err != nil {
  1966  		return err
  1967  	}
  1968  
  1969  	// get the disabled services after we stopped all the services.
  1970  	// this list is not meant to save what services are disabled at any given
  1971  	// time, specifically just what services are disabled while systemd loses
  1972  	// track of the services. this list is also used to determine what services are enabled
  1973  	// when we start services of a new revision of the snap in
  1974  	// start-snap-services handler.
  1975  	disabledServices, err := m.queryDisabledServices(currentInfo, pb)
  1976  	if err != nil {
  1977  		return err
  1978  	}
  1979  
  1980  	st.Lock()
  1981  	defer st.Unlock()
  1982  
  1983  	// for undo
  1984  	t.Set("old-last-active-disabled-services", snapst.LastActiveDisabledServices)
  1985  	// undo could queryDisabledServices, but this avoids it
  1986  	t.Set("disabled-services", disabledServices)
  1987  
  1988  	// add to the disabled services list in snapst services which were disabled
  1989  	// for usage across changes like in reverting and enabling after being
  1990  	// disabled.
  1991  	// we keep what's already in the list in snapst because that list is
  1992  	// services which were previously present in the snap and disabled, but are
  1993  	// no longer present.
  1994  	snapst.LastActiveDisabledServices = append(
  1995  		snapst.LastActiveDisabledServices,
  1996  		disabledServices...,
  1997  	)
  1998  
  1999  	// reset services tracked by operations from hooks
  2000  	snapst.ServicesDisabledByHooks = nil
  2001  	snapst.ServicesEnabledByHooks = nil
  2002  
  2003  	Set(st, snapsup.InstanceName(), snapst)
  2004  
  2005  	return nil
  2006  }
  2007  
  2008  func (m *SnapManager) undoStopSnapServices(t *state.Task, _ *tomb.Tomb) error {
  2009  	st := t.State()
  2010  	st.Lock()
  2011  	defer st.Unlock()
  2012  
  2013  	perfTimings := state.TimingsForTask(t)
  2014  	defer perfTimings.Save(st)
  2015  
  2016  	snapsup, snapst, err := snapSetupAndState(t)
  2017  	if err != nil {
  2018  		return err
  2019  	}
  2020  	currentInfo, err := snapst.CurrentInfo()
  2021  	if err != nil {
  2022  		return err
  2023  	}
  2024  
  2025  	svcs := currentInfo.Services()
  2026  	if len(svcs) == 0 {
  2027  		return nil
  2028  	}
  2029  
  2030  	startupOrdered, err := snap.SortServices(svcs)
  2031  	if err != nil {
  2032  		return err
  2033  	}
  2034  
  2035  	var lastActiveDisabled []string
  2036  	if err := t.Get("old-last-active-disabled-services", &lastActiveDisabled); err != nil && err != state.ErrNoState {
  2037  		return err
  2038  	}
  2039  	snapst.LastActiveDisabledServices = lastActiveDisabled
  2040  	Set(st, snapsup.InstanceName(), snapst)
  2041  
  2042  	var disabledServices []string
  2043  	if err := t.Get("disabled-services", &disabledServices); err != nil && err != state.ErrNoState {
  2044  		return err
  2045  	}
  2046  
  2047  	st.Unlock()
  2048  	err = m.backend.StartServices(startupOrdered, disabledServices, progress.Null, perfTimings)
  2049  	st.Lock()
  2050  	if err != nil {
  2051  		return err
  2052  	}
  2053  
  2054  	return nil
  2055  }
  2056  
  2057  func (m *SnapManager) doUnlinkSnap(t *state.Task, _ *tomb.Tomb) error {
  2058  	// invoked only if snap has a current active revision, during remove or
  2059  	// disable
  2060  	// in case of the snapd snap, we only reach here if disabling or removal
  2061  	// was deemed ok by earlier checks
  2062  
  2063  	st := t.State()
  2064  	st.Lock()
  2065  	defer st.Unlock()
  2066  
  2067  	snapsup, snapst, err := snapSetupAndState(t)
  2068  	if err != nil {
  2069  		return err
  2070  	}
  2071  
  2072  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  2073  	if err != nil {
  2074  		return err
  2075  	}
  2076  
  2077  	// do the final unlink
  2078  	unlinkCtx := backend.LinkContext{
  2079  		FirstInstall: false,
  2080  	}
  2081  	err = m.backend.UnlinkSnap(info, unlinkCtx, NewTaskProgressAdapterLocked(t))
  2082  	if err != nil {
  2083  		return err
  2084  	}
  2085  
  2086  	// mark as inactive
  2087  	snapst.Active = false
  2088  	Set(st, snapsup.InstanceName(), snapst)
  2089  
  2090  	// Notify link snap participants about link changes.
  2091  	notifyLinkParticipants(t, snapsup.InstanceName())
  2092  
  2093  	return err
  2094  }
  2095  
  2096  func (m *SnapManager) undoUnlinkSnap(t *state.Task, _ *tomb.Tomb) error {
  2097  	st := t.State()
  2098  	st.Lock()
  2099  	defer st.Unlock()
  2100  
  2101  	perfTimings := state.TimingsForTask(t)
  2102  	defer perfTimings.Save(st)
  2103  
  2104  	snapsup, snapst, err := snapSetupAndState(t)
  2105  	if err != nil {
  2106  		return err
  2107  	}
  2108  
  2109  	isInstalled := snapst.IsInstalled()
  2110  	if !isInstalled {
  2111  		return fmt.Errorf("internal error: snap %q not installed anymore", snapsup.InstanceName())
  2112  	}
  2113  
  2114  	info, err := snapst.CurrentInfo()
  2115  	if err != nil {
  2116  		return err
  2117  	}
  2118  
  2119  	deviceCtx, err := DeviceCtx(st, t, nil)
  2120  	if err != nil {
  2121  		return err
  2122  	}
  2123  
  2124  	// undo here may be part of failed snap remove change, in which case a later
  2125  	// "clear-snap" task could have been executed and some or all of the
  2126  	// data of this snap could be lost. If that's the case, then we should not
  2127  	// enable the snap back.
  2128  	// XXX: should make an exception for snapd/core?
  2129  	place := snapsup.placeInfo()
  2130  	for _, dir := range []string{place.DataDir(), place.CommonDataDir()} {
  2131  		if exists, _, _ := osutil.DirExists(dir); !exists {
  2132  			t.Logf("cannot link snap %q back, some of its data has already been removed", snapsup.InstanceName())
  2133  			// TODO: mark the snap broken at the SnapState level when we have
  2134  			// such concept.
  2135  			return nil
  2136  		}
  2137  	}
  2138  
  2139  	snapst.Active = true
  2140  	Set(st, snapsup.InstanceName(), snapst)
  2141  
  2142  	opts, err := SnapServiceOptions(st, snapsup.InstanceName(), nil)
  2143  	if err != nil {
  2144  		return err
  2145  	}
  2146  	linkCtx := backend.LinkContext{
  2147  		FirstInstall:   false,
  2148  		ServiceOptions: opts,
  2149  	}
  2150  	reboot, err := m.backend.LinkSnap(info, deviceCtx, linkCtx, perfTimings)
  2151  	if err != nil {
  2152  		return err
  2153  	}
  2154  
  2155  	// Notify link snap participants about link changes.
  2156  	notifyLinkParticipants(t, snapsup.InstanceName())
  2157  
  2158  	// if we just linked back a core snap, request a restart
  2159  	// so that we switch executing its snapd.
  2160  	m.maybeRestart(t, info, reboot, deviceCtx)
  2161  
  2162  	return nil
  2163  }
  2164  
  2165  func (m *SnapManager) doClearSnapData(t *state.Task, _ *tomb.Tomb) error {
  2166  	st := t.State()
  2167  	st.Lock()
  2168  	snapsup, snapst, err := snapSetupAndState(t)
  2169  	st.Unlock()
  2170  	if err != nil {
  2171  		return err
  2172  	}
  2173  
  2174  	st.Lock()
  2175  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  2176  	st.Unlock()
  2177  	if err != nil {
  2178  		return err
  2179  	}
  2180  
  2181  	if err = m.backend.RemoveSnapData(info); err != nil {
  2182  		return err
  2183  	}
  2184  
  2185  	if len(snapst.Sequence) == 1 {
  2186  		// Only remove data common between versions if this is the last version
  2187  		if err = m.backend.RemoveSnapCommonData(info); err != nil {
  2188  			return err
  2189  		}
  2190  
  2191  		st.Lock()
  2192  		defer st.Unlock()
  2193  
  2194  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  2195  		if err != nil {
  2196  			return err
  2197  		}
  2198  		// Snap data directory can be removed now too
  2199  		if err := m.backend.RemoveSnapDataDir(info, otherInstances); err != nil {
  2200  			return err
  2201  		}
  2202  	}
  2203  
  2204  	return nil
  2205  }
  2206  
  2207  func (m *SnapManager) doDiscardSnap(t *state.Task, _ *tomb.Tomb) error {
  2208  	st := t.State()
  2209  	st.Lock()
  2210  	defer st.Unlock()
  2211  
  2212  	snapsup, snapst, err := snapSetupAndState(t)
  2213  	if err != nil {
  2214  		return err
  2215  	}
  2216  
  2217  	deviceCtx, err := DeviceCtx(st, t, nil)
  2218  	if err != nil {
  2219  		return err
  2220  	}
  2221  
  2222  	if snapst.Current == snapsup.Revision() && snapst.Active {
  2223  		return fmt.Errorf("internal error: cannot discard snap %q: still active", snapsup.InstanceName())
  2224  	}
  2225  
  2226  	if len(snapst.Sequence) == 1 {
  2227  		snapst.Sequence = nil
  2228  		snapst.Current = snap.Revision{}
  2229  	} else {
  2230  		newSeq := make([]*snap.SideInfo, 0, len(snapst.Sequence))
  2231  		for _, si := range snapst.Sequence {
  2232  			if si.Revision == snapsup.Revision() {
  2233  				// leave out
  2234  				continue
  2235  			}
  2236  			newSeq = append(newSeq, si)
  2237  		}
  2238  		snapst.Sequence = newSeq
  2239  		if snapst.Current == snapsup.Revision() {
  2240  			snapst.Current = newSeq[len(newSeq)-1].Revision
  2241  		}
  2242  	}
  2243  
  2244  	pb := NewTaskProgressAdapterLocked(t)
  2245  	typ, err := snapst.Type()
  2246  	if err != nil {
  2247  		return err
  2248  	}
  2249  	err = m.backend.RemoveSnapFiles(snapsup.placeInfo(), typ, nil, deviceCtx, pb)
  2250  	if err != nil {
  2251  		t.Errorf("cannot remove snap file %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  2252  		return &state.Retry{After: 3 * time.Minute}
  2253  	}
  2254  	if len(snapst.Sequence) == 0 {
  2255  		// Remove configuration associated with this snap.
  2256  		err = config.DeleteSnapConfig(st, snapsup.InstanceName())
  2257  		if err != nil {
  2258  			return err
  2259  		}
  2260  		err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  2261  		if err != nil {
  2262  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  2263  			return &state.Retry{After: 3 * time.Minute}
  2264  		}
  2265  		err = m.backend.RemoveSnapInhibitLock(snapsup.InstanceName())
  2266  		if err != nil {
  2267  			return err
  2268  		}
  2269  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  2270  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  2271  		}
  2272  
  2273  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  2274  		if err != nil {
  2275  			return err
  2276  		}
  2277  
  2278  		if err := m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances); err != nil {
  2279  			return fmt.Errorf("cannot remove snap directory: %v", err)
  2280  		}
  2281  
  2282  		// try to remove the auxiliary store info
  2283  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  2284  			logger.Noticef("Cannot remove auxiliary store info for %q: %v", snapsup.InstanceName(), err)
  2285  		}
  2286  
  2287  		// XXX: also remove sequence files?
  2288  
  2289  		// remove the snap from any quota groups it may have been in, otherwise
  2290  		// that quota group may get into an inconsistent state
  2291  		if err := EnsureSnapAbsentFromQuotaGroup(st, snapsup.InstanceName()); err != nil {
  2292  			return err
  2293  		}
  2294  	}
  2295  	if err = config.DiscardRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  2296  		return err
  2297  	}
  2298  	if err = SecurityProfilesRemoveLate(snapsup.InstanceName(), snapsup.Revision(), snapsup.Type); err != nil {
  2299  		return err
  2300  	}
  2301  	Set(st, snapsup.InstanceName(), snapst)
  2302  	return nil
  2303  }
  2304  
  2305  /* aliases v2
  2306  
  2307  aliases v2 implementation uses the following tasks:
  2308  
  2309    * for install/refresh/remove/enable/disable etc
  2310  
  2311      - remove-aliases: remove aliases of a snap from disk and mark them pending
  2312  
  2313      - setup-aliases: (re)creates aliases from snap state, mark them as
  2314        not pending
  2315  
  2316      - set-auto-aliases: updates aliases snap state based on the
  2317        snap-declaration and current revision info of the snap
  2318  
  2319    * for refresh & when the snap-declaration aliases change without a
  2320      new revision
  2321  
  2322      - refresh-aliases: updates aliases snap state and updates them on disk too;
  2323        its undo is used generically by other tasks as well
  2324  
  2325      - prune-auto-aliases: used for the special case of automatic
  2326        aliases transferred from one snap to another to prune them from
  2327        the source snaps to avoid conflicts in later operations
  2328  
  2329    * for alias/unalias/prefer:
  2330  
  2331      - alias: creates a manual alias
  2332  
  2333      - unalias: removes a manual alias
  2334  
  2335      - disable-aliases: disable the automatic aliases of a snap and
  2336        removes all manual ones as well
  2337  
  2338      - prefer-aliases: enables the automatic aliases of a snap after
  2339        disabling any other snap conflicting aliases
  2340  
  2341  */
  2342  
  2343  func (m *SnapManager) doSetAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  2344  	st := t.State()
  2345  	st.Lock()
  2346  	defer st.Unlock()
  2347  	snapsup, snapst, err := snapSetupAndState(t)
  2348  	if err != nil {
  2349  		return err
  2350  	}
  2351  	snapName := snapsup.InstanceName()
  2352  	curInfo, err := snapst.CurrentInfo()
  2353  	if err != nil {
  2354  		return err
  2355  	}
  2356  
  2357  	// --unaliased
  2358  	if snapsup.Unaliased {
  2359  		t.Set("old-auto-aliases-disabled", snapst.AutoAliasesDisabled)
  2360  		snapst.AutoAliasesDisabled = true
  2361  	}
  2362  
  2363  	curAliases := snapst.Aliases
  2364  	// TODO: implement --prefer logic
  2365  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  2366  	if err != nil {
  2367  		return err
  2368  	}
  2369  	_, err = checkAliasesConflicts(st, snapName, snapst.AutoAliasesDisabled, newAliases, nil)
  2370  	if err != nil {
  2371  		return err
  2372  	}
  2373  
  2374  	t.Set("old-aliases-v2", curAliases)
  2375  	// noop, except on first install where we need to set this here
  2376  	snapst.AliasesPending = true
  2377  	snapst.Aliases = newAliases
  2378  	Set(st, snapName, snapst)
  2379  	return nil
  2380  }
  2381  
  2382  func (m *SnapManager) doRemoveAliases(t *state.Task, _ *tomb.Tomb) error {
  2383  	st := t.State()
  2384  	st.Lock()
  2385  	defer st.Unlock()
  2386  	snapsup, snapst, err := snapSetupAndState(t)
  2387  	if err != nil {
  2388  		return err
  2389  	}
  2390  	snapName := snapsup.InstanceName()
  2391  
  2392  	err = m.backend.RemoveSnapAliases(snapName)
  2393  	if err != nil {
  2394  		return err
  2395  	}
  2396  
  2397  	snapst.AliasesPending = true
  2398  	Set(st, snapName, snapst)
  2399  	return nil
  2400  }
  2401  
  2402  func (m *SnapManager) doSetupAliases(t *state.Task, _ *tomb.Tomb) error {
  2403  	st := t.State()
  2404  	st.Lock()
  2405  	defer st.Unlock()
  2406  	snapsup, snapst, err := snapSetupAndState(t)
  2407  	if err != nil {
  2408  		return err
  2409  	}
  2410  	snapName := snapsup.InstanceName()
  2411  	curAliases := snapst.Aliases
  2412  
  2413  	_, _, err = applyAliasesChange(snapName, autoDis, nil, snapst.AutoAliasesDisabled, curAliases, m.backend, doApply)
  2414  	if err != nil {
  2415  		return err
  2416  	}
  2417  
  2418  	snapst.AliasesPending = false
  2419  	Set(st, snapName, snapst)
  2420  	return nil
  2421  }
  2422  
  2423  func (m *SnapManager) doRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  2424  	st := t.State()
  2425  	st.Lock()
  2426  	defer st.Unlock()
  2427  	snapsup, snapst, err := snapSetupAndState(t)
  2428  	if err != nil {
  2429  		return err
  2430  	}
  2431  	snapName := snapsup.InstanceName()
  2432  	curInfo, err := snapst.CurrentInfo()
  2433  	if err != nil {
  2434  		return err
  2435  	}
  2436  
  2437  	autoDisabled := snapst.AutoAliasesDisabled
  2438  	curAliases := snapst.Aliases
  2439  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  2440  	if err != nil {
  2441  		return err
  2442  	}
  2443  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  2444  	if err != nil {
  2445  		return err
  2446  	}
  2447  
  2448  	if !snapst.AliasesPending {
  2449  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  2450  			return err
  2451  		}
  2452  	}
  2453  
  2454  	t.Set("old-aliases-v2", curAliases)
  2455  	snapst.Aliases = newAliases
  2456  	Set(st, snapName, snapst)
  2457  	return nil
  2458  }
  2459  
  2460  func (m *SnapManager) undoRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  2461  	st := t.State()
  2462  	st.Lock()
  2463  	defer st.Unlock()
  2464  	var oldAliases map[string]*AliasTarget
  2465  	err := t.Get("old-aliases-v2", &oldAliases)
  2466  	if err == state.ErrNoState {
  2467  		// nothing to do
  2468  		return nil
  2469  	}
  2470  	if err != nil {
  2471  		return err
  2472  	}
  2473  	snapsup, snapst, err := snapSetupAndState(t)
  2474  	if err != nil {
  2475  		return err
  2476  	}
  2477  	snapName := snapsup.InstanceName()
  2478  	curAutoDisabled := snapst.AutoAliasesDisabled
  2479  	autoDisabled := curAutoDisabled
  2480  	if err = t.Get("old-auto-aliases-disabled", &autoDisabled); err != nil && err != state.ErrNoState {
  2481  		return err
  2482  	}
  2483  
  2484  	var otherSnapDisabled map[string]*otherDisabledAliases
  2485  	if err = t.Get("other-disabled-aliases", &otherSnapDisabled); err != nil && err != state.ErrNoState {
  2486  		return err
  2487  	}
  2488  
  2489  	// check if the old states creates conflicts now
  2490  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, oldAliases, nil)
  2491  	if _, ok := err.(*AliasConflictError); ok {
  2492  		// best we can do is reinstate with all aliases disabled
  2493  		t.Errorf("cannot reinstate alias state because of conflicts, disabling: %v", err)
  2494  		oldAliases, _ = disableAliases(oldAliases)
  2495  		autoDisabled = true
  2496  	} else if err != nil {
  2497  		return err
  2498  	}
  2499  
  2500  	if !snapst.AliasesPending {
  2501  		curAliases := snapst.Aliases
  2502  		if _, _, err := applyAliasesChange(snapName, curAutoDisabled, curAliases, autoDisabled, oldAliases, m.backend, doApply); err != nil {
  2503  			return err
  2504  		}
  2505  	}
  2506  
  2507  	snapst.AutoAliasesDisabled = autoDisabled
  2508  	snapst.Aliases = oldAliases
  2509  	newSnapStates := make(map[string]*SnapState, 1+len(otherSnapDisabled))
  2510  	newSnapStates[snapName] = snapst
  2511  
  2512  	// if we disabled other snap aliases try to undo that
  2513  	conflicting := make(map[string]bool, len(otherSnapDisabled))
  2514  	otherCurSnapStates := make(map[string]*SnapState, len(otherSnapDisabled))
  2515  	for otherSnap, otherDisabled := range otherSnapDisabled {
  2516  		var otherSnapState SnapState
  2517  		err := Get(st, otherSnap, &otherSnapState)
  2518  		if err != nil {
  2519  			return err
  2520  		}
  2521  		otherCurInfo, err := otherSnapState.CurrentInfo()
  2522  		if err != nil {
  2523  			return err
  2524  		}
  2525  
  2526  		otherCurSnapStates[otherSnap] = &otherSnapState
  2527  
  2528  		autoDisabled := otherSnapState.AutoAliasesDisabled
  2529  		if otherDisabled.Auto {
  2530  			// automatic aliases of other were disabled, undo that
  2531  			autoDisabled = false
  2532  		}
  2533  		otherAliases := reenableAliases(otherCurInfo, otherSnapState.Aliases, otherDisabled.Manual)
  2534  		// check for conflicts taking into account
  2535  		// re-enabled aliases
  2536  		conflicts, err := checkAliasesConflicts(st, otherSnap, autoDisabled, otherAliases, newSnapStates)
  2537  		if _, ok := err.(*AliasConflictError); ok {
  2538  			conflicting[otherSnap] = true
  2539  			for conflictSnap := range conflicts {
  2540  				conflicting[conflictSnap] = true
  2541  			}
  2542  		} else if err != nil {
  2543  			return err
  2544  		}
  2545  
  2546  		newSnapState := otherSnapState
  2547  		newSnapState.Aliases = otherAliases
  2548  		newSnapState.AutoAliasesDisabled = autoDisabled
  2549  		newSnapStates[otherSnap] = &newSnapState
  2550  	}
  2551  
  2552  	// apply non-conflicting other
  2553  	for otherSnap, otherSnapState := range otherCurSnapStates {
  2554  		if conflicting[otherSnap] {
  2555  			// keep as it was
  2556  			continue
  2557  		}
  2558  		newSnapSt := newSnapStates[otherSnap]
  2559  		if !otherSnapState.AliasesPending {
  2560  			if _, _, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, newSnapSt.AutoAliasesDisabled, newSnapSt.Aliases, m.backend, doApply); err != nil {
  2561  				return err
  2562  			}
  2563  		}
  2564  	}
  2565  
  2566  	for instanceName, snapst := range newSnapStates {
  2567  		if conflicting[instanceName] {
  2568  			// keep as it was
  2569  			continue
  2570  		}
  2571  		Set(st, instanceName, snapst)
  2572  	}
  2573  	return nil
  2574  }
  2575  
  2576  func (m *SnapManager) doPruneAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  2577  	st := t.State()
  2578  	st.Lock()
  2579  	defer st.Unlock()
  2580  	snapsup, snapst, err := snapSetupAndState(t)
  2581  	if err != nil {
  2582  		return err
  2583  	}
  2584  	var which []string
  2585  	err = t.Get("aliases", &which)
  2586  	if err != nil {
  2587  		return err
  2588  	}
  2589  	snapName := snapsup.InstanceName()
  2590  	autoDisabled := snapst.AutoAliasesDisabled
  2591  	curAliases := snapst.Aliases
  2592  
  2593  	newAliases := pruneAutoAliases(curAliases, which)
  2594  
  2595  	if !snapst.AliasesPending {
  2596  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  2597  			return err
  2598  		}
  2599  	}
  2600  
  2601  	t.Set("old-aliases-v2", curAliases)
  2602  	snapst.Aliases = newAliases
  2603  	Set(st, snapName, snapst)
  2604  	return nil
  2605  }
  2606  
  2607  type changedAlias struct {
  2608  	Snap  string `json:"snap"`
  2609  	App   string `json:"app"`
  2610  	Alias string `json:"alias"`
  2611  }
  2612  
  2613  func aliasesTrace(t *state.Task, added, removed []*backend.Alias) error {
  2614  	chg := t.Change()
  2615  	var data map[string]interface{}
  2616  	err := chg.Get("api-data", &data)
  2617  	if err != nil && err != state.ErrNoState {
  2618  		return err
  2619  	}
  2620  	if len(data) == 0 {
  2621  		data = make(map[string]interface{})
  2622  	}
  2623  
  2624  	curAdded, _ := data["aliases-added"].([]interface{})
  2625  	for _, a := range added {
  2626  		snap, app := snap.SplitSnapApp(a.Target)
  2627  		curAdded = append(curAdded, &changedAlias{
  2628  			Snap:  snap,
  2629  			App:   app,
  2630  			Alias: a.Name,
  2631  		})
  2632  	}
  2633  	data["aliases-added"] = curAdded
  2634  
  2635  	curRemoved, _ := data["aliases-removed"].([]interface{})
  2636  	for _, a := range removed {
  2637  		snap, app := snap.SplitSnapApp(a.Target)
  2638  		curRemoved = append(curRemoved, &changedAlias{
  2639  			Snap:  snap,
  2640  			App:   app,
  2641  			Alias: a.Name,
  2642  		})
  2643  	}
  2644  	data["aliases-removed"] = curRemoved
  2645  
  2646  	chg.Set("api-data", data)
  2647  	return nil
  2648  }
  2649  
  2650  func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error {
  2651  	st := t.State()
  2652  	st.Lock()
  2653  	defer st.Unlock()
  2654  	snapsup, snapst, err := snapSetupAndState(t)
  2655  	if err != nil {
  2656  		return err
  2657  	}
  2658  	var target, alias string
  2659  	err = t.Get("target", &target)
  2660  	if err != nil {
  2661  		return err
  2662  	}
  2663  	err = t.Get("alias", &alias)
  2664  	if err != nil {
  2665  		return err
  2666  	}
  2667  
  2668  	snapName := snapsup.InstanceName()
  2669  	curInfo, err := snapst.CurrentInfo()
  2670  	if err != nil {
  2671  		return err
  2672  	}
  2673  
  2674  	autoDisabled := snapst.AutoAliasesDisabled
  2675  	curAliases := snapst.Aliases
  2676  	newAliases, err := manualAlias(curInfo, curAliases, target, alias)
  2677  	if err != nil {
  2678  		return err
  2679  	}
  2680  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  2681  	if err != nil {
  2682  		return err
  2683  	}
  2684  
  2685  	added, removed, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2686  	if err != nil {
  2687  		return err
  2688  	}
  2689  	if err := aliasesTrace(t, added, removed); err != nil {
  2690  		return err
  2691  	}
  2692  
  2693  	t.Set("old-aliases-v2", curAliases)
  2694  	snapst.Aliases = newAliases
  2695  	Set(st, snapName, snapst)
  2696  	return nil
  2697  }
  2698  
  2699  func (m *SnapManager) doDisableAliases(t *state.Task, _ *tomb.Tomb) error {
  2700  	st := t.State()
  2701  	st.Lock()
  2702  	defer st.Unlock()
  2703  	snapsup, snapst, err := snapSetupAndState(t)
  2704  	if err != nil {
  2705  		return err
  2706  	}
  2707  	snapName := snapsup.InstanceName()
  2708  
  2709  	oldAutoDisabled := snapst.AutoAliasesDisabled
  2710  	oldAliases := snapst.Aliases
  2711  	newAliases, _ := disableAliases(oldAliases)
  2712  
  2713  	added, removed, err := applyAliasesChange(snapName, oldAutoDisabled, oldAliases, autoDis, newAliases, m.backend, snapst.AliasesPending)
  2714  	if err != nil {
  2715  		return err
  2716  	}
  2717  	if err := aliasesTrace(t, added, removed); err != nil {
  2718  		return err
  2719  	}
  2720  
  2721  	t.Set("old-auto-aliases-disabled", oldAutoDisabled)
  2722  	snapst.AutoAliasesDisabled = true
  2723  	t.Set("old-aliases-v2", oldAliases)
  2724  	snapst.Aliases = newAliases
  2725  	Set(st, snapName, snapst)
  2726  	return nil
  2727  }
  2728  
  2729  func (m *SnapManager) doUnalias(t *state.Task, _ *tomb.Tomb) error {
  2730  	st := t.State()
  2731  	st.Lock()
  2732  	defer st.Unlock()
  2733  	snapsup, snapst, err := snapSetupAndState(t)
  2734  	if err != nil {
  2735  		return err
  2736  	}
  2737  	var alias string
  2738  	err = t.Get("alias", &alias)
  2739  	if err != nil {
  2740  		return err
  2741  	}
  2742  	snapName := snapsup.InstanceName()
  2743  
  2744  	autoDisabled := snapst.AutoAliasesDisabled
  2745  	oldAliases := snapst.Aliases
  2746  	newAliases, err := manualUnalias(oldAliases, alias)
  2747  	if err != nil {
  2748  		return err
  2749  	}
  2750  
  2751  	added, removed, err := applyAliasesChange(snapName, autoDisabled, oldAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2752  	if err != nil {
  2753  		return err
  2754  	}
  2755  	if err := aliasesTrace(t, added, removed); err != nil {
  2756  		return err
  2757  	}
  2758  
  2759  	t.Set("old-aliases-v2", oldAliases)
  2760  	snapst.Aliases = newAliases
  2761  	Set(st, snapName, snapst)
  2762  	return nil
  2763  }
  2764  
  2765  // otherDisabledAliases is used to track for the benefit of undo what
  2766  // changes were made aka what aliases were disabled of another
  2767  // conflicting snap by prefer logic
  2768  type otherDisabledAliases struct {
  2769  	// Auto records whether prefer had to disable automatic aliases
  2770  	Auto bool `json:"auto,omitempty"`
  2771  	// Manual records which manual aliases were removed by prefer
  2772  	Manual map[string]string `json:"manual,omitempty"`
  2773  }
  2774  
  2775  func (m *SnapManager) doPreferAliases(t *state.Task, _ *tomb.Tomb) error {
  2776  	st := t.State()
  2777  	st.Lock()
  2778  	defer st.Unlock()
  2779  	snapsup, snapst, err := snapSetupAndState(t)
  2780  	if err != nil {
  2781  		return err
  2782  	}
  2783  	instanceName := snapsup.InstanceName()
  2784  
  2785  	if !snapst.AutoAliasesDisabled {
  2786  		// already enabled, nothing to do
  2787  		return nil
  2788  	}
  2789  
  2790  	curAliases := snapst.Aliases
  2791  	aliasConflicts, err := checkAliasesConflicts(st, instanceName, autoEn, curAliases, nil)
  2792  	conflErr, isConflErr := err.(*AliasConflictError)
  2793  	if err != nil && !isConflErr {
  2794  		return err
  2795  	}
  2796  	if isConflErr && conflErr.Conflicts == nil {
  2797  		// it's a snap command namespace conflict, we cannot remedy it
  2798  		return conflErr
  2799  	}
  2800  	// proceed to disable conflicting aliases as needed
  2801  	// before re-enabling instanceName aliases
  2802  
  2803  	otherSnapStates := make(map[string]*SnapState, len(aliasConflicts))
  2804  	otherSnapDisabled := make(map[string]*otherDisabledAliases, len(aliasConflicts))
  2805  	for otherSnap := range aliasConflicts {
  2806  		var otherSnapState SnapState
  2807  		err := Get(st, otherSnap, &otherSnapState)
  2808  		if err != nil {
  2809  			return err
  2810  		}
  2811  
  2812  		otherAliases, disabledManual := disableAliases(otherSnapState.Aliases)
  2813  
  2814  		added, removed, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, autoDis, otherAliases, m.backend, otherSnapState.AliasesPending)
  2815  		if err != nil {
  2816  			return err
  2817  		}
  2818  		if err := aliasesTrace(t, added, removed); err != nil {
  2819  			return err
  2820  		}
  2821  
  2822  		var otherDisabled otherDisabledAliases
  2823  		otherDisabled.Manual = disabledManual
  2824  		otherSnapState.Aliases = otherAliases
  2825  		// disable automatic aliases as needed
  2826  		if !otherSnapState.AutoAliasesDisabled && len(otherAliases) != 0 {
  2827  			// record that we did disable automatic aliases
  2828  			otherDisabled.Auto = true
  2829  			otherSnapState.AutoAliasesDisabled = true
  2830  		}
  2831  		otherSnapDisabled[otherSnap] = &otherDisabled
  2832  		otherSnapStates[otherSnap] = &otherSnapState
  2833  	}
  2834  
  2835  	added, removed, err := applyAliasesChange(instanceName, autoDis, curAliases, autoEn, curAliases, m.backend, snapst.AliasesPending)
  2836  	if err != nil {
  2837  		return err
  2838  	}
  2839  	if err := aliasesTrace(t, added, removed); err != nil {
  2840  		return err
  2841  	}
  2842  
  2843  	for otherSnap, otherSnapState := range otherSnapStates {
  2844  		Set(st, otherSnap, otherSnapState)
  2845  	}
  2846  	if len(otherSnapDisabled) != 0 {
  2847  		t.Set("other-disabled-aliases", otherSnapDisabled)
  2848  	}
  2849  	t.Set("old-auto-aliases-disabled", true)
  2850  	t.Set("old-aliases-v2", curAliases)
  2851  	snapst.AutoAliasesDisabled = false
  2852  	Set(st, instanceName, snapst)
  2853  	return nil
  2854  }
  2855  
  2856  // changeReadyUpToTask returns whether all other change's tasks are Ready.
  2857  func changeReadyUpToTask(task *state.Task) bool {
  2858  	me := task.ID()
  2859  	change := task.Change()
  2860  	for _, task := range change.Tasks() {
  2861  		if me == task.ID() {
  2862  			// ignore self
  2863  			continue
  2864  		}
  2865  		if !task.Status().Ready() {
  2866  			return false
  2867  		}
  2868  	}
  2869  	return true
  2870  }
  2871  
  2872  // refreshedSnaps returns the instance names of the snaps successfully refreshed
  2873  // in the last batch of refreshes before the given (re-refresh) task.
  2874  //
  2875  // It does this by advancing through the given task's change's tasks, keeping
  2876  // track of the instance names from the first SnapSetup in every lane, stopping
  2877  // when finding the given task, and resetting things when finding a different
  2878  // re-refresh task (that indicates the end of a batch that isn't the given one).
  2879  func refreshedSnaps(reTask *state.Task) []string {
  2880  	// NOTE nothing requires reTask to be a check-rerefresh task, nor even to be in
  2881  	// a refresh-ish change, but it doesn't make much sense to call this otherwise.
  2882  	tid := reTask.ID()
  2883  	laneSnaps := map[int]string{}
  2884  	// change.Tasks() preserves the order tasks were added, otherwise it all falls apart
  2885  	for _, task := range reTask.Change().Tasks() {
  2886  		if task.ID() == tid {
  2887  			// we've reached ourselves; we don't care about anything beyond this
  2888  			break
  2889  		}
  2890  		if task.Kind() == "check-rerefresh" {
  2891  			// we've reached a previous check-rerefresh (but not ourselves).
  2892  			// Only snaps in tasks after this point are of interest.
  2893  			laneSnaps = map[int]string{}
  2894  		}
  2895  		lanes := task.Lanes()
  2896  		if len(lanes) != 1 {
  2897  			// can't happen, really
  2898  			continue
  2899  		}
  2900  		lane := lanes[0]
  2901  		if lane == 0 {
  2902  			// not really a lane
  2903  			continue
  2904  		}
  2905  		if task.Status() != state.DoneStatus {
  2906  			// ignore non-successful lane (1)
  2907  			laneSnaps[lane] = ""
  2908  			continue
  2909  		}
  2910  		if _, ok := laneSnaps[lane]; ok {
  2911  			// ignore lanes we've already seen (including ones explicitly ignored in (1))
  2912  			continue
  2913  		}
  2914  		var snapsup SnapSetup
  2915  		if err := task.Get("snap-setup", &snapsup); err != nil {
  2916  			continue
  2917  		}
  2918  		laneSnaps[lane] = snapsup.InstanceName()
  2919  	}
  2920  
  2921  	snapNames := make([]string, 0, len(laneSnaps))
  2922  	for _, name := range laneSnaps {
  2923  		if name == "" {
  2924  			// the lane was unsuccessful
  2925  			continue
  2926  		}
  2927  		snapNames = append(snapNames, name)
  2928  	}
  2929  	return snapNames
  2930  }
  2931  
  2932  // reRefreshSetup holds the necessary details to re-refresh snaps that need it
  2933  type reRefreshSetup struct {
  2934  	UserID int `json:"user-id,omitempty"`
  2935  	*Flags
  2936  }
  2937  
  2938  // reRefreshUpdateMany exists just to make testing simpler
  2939  var reRefreshUpdateMany = updateManyFiltered
  2940  
  2941  // reRefreshFilter is an updateFilter that returns whether the given update
  2942  // needs a re-refresh because of further epoch transitions available.
  2943  func reRefreshFilter(update *snap.Info, snapst *SnapState) bool {
  2944  	cur, err := snapst.CurrentInfo()
  2945  	if err != nil {
  2946  		return false
  2947  	}
  2948  	return !update.Epoch.Equal(&cur.Epoch)
  2949  }
  2950  
  2951  var reRefreshRetryTimeout = time.Second / 2
  2952  
  2953  func (m *SnapManager) doCheckReRefresh(t *state.Task, tomb *tomb.Tomb) error {
  2954  	st := t.State()
  2955  	st.Lock()
  2956  	defer st.Unlock()
  2957  
  2958  	if numHaltTasks := t.NumHaltTasks(); numHaltTasks > 0 {
  2959  		logger.Panicf("Re-refresh task has %d tasks waiting for it.", numHaltTasks)
  2960  	}
  2961  
  2962  	if !changeReadyUpToTask(t) {
  2963  		return &state.Retry{After: reRefreshRetryTimeout, Reason: "pending refreshes"}
  2964  	}
  2965  	snaps := refreshedSnaps(t)
  2966  	if len(snaps) == 0 {
  2967  		// nothing to do (maybe everything failed)
  2968  		return nil
  2969  	}
  2970  
  2971  	var re reRefreshSetup
  2972  	if err := t.Get("rerefresh-setup", &re); err != nil {
  2973  		return err
  2974  	}
  2975  	chg := t.Change()
  2976  	updated, tasksets, err := reRefreshUpdateMany(tomb.Context(nil), st, snaps, re.UserID, reRefreshFilter, re.Flags, chg.ID())
  2977  	if err != nil {
  2978  		return err
  2979  	}
  2980  
  2981  	if len(updated) == 0 {
  2982  		t.Logf("No re-refreshes found.")
  2983  	} else {
  2984  		t.Logf("Found re-refresh for %s.", strutil.Quoted(updated))
  2985  
  2986  		for _, taskset := range tasksets {
  2987  			chg.AddAll(taskset)
  2988  		}
  2989  		st.EnsureBefore(0)
  2990  	}
  2991  	t.SetStatus(state.DoneStatus)
  2992  
  2993  	return nil
  2994  }
  2995  
  2996  func (m *SnapManager) doConditionalAutoRefresh(t *state.Task, tomb *tomb.Tomb) error {
  2997  	st := t.State()
  2998  	st.Lock()
  2999  	defer st.Unlock()
  3000  
  3001  	snaps, err := snapsToRefresh(t)
  3002  	if err != nil {
  3003  		return err
  3004  	}
  3005  
  3006  	if len(snaps) == 0 {
  3007  		logger.Debugf("refresh gating: no snaps to refresh")
  3008  		return nil
  3009  	}
  3010  
  3011  	tss, err := autoRefreshPhase2(context.TODO(), st, snaps)
  3012  	if err != nil {
  3013  		return err
  3014  	}
  3015  
  3016  	// update original auto-refresh change
  3017  	chg := t.Change()
  3018  	for _, ts := range tss {
  3019  		ts.WaitFor(t)
  3020  		chg.AddAll(ts)
  3021  	}
  3022  	t.SetStatus(state.DoneStatus)
  3023  
  3024  	st.EnsureBefore(0)
  3025  	return nil
  3026  }
  3027  
  3028  // InjectTasks makes all the halt tasks of the mainTask wait for extraTasks;
  3029  // extraTasks join the same lane and change as the mainTask.
  3030  func InjectTasks(mainTask *state.Task, extraTasks *state.TaskSet) {
  3031  	lanes := mainTask.Lanes()
  3032  	if len(lanes) == 1 && lanes[0] == 0 {
  3033  		lanes = nil
  3034  	}
  3035  	for _, l := range lanes {
  3036  		extraTasks.JoinLane(l)
  3037  	}
  3038  
  3039  	chg := mainTask.Change()
  3040  	// Change shouldn't normally be nil, except for cases where
  3041  	// this helper is used before tasks are added to a change.
  3042  	if chg != nil {
  3043  		chg.AddAll(extraTasks)
  3044  	}
  3045  
  3046  	// make all halt tasks of the mainTask wait on extraTasks
  3047  	ht := mainTask.HaltTasks()
  3048  	for _, t := range ht {
  3049  		t.WaitAll(extraTasks)
  3050  	}
  3051  
  3052  	// make the extra tasks wait for main task
  3053  	extraTasks.WaitFor(mainTask)
  3054  }
  3055  
  3056  func InjectAutoConnect(mainTask *state.Task, snapsup *SnapSetup) {
  3057  	st := mainTask.State()
  3058  	autoConnect := st.NewTask("auto-connect", fmt.Sprintf(i18n.G("Automatically connect eligible plugs and slots of snap %q"), snapsup.InstanceName()))
  3059  	autoConnect.Set("snap-setup", snapsup)
  3060  	InjectTasks(mainTask, state.NewTaskSet(autoConnect))
  3061  	mainTask.Logf("added auto-connect task")
  3062  }