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