代码拉取完成,页面将自动刷新
同步操作将从 tupelo-shen/mysnapd 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
// -*- Mode: Go; indent-tabs-mode: t -*-
/*
* Copyright (C) 2019 Canonical Ltd
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package snapstate
import (
"fmt"
"path/filepath"
"sort"
"strings"
"gitee.com/mysnapcore/mysnapd/cmd/snaplock/runinhibit"
"gitee.com/mysnapcore/mysnapd/osutil"
"gitee.com/mysnapcore/mysnapd/overlord/snapstate/backend"
"gitee.com/mysnapcore/mysnapd/overlord/state"
"gitee.com/mysnapcore/mysnapd/sandbox/cgroup"
"gitee.com/mysnapcore/mysnapd/snap"
"gitee.com/mysnapcore/mysnapd/strutil"
userclient "gitee.com/mysnapcore/mysnapd/usersession/client"
)
// pidsOfSnap is a mockable version of PidsOfSnap
var pidsOfSnap = cgroup.PidsOfSnap
var genericRefreshCheck = func(info *snap.Info, canAppRunDuringRefresh func(app *snap.AppInfo) bool) error {
knownPids, err := pidsOfSnap(info.InstanceName())
if err != nil {
return err
}
// Due to specific of the interaction with locking, all locking is performed by the caller.
var busyAppNames []string
var busyHookNames []string
var busyPIDs []int
// Currently there are no situations when hooks might be allowed to run
// during the refresh process. The function exists to make the next two
// chunks of code symmetric.
canHookRunDuringRefresh := func(hook *snap.HookInfo) bool {
return false
}
for name, app := range info.Apps {
if canAppRunDuringRefresh(app) {
continue
}
if PIDs := knownPids[app.SecurityTag()]; len(PIDs) > 0 {
busyAppNames = append(busyAppNames, name)
busyPIDs = append(busyPIDs, PIDs...)
}
}
for name, hook := range info.Hooks {
if canHookRunDuringRefresh(hook) {
continue
}
if PIDs := knownPids[hook.SecurityTag()]; len(PIDs) > 0 {
busyHookNames = append(busyHookNames, name)
busyPIDs = append(busyPIDs, PIDs...)
}
}
if len(busyAppNames) == 0 && len(busyHookNames) == 0 {
return nil
}
sort.Strings(busyAppNames)
sort.Strings(busyHookNames)
sort.Ints(busyPIDs)
return &BusySnapError{
SnapInfo: info,
busyAppNames: busyAppNames,
busyHookNames: busyHookNames,
pids: busyPIDs,
}
}
// SoftNothingRunningRefreshCheck looks if there are at most only service processes alive.
//
// The check is designed to run early in the refresh pipeline. Before
// downloading or stopping services for the update, we can check that only
// services or snaps that explicitly allow refreshes are running, that is,
// that no non-service apps or hooks are currently running.
//
// Since services are stopped during the update this provides a good early
// precondition check. The check is also deliberately racy as existing snap
// commands can fork new processes or existing processes can die. After the
// soft check passes the user is free to start snap applications and block the
// hard check.
//
// Apart from ignoring services, the check allows apps that want not to
// block refresh to continue executing.
func SoftNothingRunningRefreshCheck(info *snap.Info) error {
return genericRefreshCheck(info, func(app *snap.AppInfo) bool {
return app.IsService() || app.RefreshMode == "ignore-running"
})
}
// HardNothingRunningRefreshCheck looks if there are any undesired processes alive.
//
// The check is designed to run late in the refresh pipeline, after stopping
// snap services. At this point non-enduring services should be stopped, hooks
// should no longer run, and applications should be barred from running
// externally (e.g. by using a new inhibition mechanism for snap run).
//
// The check fails if any process belonging to the snap, apart from services
// and snaps that explicitly allow refreshes, is still alive. If a snap is busy
// it cannot be refreshed and the refresh process is aborted.
//
// Apart from ignoring services, the check allows apps that want not to
// block refresh to continue executing.
func HardNothingRunningRefreshCheck(info *snap.Info) error {
return genericRefreshCheck(info, func(app *snap.AppInfo) bool {
return app.IsService() || app.RefreshMode == "ignore-running"
})
}
// BusySnapError indicates that snap has apps or hooks running and cannot refresh.
type BusySnapError struct {
SnapInfo *snap.Info
pids []int
busyAppNames []string
busyHookNames []string
}
// PendingSnapRefreshInfo computes information necessary to perform user notification
// of postponed refresh of a snap, based on the information about snap "business".
//
// The returned value contains the instance name of the snap as well as, if possible,
// information relevant for desktop notification services, such as application name
// and the snapd-generated desktop file name.
func (err *BusySnapError) PendingSnapRefreshInfo() *userclient.PendingSnapRefreshInfo {
refreshInfo := &userclient.PendingSnapRefreshInfo{
InstanceName: err.SnapInfo.InstanceName(),
}
for _, appName := range err.busyAppNames {
if app, ok := err.SnapInfo.Apps[appName]; ok {
path := app.DesktopFile()
if osutil.FileExists(path) {
refreshInfo.BusyAppName = appName
refreshInfo.BusyAppDesktopEntry = strings.SplitN(filepath.Base(path), ".", 2)[0]
break
}
}
}
return refreshInfo
}
// Error formats an error string describing what is running.
func (err *BusySnapError) Error() string {
pids := strutil.IntsToCommaSeparated(err.pids)
switch {
case len(err.busyAppNames) > 0 && len(err.busyHookNames) > 0:
return fmt.Sprintf("snap %q has running apps (%s) and hooks (%s), pids: %s",
err.SnapInfo.InstanceName(), strings.Join(err.busyAppNames, ", "), strings.Join(err.busyHookNames, ", "), pids)
case len(err.busyAppNames) > 0:
return fmt.Sprintf("snap %q has running apps (%s), pids: %s",
err.SnapInfo.InstanceName(), strings.Join(err.busyAppNames, ", "), pids)
case len(err.busyHookNames) > 0:
return fmt.Sprintf("snap %q has running hooks (%s), pids: %s",
err.SnapInfo.InstanceName(), strings.Join(err.busyHookNames, ", "), pids)
default:
return fmt.Sprintf("snap %q has running apps or hooks, pids: %s", err.SnapInfo.InstanceName(), pids)
}
}
// Pids returns the set of process identifiers that are running.
//
// Since this list is a snapshot it should be only acted upon if there is an
// external synchronization system applied (e.g. all processes are frozen) at
// the time the snapshot was taken.
//
// The list is intended for snapd to forcefully kill all processes for a forced
// refresh scenario.
func (err BusySnapError) Pids() []int {
return err.pids
}
// hardEnsureNothingRunningDuringRefresh performs the complete hard refresh interaction.
//
// This check uses HardNothingRunningRefreshCheck along with interaction with
// two locks - the snap lock, shared by snap-confine and snapd and the snap run
// inhibition lock, shared by snapd and snap run.
//
// On success this function returns a locked snap lock, allowing the caller to
// atomically, with regards to "snap-confine", finish any action that required
// the apps and hooks not to be running. In addition, the persistent run
// inhibition lock is established, forcing snap-run to pause and postpone
// startup of applications from the given snap.
//
// In practice, we either inhibit app startup and refresh the snap _or_ inhibit
// the refresh change and continue running existing app processes.
func hardEnsureNothingRunningDuringRefresh(backend managerBackend, st *state.State, snapst *SnapState, info *snap.Info) (*osutil.FileLock, error) {
return backend.RunInhibitSnapForUnlink(info, runinhibit.HintInhibitedForRefresh, func() error {
// In case of successful refresh inhibition the snap state is modified
// to indicate when the refresh was first inhibited. If the first
// refresh inhibition is outside of a grace period then refresh
// proceeds regardless of the existing processes.
return inhibitRefresh(st, snapst, info, HardNothingRunningRefreshCheck)
})
}
// softCheckNothingRunningForRefresh checks if non-service apps are off for a snap refresh.
//
// The details of the check are explained by SoftNothingRunningRefreshCheck.
// The check is performed while holding the snap lock, which ensures that we
// are not racing with snap-confine, which is starting a new process in the
// context of the given snap.
//
// In the case that the check fails, the state is modified to reflect when the
// refresh was first postponed. Eventually the check does not fail, even if
// non-service apps are running, because this mechanism only allows postponing
// refreshes for a bounded amount of time.
func softCheckNothingRunningForRefresh(st *state.State, snapst *SnapState, info *snap.Info) error {
// Grab per-snap lock to prevent new processes from starting. This is
// sufficient to perform the check, even though individual processes may
// fork or exit, we will have per-security-tag information about what is
// running.
return backend.WithSnapLock(info, func() error {
// Perform the soft refresh viability check, possibly writing to the state
// on failure.
return inhibitRefresh(st, snapst, info, SoftNothingRunningRefreshCheck)
})
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。