github.com/ethanhsieh/snapd@v0.0.0-20210615102523-3db9b8e4edc5/overlord/snapstate/handlers.go (about)

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