github.com/rigado/snapd@v2.42.5-go-mod+incompatible/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  	"strconv"
    29  	"strings"
    30  	"time"
    31  
    32  	"gopkg.in/tomb.v2"
    33  
    34  	"github.com/snapcore/snapd/boot"
    35  	"github.com/snapcore/snapd/dirs"
    36  	"github.com/snapcore/snapd/features"
    37  	"github.com/snapcore/snapd/i18n"
    38  	"github.com/snapcore/snapd/logger"
    39  	"github.com/snapcore/snapd/osutil"
    40  	"github.com/snapcore/snapd/overlord/auth"
    41  	"github.com/snapcore/snapd/overlord/configstate/config"
    42  	"github.com/snapcore/snapd/overlord/configstate/settings"
    43  	"github.com/snapcore/snapd/overlord/snapstate/backend"
    44  	"github.com/snapcore/snapd/overlord/state"
    45  	"github.com/snapcore/snapd/release"
    46  	"github.com/snapcore/snapd/snap"
    47  	"github.com/snapcore/snapd/store"
    48  	"github.com/snapcore/snapd/strutil"
    49  	"github.com/snapcore/snapd/timings"
    50  )
    51  
    52  // TaskSnapSetup returns the SnapSetup with task params hold by or referred to by the task.
    53  func TaskSnapSetup(t *state.Task) (*SnapSetup, error) {
    54  	var snapsup SnapSetup
    55  
    56  	err := t.Get("snap-setup", &snapsup)
    57  	if err != nil && err != state.ErrNoState {
    58  		return nil, err
    59  	}
    60  	if err == nil {
    61  		return &snapsup, nil
    62  	}
    63  
    64  	var id string
    65  	err = t.Get("snap-setup-task", &id)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	ts := t.State().Task(id)
    71  	if ts == nil {
    72  		return nil, fmt.Errorf("internal error: tasks are being pruned")
    73  	}
    74  	if err := ts.Get("snap-setup", &snapsup); err != nil {
    75  		return nil, err
    76  	}
    77  	return &snapsup, nil
    78  }
    79  
    80  func snapSetupAndState(t *state.Task) (*SnapSetup, *SnapState, error) {
    81  	snapsup, err := TaskSnapSetup(t)
    82  	if err != nil {
    83  		return nil, nil, err
    84  	}
    85  	var snapst SnapState
    86  	err = Get(t.State(), snapsup.InstanceName(), &snapst)
    87  	if err != nil && err != state.ErrNoState {
    88  		return nil, nil, err
    89  	}
    90  	return snapsup, &snapst, nil
    91  }
    92  
    93  /* State Locking
    94  
    95     do* / undo* handlers should usually lock the state just once with:
    96  
    97  	st.Lock()
    98  	defer st.Unlock()
    99  
   100     For tasks doing slow operations (long i/o, networking operations) it's OK
   101     to unlock the state temporarily:
   102  
   103          st.Unlock()
   104          err := slowIOOp()
   105          st.Lock()
   106          if err != nil {
   107             ...
   108          }
   109  
   110      but if a task Get and then Set the SnapState of a snap it must avoid
   111      releasing the state lock in between, other tasks might have
   112      reasons to update the SnapState independently:
   113  
   114          // DO NOT DO THIS!:
   115          snapst := ...
   116          snapst.Attr = ...
   117          st.Unlock()
   118          ...
   119          st.Lock()
   120          Set(st, snapName, snapst)
   121  
   122      if a task really needs to mix mutating a SnapState and releasing the state
   123      lock it should be serialized at the task runner level, see
   124      SnapManger.blockedTask and TaskRunner.SetBlocked
   125  
   126  */
   127  
   128  const defaultCoreSnapName = "core"
   129  
   130  func defaultBaseSnapsChannel() string {
   131  	channel := os.Getenv("SNAPD_BASES_CHANNEL")
   132  	if channel == "" {
   133  		return "stable"
   134  	}
   135  	return channel
   136  }
   137  
   138  func defaultSnapdSnapsChannel() string {
   139  	channel := os.Getenv("SNAPD_SNAPD_CHANNEL")
   140  	if channel == "" {
   141  		return "stable"
   142  	}
   143  	return channel
   144  }
   145  
   146  func defaultPrereqSnapsChannel() string {
   147  	channel := os.Getenv("SNAPD_PREREQS_CHANNEL")
   148  	if channel == "" {
   149  		return "stable"
   150  	}
   151  	return channel
   152  }
   153  
   154  func linkSnapInFlight(st *state.State, snapName string) (bool, error) {
   155  	for _, chg := range st.Changes() {
   156  		if chg.Status().Ready() {
   157  			continue
   158  		}
   159  		for _, tc := range chg.Tasks() {
   160  			if tc.Status().Ready() {
   161  				continue
   162  			}
   163  			if tc.Kind() == "link-snap" {
   164  				snapsup, err := TaskSnapSetup(tc)
   165  				if err != nil {
   166  					return false, err
   167  				}
   168  				if snapsup.InstanceName() == snapName {
   169  					return true, nil
   170  				}
   171  			}
   172  		}
   173  	}
   174  
   175  	return false, nil
   176  }
   177  
   178  func isInstalled(st *state.State, snapName string) (bool, error) {
   179  	var snapState SnapState
   180  	err := Get(st, snapName, &snapState)
   181  	if err != nil && err != state.ErrNoState {
   182  		return false, err
   183  	}
   184  	return snapState.IsInstalled(), nil
   185  }
   186  
   187  // timeout for tasks to check if the prerequisites are ready
   188  var prerequisitesRetryTimeout = 30 * time.Second
   189  
   190  func (m *SnapManager) doPrerequisites(t *state.Task, _ *tomb.Tomb) error {
   191  	st := t.State()
   192  	st.Lock()
   193  	defer st.Unlock()
   194  
   195  	perfTimings := timings.NewForTask(t)
   196  	defer perfTimings.Save(st)
   197  
   198  	// check if we need to inject tasks to install core
   199  	snapsup, _, err := snapSetupAndState(t)
   200  	if err != nil {
   201  		return err
   202  	}
   203  
   204  	// os/base/kernel/gadget cannot have prerequisites other
   205  	// than the models default base (or core) which is installed anyway
   206  	switch snapsup.Type {
   207  	case snap.TypeOS, snap.TypeBase, snap.TypeKernel, snap.TypeGadget:
   208  		return nil
   209  	}
   210  	// snapd is special and has no prereqs
   211  	if snapsup.Type == snap.TypeSnapd {
   212  		return nil
   213  	}
   214  
   215  	// we need to make sure we install all prereqs together in one
   216  	// operation
   217  	base := defaultCoreSnapName
   218  	if snapsup.Base != "" {
   219  		base = snapsup.Base
   220  	}
   221  
   222  	if err := m.installPrereqs(t, base, snapsup.Prereq, snapsup.UserID, perfTimings); err != nil {
   223  		return err
   224  	}
   225  
   226  	return nil
   227  }
   228  
   229  func (m *SnapManager) installOneBaseOrRequired(st *state.State, snapName string, requireTypeBase bool, channel string, onInFlight error, userID int) (*state.TaskSet, error) {
   230  	// The core snap provides everything we need for core16.
   231  	coreInstalled, err := isInstalled(st, "core")
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  	if snapName == "core16" && coreInstalled {
   236  		return nil, nil
   237  	}
   238  
   239  	// installed already?
   240  	isInstalled, err := isInstalled(st, snapName)
   241  	if err != nil {
   242  		return nil, err
   243  	}
   244  	if isInstalled {
   245  		return nil, nil
   246  	}
   247  	// in progress?
   248  	inFlight, err := linkSnapInFlight(st, snapName)
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  	if inFlight {
   253  		return nil, onInFlight
   254  	}
   255  
   256  	// not installed, nor queued for install -> install it
   257  	ts, err := Install(context.TODO(), st, snapName, &RevisionOptions{Channel: channel}, userID, Flags{RequireTypeBase: requireTypeBase})
   258  
   259  	// something might have triggered an explicit install while
   260  	// the state was unlocked -> deal with that here by simply
   261  	// retrying the operation.
   262  	if _, ok := err.(*ChangeConflictError); ok {
   263  		return nil, &state.Retry{After: prerequisitesRetryTimeout}
   264  	}
   265  	return ts, err
   266  }
   267  
   268  func (m *SnapManager) installPrereqs(t *state.Task, base string, prereq []string, userID int, tm timings.Measurer) error {
   269  	st := t.State()
   270  
   271  	// We try to install all wanted snaps. If one snap cannot be installed
   272  	// because of change conflicts or similar we retry. Only if all snaps
   273  	// can be installed together we add the tasks to the change.
   274  	var tss []*state.TaskSet
   275  	for _, prereqName := range prereq {
   276  		var onInFlightErr error = nil
   277  		var err error
   278  		var ts *state.TaskSet
   279  		timings.Run(tm, "install-prereq", fmt.Sprintf("install %q", prereqName), func(timings.Measurer) {
   280  			noTypeBaseCheck := false
   281  			ts, err = m.installOneBaseOrRequired(st, prereqName, noTypeBaseCheck, defaultPrereqSnapsChannel(), onInFlightErr, userID)
   282  		})
   283  		if err != nil {
   284  			return err
   285  		}
   286  		if ts == nil {
   287  			continue
   288  		}
   289  		tss = append(tss, ts)
   290  	}
   291  
   292  	// for base snaps we need to wait until the change is done
   293  	// (either finished or failed)
   294  	onInFlightErr := &state.Retry{After: prerequisitesRetryTimeout}
   295  
   296  	var tsBase *state.TaskSet
   297  	var err error
   298  	if base != "none" {
   299  		timings.Run(tm, "install-prereq", fmt.Sprintf("install base %q", base), func(timings.Measurer) {
   300  			requireTypeBase := true
   301  			tsBase, err = m.installOneBaseOrRequired(st, base, requireTypeBase, defaultBaseSnapsChannel(), onInFlightErr, userID)
   302  		})
   303  		if err != nil {
   304  			return err
   305  		}
   306  	}
   307  
   308  	// on systems without core or snapd need to install snapd to
   309  	// make interfaces work - LP: 1819318
   310  	var tsSnapd *state.TaskSet
   311  	snapdSnapInstalled, err := isInstalled(st, "snapd")
   312  	if err != nil {
   313  		return err
   314  	}
   315  	coreSnapInstalled, err := isInstalled(st, "core")
   316  	if err != nil {
   317  		return err
   318  	}
   319  	if base != "core" && !snapdSnapInstalled && !coreSnapInstalled {
   320  		timings.Run(tm, "install-prereq", "install snapd", func(timings.Measurer) {
   321  			noTypeBaseCheck := false
   322  			tsSnapd, err = m.installOneBaseOrRequired(st, "snapd", noTypeBaseCheck, defaultSnapdSnapsChannel(), onInFlightErr, userID)
   323  		})
   324  		if err != nil {
   325  			return err
   326  		}
   327  	}
   328  
   329  	chg := t.Change()
   330  	// add all required snaps, no ordering, this will be done in the
   331  	// auto-connect task handler
   332  	for _, ts := range tss {
   333  		ts.JoinLane(st.NewLane())
   334  		chg.AddAll(ts)
   335  	}
   336  	// add the base if needed, prereqs else must wait on this
   337  	if tsBase != nil {
   338  		tsBase.JoinLane(st.NewLane())
   339  		for _, t := range chg.Tasks() {
   340  			t.WaitAll(tsBase)
   341  		}
   342  		chg.AddAll(tsBase)
   343  	}
   344  	// add snapd if needed, everything must wait on this
   345  	if tsSnapd != nil {
   346  		tsSnapd.JoinLane(st.NewLane())
   347  		for _, t := range chg.Tasks() {
   348  			t.WaitAll(tsSnapd)
   349  		}
   350  		chg.AddAll(tsSnapd)
   351  	}
   352  
   353  	// make sure that the new change is committed to the state
   354  	// together with marking this task done
   355  	t.SetStatus(state.DoneStatus)
   356  
   357  	return nil
   358  }
   359  
   360  func (m *SnapManager) doPrepareSnap(t *state.Task, _ *tomb.Tomb) error {
   361  	st := t.State()
   362  	st.Lock()
   363  	defer st.Unlock()
   364  	snapsup, snapst, err := snapSetupAndState(t)
   365  	if err != nil {
   366  		return err
   367  	}
   368  
   369  	if snapsup.Revision().Unset() {
   370  		// Local revisions start at -1 and go down.
   371  		revision := snapst.LocalRevision()
   372  		if revision.Unset() || revision.N > 0 {
   373  			revision = snap.R(-1)
   374  		} else {
   375  			revision.N--
   376  		}
   377  		if !revision.Local() {
   378  			panic("internal error: invalid local revision built: " + revision.String())
   379  		}
   380  		snapsup.SideInfo.Revision = revision
   381  	}
   382  
   383  	t.Set("snap-setup", snapsup)
   384  	return nil
   385  }
   386  
   387  func (m *SnapManager) undoPrepareSnap(t *state.Task, _ *tomb.Tomb) error {
   388  	st := t.State()
   389  	st.Lock()
   390  	defer st.Unlock()
   391  
   392  	snapsup, err := TaskSnapSetup(t)
   393  	if err != nil {
   394  		return err
   395  	}
   396  
   397  	if snapsup.SideInfo == nil || snapsup.SideInfo.RealName == "" {
   398  		return nil
   399  	}
   400  
   401  	var logMsg []string
   402  	var snapSetup string
   403  	dupSig := []string{"snap-install:"}
   404  	chg := t.Change()
   405  	logMsg = append(logMsg, fmt.Sprintf("change %q: %q", chg.Kind(), chg.Summary()))
   406  	for _, t := range chg.Tasks() {
   407  		// TODO: report only tasks in intersecting lanes?
   408  		tintro := fmt.Sprintf("%s: %s", t.Kind(), t.Status())
   409  		logMsg = append(logMsg, tintro)
   410  		dupSig = append(dupSig, tintro)
   411  		if snapsup, err := TaskSnapSetup(t); err == nil && snapsup.SideInfo != nil {
   412  			snapSetup1 := fmt.Sprintf(" snap-setup: %q (%v) %q", snapsup.SideInfo.RealName, snapsup.SideInfo.Revision, snapsup.SideInfo.Channel)
   413  			if snapSetup1 != snapSetup {
   414  				snapSetup = snapSetup1
   415  				logMsg = append(logMsg, snapSetup)
   416  				dupSig = append(dupSig, fmt.Sprintf(" snap-setup: %q", snapsup.SideInfo.RealName))
   417  			}
   418  		}
   419  		for _, l := range t.Log() {
   420  			// cut of the rfc339 timestamp to ensure duplicate
   421  			// detection works in daisy
   422  			tStampLen := strings.Index(l, " ")
   423  			if tStampLen < 0 {
   424  				continue
   425  			}
   426  			// not tStampLen+1 because the indent is nice
   427  			entry := l[tStampLen:]
   428  			logMsg = append(logMsg, entry)
   429  			dupSig = append(dupSig, entry)
   430  		}
   431  	}
   432  
   433  	var ubuntuCoreTransitionCount int
   434  	err = st.Get("ubuntu-core-transition-retry", &ubuntuCoreTransitionCount)
   435  	if err != nil && err != state.ErrNoState {
   436  		return err
   437  	}
   438  	extra := map[string]string{
   439  		"Channel":  snapsup.Channel,
   440  		"Revision": snapsup.SideInfo.Revision.String(),
   441  	}
   442  	if ubuntuCoreTransitionCount > 0 {
   443  		extra["UbuntuCoreTransitionCount"] = strconv.Itoa(ubuntuCoreTransitionCount)
   444  	}
   445  
   446  	// Only report and error if there is an actual error in the change,
   447  	// we could undo things because the user canceled the change.
   448  	var isErr bool
   449  	for _, tt := range t.Change().Tasks() {
   450  		if tt.Status() == state.ErrorStatus {
   451  			isErr = true
   452  			break
   453  		}
   454  	}
   455  	if isErr && !settings.ProblemReportsDisabled(st) {
   456  		st.Unlock()
   457  		oopsid, err := errtrackerReport(snapsup.SideInfo.RealName, strings.Join(logMsg, "\n"), strings.Join(dupSig, "\n"), extra)
   458  		st.Lock()
   459  		if err == nil {
   460  			logger.Noticef("Reported install problem for %q as %s", snapsup.SideInfo.RealName, oopsid)
   461  		} else {
   462  			logger.Debugf("Cannot report problem: %s", err)
   463  		}
   464  	}
   465  
   466  	return nil
   467  }
   468  
   469  func installInfoUnlocked(st *state.State, snapsup *SnapSetup, deviceCtx DeviceContext) (*snap.Info, error) {
   470  	st.Lock()
   471  	defer st.Unlock()
   472  	opts := &RevisionOptions{Channel: snapsup.Channel, CohortKey: snapsup.CohortKey, Revision: snapsup.Revision()}
   473  	return installInfo(context.TODO(), st, snapsup.InstanceName(), opts, snapsup.UserID, deviceCtx)
   474  }
   475  
   476  // autoRefreshRateLimited returns the rate limit of auto-refreshes or 0 if
   477  // there is no limit.
   478  func autoRefreshRateLimited(st *state.State) (rate int64) {
   479  	tr := config.NewTransaction(st)
   480  
   481  	var rateLimit string
   482  	err := tr.Get("core", "refresh.rate-limit", &rateLimit)
   483  	if err != nil {
   484  		return 0
   485  	}
   486  	// NOTE ParseByteSize errors on negative rates
   487  	val, err := strutil.ParseByteSize(rateLimit)
   488  	if err != nil {
   489  		return 0
   490  	}
   491  	return val
   492  }
   493  
   494  func downloadSnapParams(st *state.State, t *state.Task) (*SnapSetup, StoreService, *auth.UserState, error) {
   495  	snapsup, err := TaskSnapSetup(t)
   496  	if err != nil {
   497  		return nil, nil, nil, err
   498  	}
   499  
   500  	deviceCtx, err := DeviceCtx(st, t, nil)
   501  	if err != nil {
   502  		return nil, nil, nil, err
   503  	}
   504  
   505  	sto := Store(st, deviceCtx)
   506  
   507  	user, err := userFromUserID(st, snapsup.UserID)
   508  	if err != nil {
   509  		return nil, nil, nil, err
   510  	}
   511  
   512  	return snapsup, sto, user, nil
   513  }
   514  
   515  func (m *SnapManager) doDownloadSnap(t *state.Task, tomb *tomb.Tomb) error {
   516  	st := t.State()
   517  	var rate int64
   518  
   519  	st.Lock()
   520  	perfTimings := timings.NewForTask(t)
   521  	snapsup, theStore, user, err := downloadSnapParams(st, t)
   522  	if snapsup != nil && snapsup.IsAutoRefresh {
   523  		// NOTE rate is never negative
   524  		rate = autoRefreshRateLimited(st)
   525  	}
   526  	st.Unlock()
   527  	if err != nil {
   528  		return err
   529  	}
   530  
   531  	meter := NewTaskProgressAdapterUnlocked(t)
   532  	targetFn := snapsup.MountFile()
   533  
   534  	dlOpts := &store.DownloadOptions{
   535  		IsAutoRefresh: snapsup.IsAutoRefresh,
   536  		RateLimit:     rate,
   537  	}
   538  	if snapsup.DownloadInfo == nil {
   539  		var storeInfo *snap.Info
   540  		// COMPATIBILITY - this task was created from an older version
   541  		// of snapd that did not store the DownloadInfo in the state
   542  		// yet. Therefore do not worry about DeviceContext.
   543  		storeInfo, err = installInfoUnlocked(st, snapsup, nil)
   544  		if err != nil {
   545  			return err
   546  		}
   547  		timings.Run(perfTimings, "download", fmt.Sprintf("download snap %q", snapsup.SnapName()), func(timings.Measurer) {
   548  			err = theStore.Download(tomb.Context(nil), snapsup.SnapName(), targetFn, &storeInfo.DownloadInfo, meter, user, dlOpts)
   549  		})
   550  		snapsup.SideInfo = &storeInfo.SideInfo
   551  	} else {
   552  		timings.Run(perfTimings, "download", fmt.Sprintf("download snap %q", snapsup.SnapName()), func(timings.Measurer) {
   553  			err = theStore.Download(tomb.Context(nil), snapsup.SnapName(), targetFn, snapsup.DownloadInfo, meter, user, dlOpts)
   554  		})
   555  	}
   556  	if err != nil {
   557  		return err
   558  	}
   559  
   560  	snapsup.SnapPath = targetFn
   561  
   562  	// update the snap setup for the follow up tasks
   563  	st.Lock()
   564  	t.Set("snap-setup", snapsup)
   565  	perfTimings.Save(st)
   566  	st.Unlock()
   567  
   568  	return nil
   569  }
   570  
   571  var (
   572  	mountPollInterval = 1 * time.Second
   573  )
   574  
   575  // hasOtherInstances checks whether there are other instances of the snap, be it
   576  // instance keyed or not
   577  func hasOtherInstances(st *state.State, instanceName string) (bool, error) {
   578  	snapName, _ := snap.SplitInstanceName(instanceName)
   579  	var all map[string]*json.RawMessage
   580  	if err := st.Get("snaps", &all); err != nil && err != state.ErrNoState {
   581  		return false, err
   582  	}
   583  	for otherName := range all {
   584  		if otherName == instanceName {
   585  			continue
   586  		}
   587  		if otherSnapName, _ := snap.SplitInstanceName(otherName); otherSnapName == snapName {
   588  			return true, nil
   589  		}
   590  	}
   591  	return false, nil
   592  }
   593  
   594  func (m *SnapManager) doMountSnap(t *state.Task, _ *tomb.Tomb) error {
   595  	st := t.State()
   596  	st.Lock()
   597  	perfTimings := timings.NewForTask(t)
   598  	snapsup, snapst, err := snapSetupAndState(t)
   599  	st.Unlock()
   600  	if err != nil {
   601  		return err
   602  	}
   603  
   604  	curInfo, err := snapst.CurrentInfo()
   605  	if err != nil && err != ErrNoCurrent {
   606  		return err
   607  	}
   608  
   609  	m.backend.CurrentInfo(curInfo)
   610  
   611  	st.Lock()
   612  	deviceCtx, err := DeviceCtx(t.State(), t, nil)
   613  	st.Unlock()
   614  	if err != nil {
   615  		return err
   616  	}
   617  
   618  	timings.Run(perfTimings, "check-snap", fmt.Sprintf("check snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   619  		err = checkSnap(st, snapsup.SnapPath, snapsup.InstanceName(), snapsup.SideInfo, curInfo, snapsup.Flags, deviceCtx)
   620  	})
   621  	if err != nil {
   622  		return err
   623  	}
   624  
   625  	cleanup := func() {
   626  		st.Lock()
   627  		defer st.Unlock()
   628  
   629  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   630  		if err != nil {
   631  			t.Errorf("cannot cleanup partial setup snap %q: %v", snapsup.InstanceName(), err)
   632  			return
   633  		}
   634  
   635  		// remove snap dir is idempotent so it's ok to always call it in the cleanup path
   636  		if err := m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances); err != nil {
   637  			t.Errorf("cannot cleanup partial setup snap %q: %v", snapsup.InstanceName(), err)
   638  		}
   639  
   640  	}
   641  
   642  	pb := NewTaskProgressAdapterUnlocked(t)
   643  	// TODO Use snapsup.Revision() to obtain the right info to mount
   644  	//      instead of assuming the candidate is the right one.
   645  	var snapType snap.Type
   646  	timings.Run(perfTimings, "setup-snap", fmt.Sprintf("setup snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   647  		snapType, err = m.backend.SetupSnap(snapsup.SnapPath, snapsup.InstanceName(), snapsup.SideInfo, pb)
   648  	})
   649  	if err != nil {
   650  		cleanup()
   651  		return err
   652  	}
   653  
   654  	// double check that the snap is mounted
   655  	var readInfoErr error
   656  	for i := 0; i < 10; i++ {
   657  		_, readInfoErr = readInfo(snapsup.InstanceName(), snapsup.SideInfo, errorOnBroken)
   658  		if readInfoErr == nil {
   659  			break
   660  		}
   661  		if _, ok := readInfoErr.(*snap.NotFoundError); !ok {
   662  			break
   663  		}
   664  		// snap not found, seems is not mounted yet
   665  		msg := fmt.Sprintf("expected snap %q revision %v to be mounted but is not", snapsup.InstanceName(), snapsup.Revision())
   666  		readInfoErr = fmt.Errorf("cannot proceed, %s", msg)
   667  		if i == 0 {
   668  			logger.Noticef(msg)
   669  		}
   670  		time.Sleep(mountPollInterval)
   671  	}
   672  	if readInfoErr != nil {
   673  		timings.Run(perfTimings, "undo-setup-snap", fmt.Sprintf("Undo setup of snap %q", snapsup.InstanceName()), func(timings.Measurer) {
   674  			err = m.backend.UndoSetupSnap(snapsup.placeInfo(), snapType, pb)
   675  		})
   676  		if err != nil {
   677  			st.Lock()
   678  			t.Errorf("cannot undo partial setup snap %q: %v", snapsup.InstanceName(), err)
   679  			st.Unlock()
   680  		}
   681  
   682  		cleanup()
   683  		return readInfoErr
   684  	}
   685  
   686  	st.Lock()
   687  	// set snapst type for undoMountSnap
   688  	t.Set("snap-type", snapType)
   689  	st.Unlock()
   690  
   691  	if snapsup.Flags.RemoveSnapPath {
   692  		if err := os.Remove(snapsup.SnapPath); err != nil {
   693  			logger.Noticef("Failed to cleanup %s: %s", snapsup.SnapPath, err)
   694  		}
   695  	}
   696  
   697  	st.Lock()
   698  	perfTimings.Save(st)
   699  	st.Unlock()
   700  
   701  	return nil
   702  }
   703  
   704  func (m *SnapManager) undoMountSnap(t *state.Task, _ *tomb.Tomb) error {
   705  	st := t.State()
   706  	st.Lock()
   707  	snapsup, err := TaskSnapSetup(t)
   708  	st.Unlock()
   709  	if err != nil {
   710  		return err
   711  	}
   712  
   713  	st.Lock()
   714  	var typ snap.Type
   715  	err = t.Get("snap-type", &typ)
   716  	st.Unlock()
   717  	// backward compatibility
   718  	if err == state.ErrNoState {
   719  		typ = "app"
   720  	} else if err != nil {
   721  		return err
   722  	}
   723  
   724  	pb := NewTaskProgressAdapterUnlocked(t)
   725  	if err := m.backend.UndoSetupSnap(snapsup.placeInfo(), typ, pb); err != nil {
   726  		return err
   727  	}
   728  
   729  	st.Lock()
   730  	defer st.Unlock()
   731  
   732  	otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   733  	if err != nil {
   734  		return err
   735  	}
   736  
   737  	return m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances)
   738  }
   739  
   740  func (m *SnapManager) doUnlinkCurrentSnap(t *state.Task, _ *tomb.Tomb) error {
   741  	st := t.State()
   742  	st.Lock()
   743  	defer st.Unlock()
   744  
   745  	snapsup, snapst, err := snapSetupAndState(t)
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	oldInfo, err := snapst.CurrentInfo()
   751  	if err != nil {
   752  		return err
   753  	}
   754  
   755  	tr := config.NewTransaction(st)
   756  	experimentalRefreshAppAwareness, err := config.GetFeatureFlag(tr, features.RefreshAppAwareness)
   757  	if err != nil && !config.IsNoOption(err) {
   758  		return err
   759  	}
   760  
   761  	if experimentalRefreshAppAwareness {
   762  		// A process may be created after the soft refresh done upon
   763  		// the request to refresh a snap. If such process is alive by
   764  		// the time this code is reached the refresh process is stopped.
   765  		// In case of failure the snap state is modified to indicate
   766  		// when the refresh was first inhibited. If the first
   767  		// inhibition is outside of a grace period then refresh
   768  		// proceeds regardless of the existing processes.
   769  		if err := inhibitRefresh(st, snapst, oldInfo, HardNothingRunningRefreshCheck); err != nil {
   770  			return err
   771  		}
   772  	}
   773  
   774  	snapst.Active = false
   775  
   776  	pb := NewTaskProgressAdapterLocked(t)
   777  	err = m.backend.UnlinkSnap(oldInfo, pb)
   778  	if err != nil {
   779  		return err
   780  	}
   781  
   782  	// mark as inactive
   783  	Set(st, snapsup.InstanceName(), snapst)
   784  	return nil
   785  }
   786  
   787  func (m *SnapManager) undoUnlinkCurrentSnap(t *state.Task, _ *tomb.Tomb) error {
   788  	st := t.State()
   789  	st.Lock()
   790  	defer st.Unlock()
   791  
   792  	perfTimings := timings.NewForTask(t)
   793  	defer perfTimings.Save(st)
   794  
   795  	snapsup, snapst, err := snapSetupAndState(t)
   796  	if err != nil {
   797  		return err
   798  	}
   799  
   800  	oldInfo, err := snapst.CurrentInfo()
   801  	if err != nil {
   802  		return err
   803  	}
   804  
   805  	model, err := ModelFromTask(t)
   806  	if err != nil && err != state.ErrNoState {
   807  		return err
   808  	}
   809  
   810  	snapst.Active = true
   811  	err = m.backend.LinkSnap(oldInfo, model, perfTimings)
   812  	if err != nil {
   813  		return err
   814  	}
   815  
   816  	// mark as active again
   817  	Set(st, snapsup.InstanceName(), snapst)
   818  
   819  	// if we just put back a previous a core snap, request a restart
   820  	// so that we switch executing its snapd
   821  	maybeRestart(t, oldInfo)
   822  
   823  	return nil
   824  }
   825  
   826  func (m *SnapManager) doCopySnapData(t *state.Task, _ *tomb.Tomb) error {
   827  	st := t.State()
   828  	st.Lock()
   829  	snapsup, snapst, err := snapSetupAndState(t)
   830  	st.Unlock()
   831  	if err != nil {
   832  		return err
   833  	}
   834  
   835  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
   836  	if err != nil {
   837  		return err
   838  	}
   839  
   840  	oldInfo, err := snapst.CurrentInfo()
   841  	if err != nil && err != ErrNoCurrent {
   842  		return err
   843  	}
   844  
   845  	pb := NewTaskProgressAdapterUnlocked(t)
   846  	if copyDataErr := m.backend.CopySnapData(newInfo, oldInfo, pb); copyDataErr != nil {
   847  		if oldInfo != nil {
   848  			// there is another revision of the snap, cannot remove
   849  			// shared data directory
   850  			return copyDataErr
   851  		}
   852  
   853  		// cleanup shared snap data directory
   854  		st.Lock()
   855  		defer st.Unlock()
   856  
   857  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   858  		if err != nil {
   859  			t.Errorf("cannot undo partial snap %q data copy: %v", snapsup.InstanceName(), err)
   860  			return copyDataErr
   861  		}
   862  		// no other instances of this snap, shared data directory can be
   863  		// removed now too
   864  		if err := m.backend.RemoveSnapDataDir(newInfo, otherInstances); err != nil {
   865  			t.Errorf("cannot undo partial snap %q data copy, failed removing shared directory: %v", snapsup.InstanceName(), err)
   866  		}
   867  		return copyDataErr
   868  	}
   869  	return nil
   870  }
   871  
   872  func (m *SnapManager) undoCopySnapData(t *state.Task, _ *tomb.Tomb) error {
   873  	st := t.State()
   874  	st.Lock()
   875  	snapsup, snapst, err := snapSetupAndState(t)
   876  	st.Unlock()
   877  	if err != nil {
   878  		return err
   879  	}
   880  
   881  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
   882  	if err != nil {
   883  		return err
   884  	}
   885  
   886  	oldInfo, err := snapst.CurrentInfo()
   887  	if err != nil && err != ErrNoCurrent {
   888  		return err
   889  	}
   890  
   891  	pb := NewTaskProgressAdapterUnlocked(t)
   892  	if err := m.backend.UndoCopySnapData(newInfo, oldInfo, pb); err != nil {
   893  		return err
   894  	}
   895  
   896  	if oldInfo != nil {
   897  		// there is other revision of this snap, cannot remove shared
   898  		// directory anyway
   899  		return nil
   900  	}
   901  
   902  	st.Lock()
   903  	defer st.Unlock()
   904  
   905  	otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
   906  	if err != nil {
   907  		return err
   908  	}
   909  	// no other instances of this snap and no other revisions, shared data
   910  	// directory can be removed
   911  	if err := m.backend.RemoveSnapDataDir(newInfo, otherInstances); err != nil {
   912  		return err
   913  	}
   914  	return nil
   915  }
   916  
   917  func (m *SnapManager) cleanupCopySnapData(t *state.Task, _ *tomb.Tomb) error {
   918  	st := t.State()
   919  	st.Lock()
   920  	defer st.Unlock()
   921  
   922  	if t.Status() != state.DoneStatus {
   923  		// it failed
   924  		return nil
   925  	}
   926  
   927  	_, snapst, err := snapSetupAndState(t)
   928  	if err != nil {
   929  		return err
   930  	}
   931  
   932  	info, err := snapst.CurrentInfo()
   933  	if err != nil {
   934  		return err
   935  	}
   936  
   937  	m.backend.ClearTrashedData(info)
   938  
   939  	return nil
   940  }
   941  
   942  // writeSeqFile writes the sequence file for failover handling
   943  func writeSeqFile(name string, snapst *SnapState) error {
   944  	p := filepath.Join(dirs.SnapSeqDir, name+".json")
   945  	if err := os.MkdirAll(filepath.Dir(p), 0755); err != nil {
   946  		return err
   947  	}
   948  
   949  	b, err := json.Marshal(&struct {
   950  		Sequence []*snap.SideInfo `json:"sequence"`
   951  		Current  string           `json:"current"`
   952  	}{
   953  		Sequence: snapst.Sequence,
   954  		Current:  snapst.Current.String(),
   955  	})
   956  	if err != nil {
   957  		return err
   958  	}
   959  
   960  	return osutil.AtomicWriteFile(p, b, 0644, 0)
   961  }
   962  
   963  func (m *SnapManager) doLinkSnap(t *state.Task, _ *tomb.Tomb) (err error) {
   964  	st := t.State()
   965  	st.Lock()
   966  	defer st.Unlock()
   967  
   968  	perfTimings := timings.NewForTask(t)
   969  	defer perfTimings.Save(st)
   970  
   971  	snapsup, snapst, err := snapSetupAndState(t)
   972  	if err != nil {
   973  		return err
   974  	}
   975  
   976  	// find if the snap is already installed before we modify snapst below
   977  	isInstalled := snapst.IsInstalled()
   978  
   979  	cand := snapsup.SideInfo
   980  	m.backend.Candidate(cand)
   981  
   982  	oldCandidateIndex := snapst.LastIndex(cand.Revision)
   983  
   984  	if oldCandidateIndex < 0 {
   985  		snapst.Sequence = append(snapst.Sequence, cand)
   986  	} else if !snapsup.Revert {
   987  		// remove the old candidate from the sequence, add it at the end
   988  		copy(snapst.Sequence[oldCandidateIndex:len(snapst.Sequence)-1], snapst.Sequence[oldCandidateIndex+1:])
   989  		snapst.Sequence[len(snapst.Sequence)-1] = cand
   990  	}
   991  
   992  	oldCurrent := snapst.Current
   993  	snapst.Current = cand.Revision
   994  	snapst.Active = true
   995  	oldChannel := snapst.Channel
   996  	if snapsup.Channel != "" {
   997  		snapst.Channel = snapsup.Channel
   998  	}
   999  	oldIgnoreValidation := snapst.IgnoreValidation
  1000  	snapst.IgnoreValidation = snapsup.IgnoreValidation
  1001  	oldTryMode := snapst.TryMode
  1002  	snapst.TryMode = snapsup.TryMode
  1003  	oldDevMode := snapst.DevMode
  1004  	snapst.DevMode = snapsup.DevMode
  1005  	oldJailMode := snapst.JailMode
  1006  	snapst.JailMode = snapsup.JailMode
  1007  	oldClassic := snapst.Classic
  1008  	snapst.Classic = snapsup.Classic
  1009  	oldCohortKey := snapst.CohortKey
  1010  	snapst.CohortKey = snapsup.CohortKey
  1011  	if snapsup.Required { // set only on install and left alone on refresh
  1012  		snapst.Required = true
  1013  	}
  1014  	oldRefreshInhibitedTime := snapst.RefreshInhibitedTime
  1015  	// only set userID if unset or logged out in snapst and if we
  1016  	// actually have an associated user
  1017  	if snapsup.UserID > 0 {
  1018  		var user *auth.UserState
  1019  		if snapst.UserID != 0 {
  1020  			user, err = auth.User(st, snapst.UserID)
  1021  			if err != nil && err != auth.ErrInvalidUser {
  1022  				return err
  1023  			}
  1024  		}
  1025  		if user == nil {
  1026  			// if the original user installing the snap is
  1027  			// no longer available transfer to user who
  1028  			// triggered this change
  1029  			snapst.UserID = snapsup.UserID
  1030  		}
  1031  	}
  1032  	// keep instance key
  1033  	snapst.InstanceKey = snapsup.InstanceKey
  1034  
  1035  	newInfo, err := readInfo(snapsup.InstanceName(), cand, 0)
  1036  	if err != nil {
  1037  		return err
  1038  	}
  1039  
  1040  	// record type
  1041  	snapst.SetType(newInfo.GetType())
  1042  
  1043  	// XXX: this block is slightly ugly, find a pattern when we have more examples
  1044  	model, _ := ModelFromTask(t)
  1045  	err = m.backend.LinkSnap(newInfo, model, perfTimings)
  1046  	if err != nil {
  1047  		pb := NewTaskProgressAdapterLocked(t)
  1048  		err := m.backend.UnlinkSnap(newInfo, pb)
  1049  		if err != nil {
  1050  			t.Errorf("cannot cleanup failed attempt at making snap %q available to the system: %v", snapsup.InstanceName(), err)
  1051  		}
  1052  	}
  1053  	if err != nil {
  1054  		return err
  1055  	}
  1056  
  1057  	if isInstalled {
  1058  		// Make a copy of configuration of current snap revision
  1059  		if err = config.SaveRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1060  			return err
  1061  		}
  1062  	}
  1063  
  1064  	// Restore configuration of the target revision (if available; nothing happens if it's not).
  1065  	// We only do this on reverts (and not on refreshes).
  1066  	if snapsup.Revert {
  1067  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  1068  			return err
  1069  		}
  1070  	}
  1071  
  1072  	if len(snapst.Sequence) == 1 {
  1073  		if err := m.createSnapCookie(st, snapsup.InstanceName()); err != nil {
  1074  			return fmt.Errorf("cannot create snap cookie: %v", err)
  1075  		}
  1076  	}
  1077  	// save for undoLinkSnap
  1078  	t.Set("old-trymode", oldTryMode)
  1079  	t.Set("old-devmode", oldDevMode)
  1080  	t.Set("old-jailmode", oldJailMode)
  1081  	t.Set("old-classic", oldClassic)
  1082  	t.Set("old-ignore-validation", oldIgnoreValidation)
  1083  	t.Set("old-channel", oldChannel)
  1084  	t.Set("old-current", oldCurrent)
  1085  	t.Set("old-candidate-index", oldCandidateIndex)
  1086  	t.Set("old-refresh-inhibited-time", oldRefreshInhibitedTime)
  1087  	t.Set("old-cohort-key", oldCohortKey)
  1088  
  1089  	// Record the fact that the snap was refreshed successfully.
  1090  	snapst.RefreshInhibitedTime = nil
  1091  
  1092  	// Do at the end so we only preserve the new state if it worked.
  1093  	Set(st, snapsup.InstanceName(), snapst)
  1094  
  1095  	if cand.SnapID != "" {
  1096  		// write the auxiliary store info
  1097  		aux := &auxStoreInfo{Media: snapsup.Media}
  1098  		if err := keepAuxStoreInfo(cand.SnapID, aux); err != nil {
  1099  			return err
  1100  		}
  1101  		if len(snapst.Sequence) == 1 {
  1102  			defer func() {
  1103  				if err != nil {
  1104  					// the install is getting undone, and there are no more of this snap
  1105  					// try to remove the aux info we just created
  1106  					discardAuxStoreInfo(cand.SnapID)
  1107  				}
  1108  			}()
  1109  		}
  1110  	}
  1111  
  1112  	// write sequence file for failover helpers
  1113  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1114  		return err
  1115  	}
  1116  
  1117  	// Compatibility with old snapd: check if we have auto-connect task and
  1118  	// if not, inject it after self (link-snap) for snaps that are not core
  1119  	if newInfo.GetType() != snap.TypeOS {
  1120  		var hasAutoConnect, hasSetupProfiles bool
  1121  		for _, other := range t.Change().Tasks() {
  1122  			// Check if this is auto-connect task for same snap and we it's part of the change with setup-profiles task
  1123  			if other.Kind() == "auto-connect" || other.Kind() == "setup-profiles" {
  1124  				otherSnapsup, err := TaskSnapSetup(other)
  1125  				if err != nil {
  1126  					return err
  1127  				}
  1128  				if snapsup.InstanceName() == otherSnapsup.InstanceName() {
  1129  					if other.Kind() == "auto-connect" {
  1130  						hasAutoConnect = true
  1131  					} else {
  1132  						hasSetupProfiles = true
  1133  					}
  1134  				}
  1135  			}
  1136  		}
  1137  		if !hasAutoConnect && hasSetupProfiles {
  1138  			InjectAutoConnect(t, snapsup)
  1139  		}
  1140  	}
  1141  
  1142  	// Make sure if state commits and snapst is mutated we won't be rerun
  1143  	t.SetStatus(state.DoneStatus)
  1144  
  1145  	// if we just installed a core snap, request a restart
  1146  	// so that we switch executing its snapd
  1147  	maybeRestart(t, newInfo)
  1148  
  1149  	return nil
  1150  }
  1151  
  1152  // maybeRestart will schedule a reboot or restart as needed for the
  1153  // just linked snap with info if it's a core or snapd or kernel snap.
  1154  func maybeRestart(t *state.Task, info *snap.Info) {
  1155  	st := t.State()
  1156  
  1157  	model, err := ModelFromTask(t)
  1158  	if err != nil {
  1159  		logger.Noticef("cannot get model assertion: %v", model)
  1160  		return
  1161  	}
  1162  
  1163  	typ := info.GetType()
  1164  	bp := boot.Participant(info, typ, model, release.OnClassic)
  1165  	if bp.ChangeRequiresReboot() {
  1166  		t.Logf("Requested system restart.")
  1167  		st.RequestRestart(state.RestartSystem)
  1168  		return
  1169  	}
  1170  
  1171  	// if bp is non-trivial then either we're not on classic, or the snap is
  1172  	// snapd. So daemonRestartReason will always return "" which is what we
  1173  	// want. If that combination stops being true and there's a situation
  1174  	// where a non-trivial bp could return a non-empty reason, use IsTrivial
  1175  	// to check and bail before reaching this far.
  1176  
  1177  	restartReason := daemonRestartReason(st, typ)
  1178  	if restartReason == "" {
  1179  		// no message -> no restart
  1180  		return
  1181  	}
  1182  
  1183  	t.Logf(restartReason)
  1184  	st.RequestRestart(state.RestartDaemon)
  1185  }
  1186  
  1187  func daemonRestartReason(st *state.State, typ snap.Type) string {
  1188  	if !((release.OnClassic && typ == snap.TypeOS) || typ == snap.TypeSnapd) {
  1189  		// not interesting
  1190  		return ""
  1191  	}
  1192  
  1193  	if typ == snap.TypeOS {
  1194  		// ignore error here as we have no way to return to caller
  1195  		snapdSnapInstalled, _ := isInstalled(st, "snapd")
  1196  		if snapdSnapInstalled {
  1197  			// this snap is the base, but snapd is running from the snapd snap
  1198  			return ""
  1199  		}
  1200  		return "Requested daemon restart."
  1201  	}
  1202  
  1203  	return "Requested daemon restart (snapd snap)."
  1204  }
  1205  
  1206  func (m *SnapManager) undoLinkSnap(t *state.Task, _ *tomb.Tomb) error {
  1207  	st := t.State()
  1208  	st.Lock()
  1209  	defer st.Unlock()
  1210  
  1211  	perfTimings := timings.NewForTask(t)
  1212  	defer perfTimings.Save(st)
  1213  
  1214  	snapsup, snapst, err := snapSetupAndState(t)
  1215  	if err != nil {
  1216  		return err
  1217  	}
  1218  
  1219  	var oldChannel string
  1220  	err = t.Get("old-channel", &oldChannel)
  1221  	if err != nil {
  1222  		return err
  1223  	}
  1224  	var oldIgnoreValidation bool
  1225  	err = t.Get("old-ignore-validation", &oldIgnoreValidation)
  1226  	if err != nil && err != state.ErrNoState {
  1227  		return err
  1228  	}
  1229  	var oldTryMode bool
  1230  	err = t.Get("old-trymode", &oldTryMode)
  1231  	if err != nil {
  1232  		return err
  1233  	}
  1234  	var oldDevMode bool
  1235  	err = t.Get("old-devmode", &oldDevMode)
  1236  	if err != nil {
  1237  		return err
  1238  	}
  1239  	var oldJailMode bool
  1240  	err = t.Get("old-jailmode", &oldJailMode)
  1241  	if err != nil {
  1242  		return err
  1243  	}
  1244  	var oldClassic bool
  1245  	err = t.Get("old-classic", &oldClassic)
  1246  	if err != nil {
  1247  		return err
  1248  	}
  1249  	var oldCurrent snap.Revision
  1250  	err = t.Get("old-current", &oldCurrent)
  1251  	if err != nil {
  1252  		return err
  1253  	}
  1254  	var oldCandidateIndex int
  1255  	if err := t.Get("old-candidate-index", &oldCandidateIndex); err != nil {
  1256  		return err
  1257  	}
  1258  	var oldRefreshInhibitedTime *time.Time
  1259  	if err := t.Get("old-refresh-inhibited-time", &oldRefreshInhibitedTime); err != nil && err != state.ErrNoState {
  1260  		return err
  1261  	}
  1262  	var oldCohortKey string
  1263  	if err := t.Get("old-cohort-key", &oldCohortKey); err != nil && err != state.ErrNoState {
  1264  		return err
  1265  	}
  1266  
  1267  	if len(snapst.Sequence) == 1 {
  1268  		// XXX: shouldn't these two just log and carry on? this is an undo handler...
  1269  		timings.Run(perfTimings, "discard-snap-namespace", fmt.Sprintf("discard the namespace of snap %q", snapsup.InstanceName()), func(tm timings.Measurer) {
  1270  			err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  1271  		})
  1272  		if err != nil {
  1273  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  1274  			return &state.Retry{After: 3 * time.Minute}
  1275  		}
  1276  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  1277  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  1278  		}
  1279  		// try to remove the auxiliary store info
  1280  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  1281  			return fmt.Errorf("cannot remove auxiliary store info: %v", err)
  1282  		}
  1283  	}
  1284  
  1285  	isRevert := snapsup.Revert
  1286  
  1287  	// relinking of the old snap is done in the undo of unlink-current-snap
  1288  	currentIndex := snapst.LastIndex(snapst.Current)
  1289  	if currentIndex < 0 {
  1290  		return fmt.Errorf("internal error: cannot find revision %d in %v for undoing the added revision", snapsup.SideInfo.Revision, snapst.Sequence)
  1291  	}
  1292  
  1293  	if oldCandidateIndex < 0 {
  1294  		snapst.Sequence = append(snapst.Sequence[:currentIndex], snapst.Sequence[currentIndex+1:]...)
  1295  	} else if !isRevert {
  1296  		oldCand := snapst.Sequence[currentIndex]
  1297  		copy(snapst.Sequence[oldCandidateIndex+1:], snapst.Sequence[oldCandidateIndex:])
  1298  		snapst.Sequence[oldCandidateIndex] = oldCand
  1299  	}
  1300  	snapst.Current = oldCurrent
  1301  	snapst.Active = false
  1302  	snapst.Channel = oldChannel
  1303  	snapst.IgnoreValidation = oldIgnoreValidation
  1304  	snapst.TryMode = oldTryMode
  1305  	snapst.DevMode = oldDevMode
  1306  	snapst.JailMode = oldJailMode
  1307  	snapst.Classic = oldClassic
  1308  	snapst.RefreshInhibitedTime = oldRefreshInhibitedTime
  1309  	snapst.CohortKey = oldCohortKey
  1310  
  1311  	newInfo, err := readInfo(snapsup.InstanceName(), snapsup.SideInfo, 0)
  1312  	if err != nil {
  1313  		return err
  1314  	}
  1315  
  1316  	// we need to undo potential changes to current snap configuration (e.g. if modified by post-refresh/install/configure hooks
  1317  	// as part of failed refresh/install) by restoring the configuration of "old current".
  1318  	if len(snapst.Sequence) > 0 {
  1319  		if err = config.RestoreRevisionConfig(st, snapsup.InstanceName(), oldCurrent); err != nil {
  1320  			return err
  1321  		}
  1322  	}
  1323  	pb := NewTaskProgressAdapterLocked(t)
  1324  	err = m.backend.UnlinkSnap(newInfo, pb)
  1325  	if err != nil {
  1326  		return err
  1327  	}
  1328  
  1329  	// mark as inactive
  1330  	Set(st, snapsup.InstanceName(), snapst)
  1331  	// write sequence file for failover helpers
  1332  	if err := writeSeqFile(snapsup.InstanceName(), snapst); err != nil {
  1333  		return err
  1334  	}
  1335  	// Make sure if state commits and snapst is mutated we won't be rerun
  1336  	t.SetStatus(state.UndoneStatus)
  1337  
  1338  	// If we are on classic and have no previous version of core
  1339  	// we may have restarted from a distro package into the core
  1340  	// snap. We need to undo that restart here. Instead of in
  1341  	// doUnlinkCurrentSnap() like we usually do when going from
  1342  	// core snap -> next core snap
  1343  	if release.OnClassic && newInfo.GetType() == snap.TypeOS && oldCurrent.Unset() {
  1344  		t.Logf("Requested daemon restart (undo classic initial core install)")
  1345  		st.RequestRestart(state.RestartDaemon)
  1346  	}
  1347  	return nil
  1348  }
  1349  
  1350  type doSwitchFlags struct {
  1351  	switchCurrentChannel bool
  1352  }
  1353  
  1354  // doSwitchSnapChannel switches the snap's tracking channel and/or cohort. It
  1355  // also switches the current channel if appropriate. For use from 'Update'.
  1356  func (m *SnapManager) doSwitchSnapChannel(t *state.Task, _ *tomb.Tomb) error {
  1357  	return m.genericDoSwitchSnap(t, doSwitchFlags{switchCurrentChannel: true})
  1358  }
  1359  
  1360  // doSwitchSnap switches the snap's tracking channel and/or cohort, *without*
  1361  // switching the current snap channel. For use from 'Switch'.
  1362  func (m *SnapManager) doSwitchSnap(t *state.Task, _ *tomb.Tomb) error {
  1363  	return m.genericDoSwitchSnap(t, doSwitchFlags{})
  1364  }
  1365  
  1366  func (m *SnapManager) genericDoSwitchSnap(t *state.Task, flags doSwitchFlags) error {
  1367  	st := t.State()
  1368  	st.Lock()
  1369  	defer st.Unlock()
  1370  
  1371  	snapsup, snapst, err := snapSetupAndState(t)
  1372  	if err != nil {
  1373  		return err
  1374  	}
  1375  
  1376  	// switched the tracked channel
  1377  	snapst.Channel = snapsup.Channel
  1378  	snapst.CohortKey = snapsup.CohortKey
  1379  	if flags.switchCurrentChannel {
  1380  		// optionally support switching the current snap channel too, e.g.
  1381  		// if a snap is in both stable and candidate with the same revision
  1382  		// we can update it here and it will be displayed correctly in the UI
  1383  		if snapsup.SideInfo.Channel != "" {
  1384  			snapst.CurrentSideInfo().Channel = snapsup.Channel
  1385  		}
  1386  	}
  1387  
  1388  	Set(st, snapsup.InstanceName(), snapst)
  1389  	return nil
  1390  }
  1391  
  1392  func (m *SnapManager) doToggleSnapFlags(t *state.Task, _ *tomb.Tomb) error {
  1393  	st := t.State()
  1394  	st.Lock()
  1395  	defer st.Unlock()
  1396  
  1397  	snapsup, snapst, err := snapSetupAndState(t)
  1398  	if err != nil {
  1399  		return err
  1400  	}
  1401  
  1402  	// for now we support toggling only ignore-validation
  1403  	snapst.IgnoreValidation = snapsup.IgnoreValidation
  1404  
  1405  	Set(st, snapsup.InstanceName(), snapst)
  1406  	return nil
  1407  }
  1408  
  1409  func (m *SnapManager) startSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1410  	st := t.State()
  1411  	st.Lock()
  1412  	defer st.Unlock()
  1413  
  1414  	perfTimings := timings.NewForTask(t)
  1415  	defer perfTimings.Save(st)
  1416  
  1417  	_, snapst, err := snapSetupAndState(t)
  1418  	if err != nil {
  1419  		return err
  1420  	}
  1421  
  1422  	currentInfo, err := snapst.CurrentInfo()
  1423  	if err != nil {
  1424  		return err
  1425  	}
  1426  	svcs := currentInfo.Services()
  1427  	if len(svcs) == 0 {
  1428  		return nil
  1429  	}
  1430  
  1431  	startupOrdered, err := snap.SortServices(svcs)
  1432  	if err != nil {
  1433  		return err
  1434  	}
  1435  
  1436  	pb := NewTaskProgressAdapterUnlocked(t)
  1437  	st.Unlock()
  1438  	err = m.backend.StartServices(startupOrdered, pb, perfTimings)
  1439  	st.Lock()
  1440  	return err
  1441  }
  1442  
  1443  func (m *SnapManager) stopSnapServices(t *state.Task, _ *tomb.Tomb) error {
  1444  	st := t.State()
  1445  	st.Lock()
  1446  	defer st.Unlock()
  1447  
  1448  	perfTimings := timings.NewForTask(t)
  1449  	defer perfTimings.Save(st)
  1450  
  1451  	_, snapst, err := snapSetupAndState(t)
  1452  	if err != nil {
  1453  		return err
  1454  	}
  1455  
  1456  	currentInfo, err := snapst.CurrentInfo()
  1457  	if err != nil {
  1458  		return err
  1459  	}
  1460  	svcs := currentInfo.Services()
  1461  	if len(svcs) == 0 {
  1462  		return nil
  1463  	}
  1464  
  1465  	var stopReason snap.ServiceStopReason
  1466  	if err := t.Get("stop-reason", &stopReason); err != nil && err != state.ErrNoState {
  1467  		return err
  1468  	}
  1469  
  1470  	pb := NewTaskProgressAdapterUnlocked(t)
  1471  	st.Unlock()
  1472  	err = m.backend.StopServices(svcs, stopReason, pb, perfTimings)
  1473  	st.Lock()
  1474  	return err
  1475  }
  1476  
  1477  func (m *SnapManager) doUnlinkSnap(t *state.Task, _ *tomb.Tomb) error {
  1478  	// invoked only if snap has a current active revision
  1479  	st := t.State()
  1480  	st.Lock()
  1481  	defer st.Unlock()
  1482  
  1483  	snapsup, snapst, err := snapSetupAndState(t)
  1484  	if err != nil {
  1485  		return err
  1486  	}
  1487  
  1488  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  1489  	if err != nil {
  1490  		return err
  1491  	}
  1492  
  1493  	pb := NewTaskProgressAdapterLocked(t)
  1494  	err = m.backend.UnlinkSnap(info, pb)
  1495  	if err != nil {
  1496  		return err
  1497  	}
  1498  
  1499  	// mark as inactive
  1500  	snapst.Active = false
  1501  	Set(st, snapsup.InstanceName(), snapst)
  1502  
  1503  	return err
  1504  }
  1505  
  1506  func (m *SnapManager) doClearSnapData(t *state.Task, _ *tomb.Tomb) error {
  1507  	st := t.State()
  1508  	st.Lock()
  1509  	snapsup, snapst, err := snapSetupAndState(t)
  1510  	st.Unlock()
  1511  	if err != nil {
  1512  		return err
  1513  	}
  1514  
  1515  	st.Lock()
  1516  	info, err := Info(t.State(), snapsup.InstanceName(), snapsup.Revision())
  1517  	st.Unlock()
  1518  	if err != nil {
  1519  		return err
  1520  	}
  1521  
  1522  	if err = m.backend.RemoveSnapData(info); err != nil {
  1523  		return err
  1524  	}
  1525  
  1526  	if len(snapst.Sequence) == 1 {
  1527  		// Only remove data common between versions if this is the last version
  1528  		if err = m.backend.RemoveSnapCommonData(info); err != nil {
  1529  			return err
  1530  		}
  1531  
  1532  		st.Lock()
  1533  		defer st.Unlock()
  1534  
  1535  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  1536  		if err != nil {
  1537  			return err
  1538  		}
  1539  		// Snap data directory can be removed now too
  1540  		if err := m.backend.RemoveSnapDataDir(info, otherInstances); err != nil {
  1541  			return err
  1542  		}
  1543  	}
  1544  
  1545  	return nil
  1546  }
  1547  
  1548  func (m *SnapManager) doDiscardSnap(t *state.Task, _ *tomb.Tomb) error {
  1549  	st := t.State()
  1550  	st.Lock()
  1551  	defer st.Unlock()
  1552  
  1553  	snapsup, snapst, err := snapSetupAndState(t)
  1554  	if err != nil {
  1555  		return err
  1556  	}
  1557  
  1558  	if snapst.Current == snapsup.Revision() && snapst.Active {
  1559  		return fmt.Errorf("internal error: cannot discard snap %q: still active", snapsup.InstanceName())
  1560  	}
  1561  
  1562  	if len(snapst.Sequence) == 1 {
  1563  		snapst.Sequence = nil
  1564  		snapst.Current = snap.Revision{}
  1565  	} else {
  1566  		newSeq := make([]*snap.SideInfo, 0, len(snapst.Sequence))
  1567  		for _, si := range snapst.Sequence {
  1568  			if si.Revision == snapsup.Revision() {
  1569  				// leave out
  1570  				continue
  1571  			}
  1572  			newSeq = append(newSeq, si)
  1573  		}
  1574  		snapst.Sequence = newSeq
  1575  		if snapst.Current == snapsup.Revision() {
  1576  			snapst.Current = newSeq[len(newSeq)-1].Revision
  1577  		}
  1578  	}
  1579  
  1580  	pb := NewTaskProgressAdapterLocked(t)
  1581  	typ, err := snapst.Type()
  1582  	if err != nil {
  1583  		return err
  1584  	}
  1585  	err = m.backend.RemoveSnapFiles(snapsup.placeInfo(), typ, pb)
  1586  	if err != nil {
  1587  		t.Errorf("cannot remove snap file %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  1588  		return &state.Retry{After: 3 * time.Minute}
  1589  	}
  1590  	if len(snapst.Sequence) == 0 {
  1591  		// Remove configuration associated with this snap.
  1592  		err = config.DeleteSnapConfig(st, snapsup.InstanceName())
  1593  		if err != nil {
  1594  			return err
  1595  		}
  1596  		err = m.backend.DiscardSnapNamespace(snapsup.InstanceName())
  1597  		if err != nil {
  1598  			t.Errorf("cannot discard snap namespace %q, will retry in 3 mins: %s", snapsup.InstanceName(), err)
  1599  			return &state.Retry{After: 3 * time.Minute}
  1600  		}
  1601  		if err := m.removeSnapCookie(st, snapsup.InstanceName()); err != nil {
  1602  			return fmt.Errorf("cannot remove snap cookie: %v", err)
  1603  		}
  1604  
  1605  		otherInstances, err := hasOtherInstances(st, snapsup.InstanceName())
  1606  		if err != nil {
  1607  			return err
  1608  		}
  1609  
  1610  		if err := m.backend.RemoveSnapDir(snapsup.placeInfo(), otherInstances); err != nil {
  1611  			return fmt.Errorf("cannot remove snap directory: %v", err)
  1612  		}
  1613  
  1614  		// try to remove the auxiliary store info
  1615  		if err := discardAuxStoreInfo(snapsup.SideInfo.SnapID); err != nil {
  1616  			logger.Noticef("Cannot remove auxiliary store info for %q: %v", snapsup.InstanceName(), err)
  1617  		}
  1618  
  1619  		// XXX: also remove sequence files?
  1620  	}
  1621  	if err = config.DiscardRevisionConfig(st, snapsup.InstanceName(), snapsup.Revision()); err != nil {
  1622  		return err
  1623  	}
  1624  	Set(st, snapsup.InstanceName(), snapst)
  1625  	return nil
  1626  }
  1627  
  1628  /* aliases v2
  1629  
  1630  aliases v2 implementation uses the following tasks:
  1631  
  1632    * for install/refresh/remove/enable/disable etc
  1633  
  1634      - remove-aliases: remove aliases of a snap from disk and mark them pending
  1635  
  1636      - setup-aliases: (re)creates aliases from snap state, mark them as
  1637        not pending
  1638  
  1639      - set-auto-aliases: updates aliases snap state based on the
  1640        snap-declaration and current revision info of the snap
  1641  
  1642    * for refresh & when the snap-declaration aliases change without a
  1643      new revision
  1644  
  1645      - refresh-aliases: updates aliases snap state and updates them on disk too;
  1646        its undo is used generically by other tasks as well
  1647  
  1648      - prune-auto-aliases: used for the special case of automatic
  1649        aliases transferred from one snap to another to prune them from
  1650        the source snaps to avoid conflicts in later operations
  1651  
  1652    * for alias/unalias/prefer:
  1653  
  1654      - alias: creates a manual alias
  1655  
  1656      - unalias: removes a manual alias
  1657  
  1658      - disable-aliases: disable the automatic aliases of a snap and
  1659        removes all manual ones as well
  1660  
  1661      - prefer-aliases: enables the automatic aliases of a snap after
  1662        disabling any other snap conflicting aliases
  1663  
  1664  */
  1665  
  1666  func (m *SnapManager) doSetAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  1667  	st := t.State()
  1668  	st.Lock()
  1669  	defer st.Unlock()
  1670  	snapsup, snapst, err := snapSetupAndState(t)
  1671  	if err != nil {
  1672  		return err
  1673  	}
  1674  	snapName := snapsup.InstanceName()
  1675  	curInfo, err := snapst.CurrentInfo()
  1676  	if err != nil {
  1677  		return err
  1678  	}
  1679  
  1680  	// --unaliased
  1681  	if snapsup.Unaliased {
  1682  		t.Set("old-auto-aliases-disabled", snapst.AutoAliasesDisabled)
  1683  		snapst.AutoAliasesDisabled = true
  1684  	}
  1685  
  1686  	curAliases := snapst.Aliases
  1687  	// TODO: implement --prefer logic
  1688  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  1689  	if err != nil {
  1690  		return err
  1691  	}
  1692  	_, err = checkAliasesConflicts(st, snapName, snapst.AutoAliasesDisabled, newAliases, nil)
  1693  	if err != nil {
  1694  		return err
  1695  	}
  1696  
  1697  	t.Set("old-aliases-v2", curAliases)
  1698  	// noop, except on first install where we need to set this here
  1699  	snapst.AliasesPending = true
  1700  	snapst.Aliases = newAliases
  1701  	Set(st, snapName, snapst)
  1702  	return nil
  1703  }
  1704  
  1705  func (m *SnapManager) doRemoveAliases(t *state.Task, _ *tomb.Tomb) error {
  1706  	st := t.State()
  1707  	st.Lock()
  1708  	defer st.Unlock()
  1709  	snapsup, snapst, err := snapSetupAndState(t)
  1710  	if err != nil {
  1711  		return err
  1712  	}
  1713  	snapName := snapsup.InstanceName()
  1714  
  1715  	err = m.backend.RemoveSnapAliases(snapName)
  1716  	if err != nil {
  1717  		return err
  1718  	}
  1719  
  1720  	snapst.AliasesPending = true
  1721  	Set(st, snapName, snapst)
  1722  	return nil
  1723  }
  1724  
  1725  func (m *SnapManager) doSetupAliases(t *state.Task, _ *tomb.Tomb) error {
  1726  	st := t.State()
  1727  	st.Lock()
  1728  	defer st.Unlock()
  1729  	snapsup, snapst, err := snapSetupAndState(t)
  1730  	if err != nil {
  1731  		return err
  1732  	}
  1733  	snapName := snapsup.InstanceName()
  1734  	curAliases := snapst.Aliases
  1735  
  1736  	_, _, err = applyAliasesChange(snapName, autoDis, nil, snapst.AutoAliasesDisabled, curAliases, m.backend, doApply)
  1737  	if err != nil {
  1738  		return err
  1739  	}
  1740  
  1741  	snapst.AliasesPending = false
  1742  	Set(st, snapName, snapst)
  1743  	return nil
  1744  }
  1745  
  1746  func (m *SnapManager) doRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  1747  	st := t.State()
  1748  	st.Lock()
  1749  	defer st.Unlock()
  1750  	snapsup, snapst, err := snapSetupAndState(t)
  1751  	if err != nil {
  1752  		return err
  1753  	}
  1754  	snapName := snapsup.InstanceName()
  1755  	curInfo, err := snapst.CurrentInfo()
  1756  	if err != nil {
  1757  		return err
  1758  	}
  1759  
  1760  	autoDisabled := snapst.AutoAliasesDisabled
  1761  	curAliases := snapst.Aliases
  1762  	newAliases, err := refreshAliases(st, curInfo, curAliases)
  1763  	if err != nil {
  1764  		return err
  1765  	}
  1766  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  1767  	if err != nil {
  1768  		return err
  1769  	}
  1770  
  1771  	if !snapst.AliasesPending {
  1772  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  1773  			return err
  1774  		}
  1775  	}
  1776  
  1777  	t.Set("old-aliases-v2", curAliases)
  1778  	snapst.Aliases = newAliases
  1779  	Set(st, snapName, snapst)
  1780  	return nil
  1781  }
  1782  
  1783  func (m *SnapManager) undoRefreshAliases(t *state.Task, _ *tomb.Tomb) error {
  1784  	st := t.State()
  1785  	st.Lock()
  1786  	defer st.Unlock()
  1787  	var oldAliases map[string]*AliasTarget
  1788  	err := t.Get("old-aliases-v2", &oldAliases)
  1789  	if err == state.ErrNoState {
  1790  		// nothing to do
  1791  		return nil
  1792  	}
  1793  	if err != nil {
  1794  		return err
  1795  	}
  1796  	snapsup, snapst, err := snapSetupAndState(t)
  1797  	if err != nil {
  1798  		return err
  1799  	}
  1800  	snapName := snapsup.InstanceName()
  1801  	curAutoDisabled := snapst.AutoAliasesDisabled
  1802  	autoDisabled := curAutoDisabled
  1803  	if err = t.Get("old-auto-aliases-disabled", &autoDisabled); err != nil && err != state.ErrNoState {
  1804  		return err
  1805  	}
  1806  
  1807  	var otherSnapDisabled map[string]*otherDisabledAliases
  1808  	if err = t.Get("other-disabled-aliases", &otherSnapDisabled); err != nil && err != state.ErrNoState {
  1809  		return err
  1810  	}
  1811  
  1812  	// check if the old states creates conflicts now
  1813  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, oldAliases, nil)
  1814  	if _, ok := err.(*AliasConflictError); ok {
  1815  		// best we can do is reinstate with all aliases disabled
  1816  		t.Errorf("cannot reinstate alias state because of conflicts, disabling: %v", err)
  1817  		oldAliases, _ = disableAliases(oldAliases)
  1818  		autoDisabled = true
  1819  	} else if err != nil {
  1820  		return err
  1821  	}
  1822  
  1823  	if !snapst.AliasesPending {
  1824  		curAliases := snapst.Aliases
  1825  		if _, _, err := applyAliasesChange(snapName, curAutoDisabled, curAliases, autoDisabled, oldAliases, m.backend, doApply); err != nil {
  1826  			return err
  1827  		}
  1828  	}
  1829  
  1830  	snapst.AutoAliasesDisabled = autoDisabled
  1831  	snapst.Aliases = oldAliases
  1832  	newSnapStates := make(map[string]*SnapState, 1+len(otherSnapDisabled))
  1833  	newSnapStates[snapName] = snapst
  1834  
  1835  	// if we disabled other snap aliases try to undo that
  1836  	conflicting := make(map[string]bool, len(otherSnapDisabled))
  1837  	otherCurSnapStates := make(map[string]*SnapState, len(otherSnapDisabled))
  1838  	for otherSnap, otherDisabled := range otherSnapDisabled {
  1839  		var otherSnapState SnapState
  1840  		err := Get(st, otherSnap, &otherSnapState)
  1841  		if err != nil {
  1842  			return err
  1843  		}
  1844  		otherCurInfo, err := otherSnapState.CurrentInfo()
  1845  		if err != nil {
  1846  			return err
  1847  		}
  1848  
  1849  		otherCurSnapStates[otherSnap] = &otherSnapState
  1850  
  1851  		autoDisabled := otherSnapState.AutoAliasesDisabled
  1852  		if otherDisabled.Auto {
  1853  			// automatic aliases of other were disabled, undo that
  1854  			autoDisabled = false
  1855  		}
  1856  		otherAliases := reenableAliases(otherCurInfo, otherSnapState.Aliases, otherDisabled.Manual)
  1857  		// check for conflicts taking into account
  1858  		// re-enabled aliases
  1859  		conflicts, err := checkAliasesConflicts(st, otherSnap, autoDisabled, otherAliases, newSnapStates)
  1860  		if _, ok := err.(*AliasConflictError); ok {
  1861  			conflicting[otherSnap] = true
  1862  			for conflictSnap := range conflicts {
  1863  				conflicting[conflictSnap] = true
  1864  			}
  1865  		} else if err != nil {
  1866  			return err
  1867  		}
  1868  
  1869  		newSnapState := otherSnapState
  1870  		newSnapState.Aliases = otherAliases
  1871  		newSnapState.AutoAliasesDisabled = autoDisabled
  1872  		newSnapStates[otherSnap] = &newSnapState
  1873  	}
  1874  
  1875  	// apply non-conflicting other
  1876  	for otherSnap, otherSnapState := range otherCurSnapStates {
  1877  		if conflicting[otherSnap] {
  1878  			// keep as it was
  1879  			continue
  1880  		}
  1881  		newSnapSt := newSnapStates[otherSnap]
  1882  		if !otherSnapState.AliasesPending {
  1883  			if _, _, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, newSnapSt.AutoAliasesDisabled, newSnapSt.Aliases, m.backend, doApply); err != nil {
  1884  				return err
  1885  			}
  1886  		}
  1887  	}
  1888  
  1889  	for instanceName, snapst := range newSnapStates {
  1890  		if conflicting[instanceName] {
  1891  			// keep as it was
  1892  			continue
  1893  		}
  1894  		Set(st, instanceName, snapst)
  1895  	}
  1896  	return nil
  1897  }
  1898  
  1899  func (m *SnapManager) doPruneAutoAliases(t *state.Task, _ *tomb.Tomb) error {
  1900  	st := t.State()
  1901  	st.Lock()
  1902  	defer st.Unlock()
  1903  	snapsup, snapst, err := snapSetupAndState(t)
  1904  	if err != nil {
  1905  		return err
  1906  	}
  1907  	var which []string
  1908  	err = t.Get("aliases", &which)
  1909  	if err != nil {
  1910  		return err
  1911  	}
  1912  	snapName := snapsup.InstanceName()
  1913  	autoDisabled := snapst.AutoAliasesDisabled
  1914  	curAliases := snapst.Aliases
  1915  
  1916  	newAliases := pruneAutoAliases(curAliases, which)
  1917  
  1918  	if !snapst.AliasesPending {
  1919  		if _, _, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, doApply); err != nil {
  1920  			return err
  1921  		}
  1922  	}
  1923  
  1924  	t.Set("old-aliases-v2", curAliases)
  1925  	snapst.Aliases = newAliases
  1926  	Set(st, snapName, snapst)
  1927  	return nil
  1928  }
  1929  
  1930  type changedAlias struct {
  1931  	Snap  string `json:"snap"`
  1932  	App   string `json:"app"`
  1933  	Alias string `json:"alias"`
  1934  }
  1935  
  1936  func aliasesTrace(t *state.Task, added, removed []*backend.Alias) error {
  1937  	chg := t.Change()
  1938  	var data map[string]interface{}
  1939  	err := chg.Get("api-data", &data)
  1940  	if err != nil && err != state.ErrNoState {
  1941  		return err
  1942  	}
  1943  	if len(data) == 0 {
  1944  		data = make(map[string]interface{})
  1945  	}
  1946  
  1947  	curAdded, _ := data["aliases-added"].([]interface{})
  1948  	for _, a := range added {
  1949  		snap, app := snap.SplitSnapApp(a.Target)
  1950  		curAdded = append(curAdded, &changedAlias{
  1951  			Snap:  snap,
  1952  			App:   app,
  1953  			Alias: a.Name,
  1954  		})
  1955  	}
  1956  	data["aliases-added"] = curAdded
  1957  
  1958  	curRemoved, _ := data["aliases-removed"].([]interface{})
  1959  	for _, a := range removed {
  1960  		snap, app := snap.SplitSnapApp(a.Target)
  1961  		curRemoved = append(curRemoved, &changedAlias{
  1962  			Snap:  snap,
  1963  			App:   app,
  1964  			Alias: a.Name,
  1965  		})
  1966  	}
  1967  	data["aliases-removed"] = curRemoved
  1968  
  1969  	chg.Set("api-data", data)
  1970  	return nil
  1971  }
  1972  
  1973  func (m *SnapManager) doAlias(t *state.Task, _ *tomb.Tomb) error {
  1974  	st := t.State()
  1975  	st.Lock()
  1976  	defer st.Unlock()
  1977  	snapsup, snapst, err := snapSetupAndState(t)
  1978  	if err != nil {
  1979  		return err
  1980  	}
  1981  	var target, alias string
  1982  	err = t.Get("target", &target)
  1983  	if err != nil {
  1984  		return err
  1985  	}
  1986  	err = t.Get("alias", &alias)
  1987  	if err != nil {
  1988  		return err
  1989  	}
  1990  
  1991  	snapName := snapsup.InstanceName()
  1992  	curInfo, err := snapst.CurrentInfo()
  1993  	if err != nil {
  1994  		return err
  1995  	}
  1996  
  1997  	autoDisabled := snapst.AutoAliasesDisabled
  1998  	curAliases := snapst.Aliases
  1999  	newAliases, err := manualAlias(curInfo, curAliases, target, alias)
  2000  	if err != nil {
  2001  		return err
  2002  	}
  2003  	_, err = checkAliasesConflicts(st, snapName, autoDisabled, newAliases, nil)
  2004  	if err != nil {
  2005  		return err
  2006  	}
  2007  
  2008  	added, removed, err := applyAliasesChange(snapName, autoDisabled, curAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2009  	if err != nil {
  2010  		return err
  2011  	}
  2012  	if err := aliasesTrace(t, added, removed); err != nil {
  2013  		return err
  2014  	}
  2015  
  2016  	t.Set("old-aliases-v2", curAliases)
  2017  	snapst.Aliases = newAliases
  2018  	Set(st, snapName, snapst)
  2019  	return nil
  2020  }
  2021  
  2022  func (m *SnapManager) doDisableAliases(t *state.Task, _ *tomb.Tomb) error {
  2023  	st := t.State()
  2024  	st.Lock()
  2025  	defer st.Unlock()
  2026  	snapsup, snapst, err := snapSetupAndState(t)
  2027  	if err != nil {
  2028  		return err
  2029  	}
  2030  	snapName := snapsup.InstanceName()
  2031  
  2032  	oldAutoDisabled := snapst.AutoAliasesDisabled
  2033  	oldAliases := snapst.Aliases
  2034  	newAliases, _ := disableAliases(oldAliases)
  2035  
  2036  	added, removed, err := applyAliasesChange(snapName, oldAutoDisabled, oldAliases, autoDis, newAliases, m.backend, snapst.AliasesPending)
  2037  	if err != nil {
  2038  		return err
  2039  	}
  2040  	if err := aliasesTrace(t, added, removed); err != nil {
  2041  		return err
  2042  	}
  2043  
  2044  	t.Set("old-auto-aliases-disabled", oldAutoDisabled)
  2045  	snapst.AutoAliasesDisabled = true
  2046  	t.Set("old-aliases-v2", oldAliases)
  2047  	snapst.Aliases = newAliases
  2048  	Set(st, snapName, snapst)
  2049  	return nil
  2050  }
  2051  
  2052  func (m *SnapManager) doUnalias(t *state.Task, _ *tomb.Tomb) error {
  2053  	st := t.State()
  2054  	st.Lock()
  2055  	defer st.Unlock()
  2056  	snapsup, snapst, err := snapSetupAndState(t)
  2057  	if err != nil {
  2058  		return err
  2059  	}
  2060  	var alias string
  2061  	err = t.Get("alias", &alias)
  2062  	if err != nil {
  2063  		return err
  2064  	}
  2065  	snapName := snapsup.InstanceName()
  2066  
  2067  	autoDisabled := snapst.AutoAliasesDisabled
  2068  	oldAliases := snapst.Aliases
  2069  	newAliases, err := manualUnalias(oldAliases, alias)
  2070  	if err != nil {
  2071  		return err
  2072  	}
  2073  
  2074  	added, removed, err := applyAliasesChange(snapName, autoDisabled, oldAliases, autoDisabled, newAliases, m.backend, snapst.AliasesPending)
  2075  	if err != nil {
  2076  		return err
  2077  	}
  2078  	if err := aliasesTrace(t, added, removed); err != nil {
  2079  		return err
  2080  	}
  2081  
  2082  	t.Set("old-aliases-v2", oldAliases)
  2083  	snapst.Aliases = newAliases
  2084  	Set(st, snapName, snapst)
  2085  	return nil
  2086  }
  2087  
  2088  // otherDisabledAliases is used to track for the benefit of undo what
  2089  // changes were made aka what aliases were disabled of another
  2090  // conflicting snap by prefer logic
  2091  type otherDisabledAliases struct {
  2092  	// Auto records whether prefer had to disable automatic aliases
  2093  	Auto bool `json:"auto,omitempty"`
  2094  	// Manual records which manual aliases were removed by prefer
  2095  	Manual map[string]string `json:"manual,omitempty"`
  2096  }
  2097  
  2098  func (m *SnapManager) doPreferAliases(t *state.Task, _ *tomb.Tomb) error {
  2099  	st := t.State()
  2100  	st.Lock()
  2101  	defer st.Unlock()
  2102  	snapsup, snapst, err := snapSetupAndState(t)
  2103  	if err != nil {
  2104  		return err
  2105  	}
  2106  	instanceName := snapsup.InstanceName()
  2107  
  2108  	if !snapst.AutoAliasesDisabled {
  2109  		// already enabled, nothing to do
  2110  		return nil
  2111  	}
  2112  
  2113  	curAliases := snapst.Aliases
  2114  	aliasConflicts, err := checkAliasesConflicts(st, instanceName, autoEn, curAliases, nil)
  2115  	conflErr, isConflErr := err.(*AliasConflictError)
  2116  	if err != nil && !isConflErr {
  2117  		return err
  2118  	}
  2119  	if isConflErr && conflErr.Conflicts == nil {
  2120  		// it's a snap command namespace conflict, we cannot remedy it
  2121  		return conflErr
  2122  	}
  2123  	// proceed to disable conflicting aliases as needed
  2124  	// before re-enabling instanceName aliases
  2125  
  2126  	otherSnapStates := make(map[string]*SnapState, len(aliasConflicts))
  2127  	otherSnapDisabled := make(map[string]*otherDisabledAliases, len(aliasConflicts))
  2128  	for otherSnap := range aliasConflicts {
  2129  		var otherSnapState SnapState
  2130  		err := Get(st, otherSnap, &otherSnapState)
  2131  		if err != nil {
  2132  			return err
  2133  		}
  2134  
  2135  		otherAliases, disabledManual := disableAliases(otherSnapState.Aliases)
  2136  
  2137  		added, removed, err := applyAliasesChange(otherSnap, otherSnapState.AutoAliasesDisabled, otherSnapState.Aliases, autoDis, otherAliases, m.backend, otherSnapState.AliasesPending)
  2138  		if err != nil {
  2139  			return err
  2140  		}
  2141  		if err := aliasesTrace(t, added, removed); err != nil {
  2142  			return err
  2143  		}
  2144  
  2145  		var otherDisabled otherDisabledAliases
  2146  		otherDisabled.Manual = disabledManual
  2147  		otherSnapState.Aliases = otherAliases
  2148  		// disable automatic aliases as needed
  2149  		if !otherSnapState.AutoAliasesDisabled && len(otherAliases) != 0 {
  2150  			// record that we did disable automatic aliases
  2151  			otherDisabled.Auto = true
  2152  			otherSnapState.AutoAliasesDisabled = true
  2153  		}
  2154  		otherSnapDisabled[otherSnap] = &otherDisabled
  2155  		otherSnapStates[otherSnap] = &otherSnapState
  2156  	}
  2157  
  2158  	added, removed, err := applyAliasesChange(instanceName, autoDis, curAliases, autoEn, curAliases, m.backend, snapst.AliasesPending)
  2159  	if err != nil {
  2160  		return err
  2161  	}
  2162  	if err := aliasesTrace(t, added, removed); err != nil {
  2163  		return err
  2164  	}
  2165  
  2166  	for otherSnap, otherSnapState := range otherSnapStates {
  2167  		Set(st, otherSnap, otherSnapState)
  2168  	}
  2169  	if len(otherSnapDisabled) != 0 {
  2170  		t.Set("other-disabled-aliases", otherSnapDisabled)
  2171  	}
  2172  	t.Set("old-auto-aliases-disabled", true)
  2173  	t.Set("old-aliases-v2", curAliases)
  2174  	snapst.AutoAliasesDisabled = false
  2175  	Set(st, instanceName, snapst)
  2176  	return nil
  2177  }
  2178  
  2179  // changeReadyUpToTask returns whether all other change's tasks are Ready.
  2180  func changeReadyUpToTask(task *state.Task) bool {
  2181  	me := task.ID()
  2182  	change := task.Change()
  2183  	for _, task := range change.Tasks() {
  2184  		if me == task.ID() {
  2185  			// ignore self
  2186  			continue
  2187  		}
  2188  		if !task.Status().Ready() {
  2189  			return false
  2190  		}
  2191  	}
  2192  	return true
  2193  }
  2194  
  2195  // refreshedSnaps returns the instance names of the snaps successfully refreshed
  2196  // in the last batch of refreshes before the given (re-refresh) task.
  2197  //
  2198  // It does this by advancing through the given task's change's tasks, keeping
  2199  // track of the instance names from the first SnapSetup in every lane, stopping
  2200  // when finding the given task, and resetting things when finding a different
  2201  // re-refresh task (that indicates the end of a batch that isn't the given one).
  2202  func refreshedSnaps(reTask *state.Task) []string {
  2203  	// NOTE nothing requires reTask to be a check-rerefresh task, nor even to be in
  2204  	// a refresh-ish change, but it doesn't make much sense to call this otherwise.
  2205  	tid := reTask.ID()
  2206  	laneSnaps := map[int]string{}
  2207  	// change.Tasks() preserves the order tasks were added, otherwise it all falls apart
  2208  	for _, task := range reTask.Change().Tasks() {
  2209  		if task.ID() == tid {
  2210  			// we've reached ourselves; we don't care about anything beyond this
  2211  			break
  2212  		}
  2213  		if task.Kind() == "check-rerefresh" {
  2214  			// we've reached a previous check-rerefresh (but not ourselves).
  2215  			// Only snaps in tasks after this point are of interest.
  2216  			laneSnaps = map[int]string{}
  2217  		}
  2218  		lanes := task.Lanes()
  2219  		if len(lanes) != 1 {
  2220  			// can't happen, really
  2221  			continue
  2222  		}
  2223  		lane := lanes[0]
  2224  		if lane == 0 {
  2225  			// not really a lane
  2226  			continue
  2227  		}
  2228  		if task.Status() != state.DoneStatus {
  2229  			// ignore non-successful lane (1)
  2230  			laneSnaps[lane] = ""
  2231  			continue
  2232  		}
  2233  		if _, ok := laneSnaps[lane]; ok {
  2234  			// ignore lanes we've already seen (including ones explicitly ignored in (1))
  2235  			continue
  2236  		}
  2237  		var snapsup SnapSetup
  2238  		if err := task.Get("snap-setup", &snapsup); err != nil {
  2239  			continue
  2240  		}
  2241  		laneSnaps[lane] = snapsup.InstanceName()
  2242  	}
  2243  
  2244  	snapNames := make([]string, 0, len(laneSnaps))
  2245  	for _, name := range laneSnaps {
  2246  		if name == "" {
  2247  			// the lane was unsuccessful
  2248  			continue
  2249  		}
  2250  		snapNames = append(snapNames, name)
  2251  	}
  2252  	return snapNames
  2253  }
  2254  
  2255  // reRefreshSetup holds the necessary details to re-refresh snaps that need it
  2256  type reRefreshSetup struct {
  2257  	UserID int `json:"user-id,omitempty"`
  2258  	*Flags
  2259  }
  2260  
  2261  // reRefreshUpdateMany exists just to make testing simpler
  2262  var reRefreshUpdateMany = updateManyFiltered
  2263  
  2264  // reRefreshFilter is an updateFilter that returns whether the given update
  2265  // needs a re-refresh because of further epoch transitions available.
  2266  func reRefreshFilter(update *snap.Info, snapst *SnapState) bool {
  2267  	cur, err := snapst.CurrentInfo()
  2268  	if err != nil {
  2269  		return false
  2270  	}
  2271  	return !update.Epoch.Equal(&cur.Epoch)
  2272  }
  2273  
  2274  var reRefreshRetryTimeout = time.Second / 10
  2275  
  2276  func (m *SnapManager) doCheckReRefresh(t *state.Task, tomb *tomb.Tomb) error {
  2277  	st := t.State()
  2278  	st.Lock()
  2279  	defer st.Unlock()
  2280  
  2281  	if numHaltTasks := t.NumHaltTasks(); numHaltTasks > 0 {
  2282  		logger.Panicf("Re-refresh task has %d tasks waiting for it.", numHaltTasks)
  2283  	}
  2284  
  2285  	if !changeReadyUpToTask(t) {
  2286  		return &state.Retry{After: reRefreshRetryTimeout, Reason: "pending refreshes"}
  2287  	}
  2288  	snaps := refreshedSnaps(t)
  2289  	if len(snaps) == 0 {
  2290  		// nothing to do (maybe everything failed)
  2291  		return nil
  2292  	}
  2293  
  2294  	var re reRefreshSetup
  2295  	if err := t.Get("rerefresh-setup", &re); err != nil {
  2296  		return err
  2297  	}
  2298  	chg := t.Change()
  2299  	updated, tasksets, err := reRefreshUpdateMany(tomb.Context(nil), st, snaps, re.UserID, reRefreshFilter, re.Flags, chg.ID())
  2300  	if err != nil {
  2301  		return err
  2302  	}
  2303  
  2304  	if len(updated) == 0 {
  2305  		t.Logf("No re-refreshes found.")
  2306  	} else {
  2307  		t.Logf("Found re-refresh for %s.", strutil.Quoted(updated))
  2308  
  2309  		for _, taskset := range tasksets {
  2310  			chg.AddAll(taskset)
  2311  		}
  2312  		st.EnsureBefore(0)
  2313  	}
  2314  	t.SetStatus(state.DoneStatus)
  2315  
  2316  	return nil
  2317  }
  2318  
  2319  // InjectTasks makes all the halt tasks of the mainTask wait for extraTasks;
  2320  // extraTasks join the same lane and change as the mainTask.
  2321  func InjectTasks(mainTask *state.Task, extraTasks *state.TaskSet) {
  2322  	lanes := mainTask.Lanes()
  2323  	if len(lanes) == 1 && lanes[0] == 0 {
  2324  		lanes = nil
  2325  	}
  2326  	for _, l := range lanes {
  2327  		extraTasks.JoinLane(l)
  2328  	}
  2329  
  2330  	chg := mainTask.Change()
  2331  	// Change shouldn't normally be nil, except for cases where
  2332  	// this helper is used before tasks are added to a change.
  2333  	if chg != nil {
  2334  		chg.AddAll(extraTasks)
  2335  	}
  2336  
  2337  	// make all halt tasks of the mainTask wait on extraTasks
  2338  	ht := mainTask.HaltTasks()
  2339  	for _, t := range ht {
  2340  		t.WaitAll(extraTasks)
  2341  	}
  2342  
  2343  	// make the extra tasks wait for main task
  2344  	extraTasks.WaitFor(mainTask)
  2345  }
  2346  
  2347  func InjectAutoConnect(mainTask *state.Task, snapsup *SnapSetup) {
  2348  	st := mainTask.State()
  2349  	autoConnect := st.NewTask("auto-connect", fmt.Sprintf(i18n.G("Automatically connect eligible plugs and slots of snap %q"), snapsup.InstanceName()))
  2350  	autoConnect.Set("snap-setup", snapsup)
  2351  	InjectTasks(mainTask, state.NewTaskSet(autoConnect))
  2352  	mainTask.Logf("added auto-connect task")
  2353  }