gopkg.in/ubuntu-core/snappy.v0@v0.0.0-20210902073436-25a8614f10a6/systemd/emulation.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2019 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 systemd
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  	"io"
    26  	"os"
    27  	"os/exec"
    28  	"path/filepath"
    29  	"strings"
    30  	"time"
    31  
    32  	"github.com/snapcore/snapd/dirs"
    33  	"github.com/snapcore/snapd/gadget/quantity"
    34  	"github.com/snapcore/snapd/osutil"
    35  	"github.com/snapcore/snapd/osutil/squashfs"
    36  )
    37  
    38  type emulation struct {
    39  	rootDir string
    40  }
    41  
    42  var errNotImplemented = errors.New("not implemented in emulation mode")
    43  
    44  func (s *emulation) DaemonReload() error {
    45  	return errNotImplemented
    46  }
    47  
    48  func (s *emulation) DaemonReexec() error {
    49  	return errNotImplemented
    50  }
    51  
    52  func (s *emulation) Enable(service string) error {
    53  	_, err := systemctlCmd("--root", s.rootDir, "enable", service)
    54  	return err
    55  }
    56  
    57  func (s *emulation) Disable(service string) error {
    58  	_, err := systemctlCmd("--root", s.rootDir, "disable", service)
    59  	return err
    60  }
    61  
    62  func (s *emulation) Start(service ...string) error {
    63  	return errNotImplemented
    64  }
    65  
    66  func (s *emulation) StartNoBlock(service ...string) error {
    67  	return errNotImplemented
    68  }
    69  
    70  func (s *emulation) Stop(service string, timeout time.Duration) error {
    71  	return errNotImplemented
    72  }
    73  
    74  func (s *emulation) Kill(service, signal, who string) error {
    75  	return errNotImplemented
    76  }
    77  
    78  func (s *emulation) Restart(service string, timeout time.Duration) error {
    79  	return errNotImplemented
    80  }
    81  
    82  func (s *emulation) ReloadOrRestart(service string) error {
    83  	return errNotImplemented
    84  }
    85  
    86  func (s *emulation) RestartAll(service string) error {
    87  	return errNotImplemented
    88  }
    89  
    90  func (s *emulation) Status(units ...string) ([]*UnitStatus, error) {
    91  	return nil, errNotImplemented
    92  }
    93  
    94  func (s *emulation) InactiveEnterTimestamp(unit string) (time.Time, error) {
    95  	return time.Time{}, errNotImplemented
    96  }
    97  
    98  func (s *emulation) CurrentMemoryUsage(unit string) (quantity.Size, error) {
    99  	return 0, errNotImplemented
   100  }
   101  
   102  func (s *emulation) CurrentTasksCount(unit string) (uint64, error) {
   103  	return 0, errNotImplemented
   104  }
   105  
   106  func (s *emulation) IsEnabled(service string) (bool, error) {
   107  	return false, errNotImplemented
   108  }
   109  
   110  func (s *emulation) IsActive(service string) (bool, error) {
   111  	return false, errNotImplemented
   112  }
   113  
   114  func (s *emulation) LogReader(services []string, n int, follow bool) (io.ReadCloser, error) {
   115  	return nil, errNotImplemented
   116  }
   117  
   118  func (s *emulation) AddMountUnitFile(snapName, revision, what, where, fstype string) (string, error) {
   119  	if osutil.IsDirectory(what) {
   120  		return "", fmt.Errorf("bind-mounted directory is not supported in emulation mode")
   121  	}
   122  
   123  	// In emulation mode hostFsType is the fs we want to use to manually mount
   124  	// the snap below, but fstype is used for the created mount unit.
   125  	// This means that when preseeding in a lxd container, the snap will be
   126  	// mounted with fuse, but mount unit will use squashfs.
   127  	mountUnitOptions := append(fsMountOptions(fstype), squashfs.StandardOptions()...)
   128  	mountUnitName, err := writeMountUnitFile(snapName, revision, what, where, fstype, mountUnitOptions)
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  
   133  	hostFsType, actualOptions := hostFsTypeAndMountOptions(fstype)
   134  	cmd := exec.Command("mount", "-t", hostFsType, what, where, "-o", strings.Join(actualOptions, ","))
   135  	if out, err := cmd.CombinedOutput(); err != nil {
   136  		return "", fmt.Errorf("cannot mount %s (%s) at %s in preseed mode: %s; %s", what, hostFsType, where, err, string(out))
   137  	}
   138  
   139  	multiUserTargetWantsDir := filepath.Join(dirs.SnapServicesDir, "multi-user.target.wants")
   140  	if err := os.MkdirAll(multiUserTargetWantsDir, 0755); err != nil {
   141  		return "", err
   142  	}
   143  
   144  	// cannot call systemd, so manually enable the unit by symlinking into multi-user.target.wants
   145  	mu := MountUnitPath(where)
   146  	enableUnitPath := filepath.Join(multiUserTargetWantsDir, mountUnitName)
   147  	if err := os.Symlink(mu, enableUnitPath); err != nil {
   148  		return "", fmt.Errorf("cannot enable mount unit %s: %v", mountUnitName, err)
   149  	}
   150  	return mountUnitName, nil
   151  }
   152  
   153  func (s *emulation) RemoveMountUnitFile(mountedDir string) error {
   154  	unit := MountUnitPath(dirs.StripRootDir(mountedDir))
   155  	if !osutil.FileExists(unit) {
   156  		return nil
   157  	}
   158  
   159  	isMounted, err := osutilIsMounted(mountedDir)
   160  	if err != nil {
   161  		return err
   162  	}
   163  	if isMounted {
   164  		// use detach-loop and lazy unmount
   165  		if output, err := exec.Command("umount", "-d", "-l", mountedDir).CombinedOutput(); err != nil {
   166  			return osutil.OutputErr(output, err)
   167  		}
   168  	}
   169  
   170  	multiUserTargetWantsDir := filepath.Join(dirs.SnapServicesDir, "multi-user.target.wants")
   171  	enableUnitPathSymlink := filepath.Join(multiUserTargetWantsDir, filepath.Base(unit))
   172  	if err := os.Remove(enableUnitPathSymlink); err != nil {
   173  		return err
   174  	}
   175  
   176  	if err := os.Remove(unit); err != nil {
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func (s *emulation) Mask(service string) error {
   184  	_, err := systemctlCmd("--root", s.rootDir, "mask", service)
   185  	return err
   186  }
   187  
   188  func (s *emulation) Unmask(service string) error {
   189  	_, err := systemctlCmd("--root", s.rootDir, "unmask", service)
   190  	return err
   191  }
   192  
   193  func (s *emulation) Mount(what, where string, options ...string) error {
   194  	return errNotImplemented
   195  }
   196  
   197  func (s *emulation) Umount(whatOrWhere string) error {
   198  	return errNotImplemented
   199  }