github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/overlord/snapstate/handlers.go (about)

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