gitee.com/mysnapcore/mysnapd@v0.1.0/image/preseed/reset.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2020-2022 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 preseed
    21  
    22  import (
    23  	"fmt"
    24  	"io/ioutil"
    25  	"os"
    26  	"path/filepath"
    27  
    28  	"gitee.com/mysnapcore/mysnapd/cmd/snaplock/runinhibit"
    29  	"gitee.com/mysnapcore/mysnapd/dirs"
    30  	"gitee.com/mysnapcore/mysnapd/osutil"
    31  	apparmor_sandbox "gitee.com/mysnapcore/mysnapd/sandbox/apparmor"
    32  )
    33  
    34  // bash-completion symlinks; note there are symlinks that point at
    35  // completer, and symlinks that point at the completer symlinks.
    36  // e.g.
    37  // lxd.lxc -> /snap/core/current/usr/lib/snapd/complete.sh
    38  // lxc -> lxd.lxc
    39  func resetCompletionSymlinks(completersPath string) error {
    40  	files, err := ioutil.ReadDir(completersPath)
    41  	if err != nil && !os.IsNotExist(err) {
    42  		return fmt.Errorf("error reading %s: %v", completersPath, err)
    43  	}
    44  	completeShSymlinks := make(map[string]string)
    45  	var otherSymlinks []string
    46  
    47  	// pass 1: find all symlinks pointing at complete.sh
    48  	for _, fileInfo := range files {
    49  		if fileInfo.Mode()&os.ModeSymlink == 0 {
    50  			continue
    51  		}
    52  		fullPath := filepath.Join(completersPath, fileInfo.Name())
    53  		if dirs.IsCompleteShSymlink(fullPath) {
    54  			if err := os.Remove(fullPath); err != nil {
    55  				return fmt.Errorf("error removing symlink %s: %v", fullPath, err)
    56  			}
    57  			completeShSymlinks[fileInfo.Name()] = fullPath
    58  		} else {
    59  			otherSymlinks = append(otherSymlinks, fullPath)
    60  		}
    61  	}
    62  	// pass 2: find all symlinks that point at the symlinks found in pass 1.
    63  	for _, other := range otherSymlinks {
    64  		target, err := os.Readlink(other)
    65  		if err != nil {
    66  			return fmt.Errorf("error reading symlink target of %s: %v", other, err)
    67  		}
    68  		if _, ok := completeShSymlinks[target]; ok {
    69  			if err := os.Remove(other); err != nil {
    70  				return fmt.Errorf("error removing symlink %s: %v", other, err)
    71  			}
    72  		}
    73  	}
    74  
    75  	return nil
    76  }
    77  
    78  // ResetPreseededChroot removes all preseeding artifacts from preseedChroot
    79  // (classic Ubuntu only).
    80  func ResetPreseededChroot(preseedChroot string) error {
    81  	var err error
    82  	preseedChroot, err = filepath.Abs(preseedChroot)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	exists, isDir, err := osutil.DirExists(preseedChroot)
    88  	if err != nil {
    89  		return fmt.Errorf("cannot reset %q: %v", preseedChroot, err)
    90  	}
    91  	if !exists {
    92  		return fmt.Errorf("cannot reset non-existing directory %q", preseedChroot)
    93  	}
    94  	if !isDir {
    95  		return fmt.Errorf("cannot reset %q, it is not a directory", preseedChroot)
    96  	}
    97  
    98  	// globs that yield individual files
    99  	globs := []string{
   100  		dirs.SnapStateFile,
   101  		dirs.SnapSystemKeyFile,
   102  		filepath.Join(dirs.SnapBlobDir, "*.snap"),
   103  		filepath.Join(dirs.SnapUdevRulesDir, "*-snap.*.rules"),
   104  		filepath.Join(dirs.SnapDBusSystemPolicyDir, "snap.*.*.conf"),
   105  		filepath.Join(dirs.SnapServicesDir, "snap.*.service"),
   106  		filepath.Join(dirs.SnapServicesDir, "snap.*.timer"),
   107  		filepath.Join(dirs.SnapServicesDir, "snap.*.socket"),
   108  		filepath.Join(dirs.SnapServicesDir, "snap-*.mount"),
   109  		filepath.Join(dirs.SnapServicesDir, "multi-user.target.wants", "snap-*.mount"),
   110  		filepath.Join(dirs.SnapUserServicesDir, "snap.*.service"),
   111  		filepath.Join(dirs.SnapUserServicesDir, "snap.*.socket"),
   112  		filepath.Join(dirs.SnapUserServicesDir, "snap.*.timer"),
   113  		filepath.Join(dirs.SnapUserServicesDir, "default.target.wants", "snap.*.service"),
   114  		filepath.Join(dirs.SnapUserServicesDir, "sockets.target.wants", "snap.*.socket"),
   115  		filepath.Join(dirs.SnapUserServicesDir, "timers.target.wants", "snap.*.timer"),
   116  		filepath.Join(runinhibit.InhibitDir, "*.lock"),
   117  	}
   118  
   119  	for _, gl := range globs {
   120  		matches, err := filepath.Glob(filepath.Join(preseedChroot, gl))
   121  		if err != nil {
   122  			// the only possible error from Glob() is ErrBadPattern
   123  			return err
   124  		}
   125  		for _, path := range matches {
   126  			if err := os.Remove(path); err != nil {
   127  				return fmt.Errorf("error removing %s: %v", path, err)
   128  			}
   129  		}
   130  	}
   131  
   132  	// directories that need to be removed recursively (but
   133  	// leaving parent directory intact).
   134  	globs = []string{
   135  		filepath.Join(dirs.SnapDataDir, "*"),
   136  		filepath.Join(dirs.SnapCacheDir, "*"),
   137  		filepath.Join(apparmor_sandbox.CacheDir, "*"),
   138  		filepath.Join(dirs.SnapDesktopFilesDir, "*"),
   139  		filepath.Join(dirs.SnapDBusSessionServicesDir, "*"),
   140  		filepath.Join(dirs.SnapDBusSystemServicesDir, "*"),
   141  	}
   142  
   143  	for _, gl := range globs {
   144  		matches, err := filepath.Glob(filepath.Join(preseedChroot, gl))
   145  		if err != nil {
   146  			// the only possible error from Glob() is ErrBadPattern
   147  			return err
   148  		}
   149  		for _, path := range matches {
   150  			if err := os.RemoveAll(path); err != nil {
   151  				return fmt.Errorf("error removing %s: %v", path, err)
   152  			}
   153  		}
   154  	}
   155  
   156  	// directories removed entirely
   157  	paths := []string{
   158  		dirs.SnapAssertsDBDir,
   159  		dirs.FeaturesDir,
   160  		dirs.SnapDesktopIconsDir,
   161  		dirs.SnapDeviceDir,
   162  		dirs.SnapCookieDir,
   163  		dirs.SnapMountPolicyDir,
   164  		dirs.SnapAppArmorDir,
   165  		dirs.SnapSeqDir,
   166  		dirs.SnapMountDir,
   167  		dirs.SnapSeccompBase,
   168  	}
   169  
   170  	for _, path := range paths {
   171  		if err := os.RemoveAll(filepath.Join(preseedChroot, path)); err != nil {
   172  			// report the error and carry on
   173  			return fmt.Errorf("error removing %s: %v", path, err)
   174  		}
   175  	}
   176  
   177  	for _, completersPath := range []string{dirs.CompletersDir, dirs.LegacyCompletersDir} {
   178  		if err := resetCompletionSymlinks(filepath.Join(preseedChroot, completersPath)); err != nil {
   179  			return err
   180  		}
   181  	}
   182  
   183  	return nil
   184  }