github.com/ubuntu-core/snappy@v0.0.0-20210827154228-9e584df982bb/snap/broken.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2016 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 snap
    21  
    22  import (
    23  	"fmt"
    24  	"path/filepath"
    25  	"strings"
    26  
    27  	"github.com/snapcore/snapd/dirs"
    28  )
    29  
    30  // GuessAppsForBroken guesses what apps and services a broken snap has
    31  // on the system by searching for matches based on the snap name in
    32  // the snap binaries and service file directories. It returns a
    33  // mapping from app names to partial AppInfo.
    34  func GuessAppsForBroken(info *Info) map[string]*AppInfo {
    35  	out := make(map[string]*AppInfo)
    36  
    37  	// guess binaries first
    38  	name := info.InstanceName()
    39  	for _, p := range []string{name, fmt.Sprintf("%s.*", name)} {
    40  		matches, _ := filepath.Glob(filepath.Join(dirs.SnapBinariesDir, p))
    41  		for _, m := range matches {
    42  			l := strings.SplitN(filepath.Base(m), ".", 2)
    43  			var appname string
    44  			if len(l) == 1 {
    45  				// when app is named the same as snap, it will
    46  				// be available under '<snap>' name, if the snap
    47  				// was installed with instance key, the app will
    48  				// be named `<snap>_<instance>'
    49  				appname = InstanceSnap(l[0])
    50  			} else {
    51  				appname = l[1]
    52  			}
    53  			out[appname] = &AppInfo{
    54  				Snap: info,
    55  				Name: appname,
    56  			}
    57  		}
    58  	}
    59  
    60  	// guess the services next
    61  	matches, _ := filepath.Glob(filepath.Join(dirs.SnapServicesDir, fmt.Sprintf("snap.%s.*.service", name)))
    62  	for _, m := range matches {
    63  		appname := strings.Split(m, ".")[2]
    64  		out[appname] = &AppInfo{
    65  			Snap:        info,
    66  			Name:        appname,
    67  			Daemon:      "simple",
    68  			DaemonScope: SystemDaemon,
    69  		}
    70  	}
    71  	// guess the user services next
    72  	matches, _ = filepath.Glob(filepath.Join(dirs.SnapUserServicesDir, fmt.Sprintf("snap.%s.*.service", name)))
    73  	for _, m := range matches {
    74  		appname := strings.Split(m, ".")[2]
    75  		out[appname] = &AppInfo{
    76  			Snap:        info,
    77  			Name:        appname,
    78  			Daemon:      "simple",
    79  			DaemonScope: UserDaemon,
    80  		}
    81  	}
    82  
    83  	return out
    84  }
    85  
    86  // renameClashingCorePlugs renames plugs that clash with slot names on core snap.
    87  //
    88  // Some released core snaps had explicitly defined plugs "network-bind" and
    89  // "core-support" that clashed with implicit slots with the same names but this
    90  // was not validated before.  To avoid a flag day and any potential issues,
    91  // transparently rename the two clashing plugs by appending the "-plug" suffix.
    92  func (info *Info) renameClashingCorePlugs() {
    93  	if info.InstanceName() == "core" && info.Type() == TypeOS {
    94  		for _, plugName := range []string{"network-bind", "core-support"} {
    95  			info.forceRenamePlug(plugName, plugName+"-plug")
    96  		}
    97  	}
    98  }
    99  
   100  // forceRenamePlug renames the plug from oldName to newName, if present.
   101  func (info *Info) forceRenamePlug(oldName, newName string) {
   102  	if plugInfo, ok := info.Plugs[oldName]; ok {
   103  		delete(info.Plugs, oldName)
   104  		info.Plugs[newName] = plugInfo
   105  		plugInfo.Name = newName
   106  		for _, appInfo := range info.Apps {
   107  			if _, ok := appInfo.Plugs[oldName]; ok {
   108  				delete(appInfo.Plugs, oldName)
   109  				appInfo.Plugs[newName] = plugInfo
   110  			}
   111  		}
   112  		for _, hookInfo := range info.Hooks {
   113  			if _, ok := hookInfo.Plugs[oldName]; ok {
   114  				delete(hookInfo.Plugs, oldName)
   115  				hookInfo.Plugs[newName] = plugInfo
   116  			}
   117  		}
   118  	}
   119  }