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