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