github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/pkg/domain/infra/abi/containers.go (about)

     1  // +build ABISupport
     2  
     3  package abi
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"strconv"
    11  	"strings"
    12  	"sync"
    13  
    14  	"github.com/containers/buildah"
    15  	"github.com/containers/common/pkg/config"
    16  	"github.com/containers/image/v5/manifest"
    17  	"github.com/containers/libpod/libpod"
    18  	"github.com/containers/libpod/libpod/define"
    19  	"github.com/containers/libpod/libpod/events"
    20  	"github.com/containers/libpod/libpod/image"
    21  	"github.com/containers/libpod/libpod/logs"
    22  	"github.com/containers/libpod/pkg/checkpoint"
    23  	"github.com/containers/libpod/pkg/domain/entities"
    24  	"github.com/containers/libpod/pkg/domain/infra/abi/terminal"
    25  	"github.com/containers/libpod/pkg/ps"
    26  	"github.com/containers/libpod/pkg/rootless"
    27  	"github.com/containers/libpod/pkg/signal"
    28  	"github.com/containers/libpod/pkg/specgen"
    29  	"github.com/containers/libpod/pkg/specgen/generate"
    30  	"github.com/containers/storage"
    31  	"github.com/pkg/errors"
    32  	"github.com/sirupsen/logrus"
    33  )
    34  
    35  // getContainersByContext gets pods whether all, latest, or a slice of names/ids
    36  // is specified.
    37  func getContainersByContext(all, latest bool, names []string, runtime *libpod.Runtime) (ctrs []*libpod.Container, err error) {
    38  	var ctr *libpod.Container
    39  	ctrs = []*libpod.Container{}
    40  
    41  	switch {
    42  	case all:
    43  		ctrs, err = runtime.GetAllContainers()
    44  	case latest:
    45  		ctr, err = runtime.GetLatestContainer()
    46  		ctrs = append(ctrs, ctr)
    47  	default:
    48  		for _, n := range names {
    49  			ctr, e := runtime.LookupContainer(n)
    50  			if e != nil {
    51  				// Log all errors here, so callers don't need to.
    52  				logrus.Debugf("Error looking up container %q: %v", n, e)
    53  				if err == nil {
    54  					err = e
    55  				}
    56  			} else {
    57  				ctrs = append(ctrs, ctr)
    58  			}
    59  		}
    60  	}
    61  	return
    62  }
    63  
    64  // TODO: Should return *entities.ContainerExistsReport, error
    65  func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrId string) (*entities.BoolReport, error) {
    66  	_, err := ic.Libpod.LookupContainer(nameOrId)
    67  	if err != nil && errors.Cause(err) != define.ErrNoSuchCtr {
    68  		return nil, err
    69  	}
    70  	return &entities.BoolReport{Value: err == nil}, nil
    71  }
    72  
    73  func (ic *ContainerEngine) ContainerWait(ctx context.Context, namesOrIds []string, options entities.WaitOptions) ([]entities.WaitReport, error) {
    74  	var (
    75  		responses []entities.WaitReport
    76  	)
    77  	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	for _, c := range ctrs {
    82  		response := entities.WaitReport{Id: c.ID()}
    83  		exitCode, err := c.WaitForConditionWithInterval(options.Interval, options.Condition)
    84  		if err != nil {
    85  			response.Error = err
    86  		} else {
    87  			response.ExitCode = exitCode
    88  		}
    89  		responses = append(responses, response)
    90  	}
    91  	return responses, nil
    92  }
    93  
    94  func (ic *ContainerEngine) ContainerPause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
    95  	var (
    96  		ctrs   []*libpod.Container
    97  		err    error
    98  		report []*entities.PauseUnpauseReport
    99  	)
   100  	if options.All {
   101  		ctrs, err = ic.Libpod.GetAllContainers()
   102  	} else {
   103  		ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
   104  	}
   105  	if err != nil {
   106  		return nil, err
   107  	}
   108  	for _, c := range ctrs {
   109  		err := c.Pause()
   110  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   111  	}
   112  	return report, nil
   113  }
   114  
   115  func (ic *ContainerEngine) ContainerUnpause(ctx context.Context, namesOrIds []string, options entities.PauseUnPauseOptions) ([]*entities.PauseUnpauseReport, error) {
   116  	var (
   117  		ctrs   []*libpod.Container
   118  		err    error
   119  		report []*entities.PauseUnpauseReport
   120  	)
   121  	if options.All {
   122  		ctrs, err = ic.Libpod.GetAllContainers()
   123  	} else {
   124  		ctrs, err = getContainersByContext(false, false, namesOrIds, ic.Libpod)
   125  	}
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  	for _, c := range ctrs {
   130  		err := c.Unpause()
   131  		report = append(report, &entities.PauseUnpauseReport{Id: c.ID(), Err: err})
   132  	}
   133  	return report, nil
   134  }
   135  func (ic *ContainerEngine) ContainerStop(ctx context.Context, namesOrIds []string, options entities.StopOptions) ([]*entities.StopReport, error) {
   136  	var (
   137  		reports []*entities.StopReport
   138  	)
   139  	names := namesOrIds
   140  	for _, cidFile := range options.CIDFiles {
   141  		content, err := ioutil.ReadFile(cidFile)
   142  		if err != nil {
   143  			return nil, errors.Wrap(err, "error reading CIDFile")
   144  		}
   145  		id := strings.Split(string(content), "\n")[0]
   146  		names = append(names, id)
   147  	}
   148  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
   149  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   150  		return nil, err
   151  	}
   152  	for _, con := range ctrs {
   153  		report := entities.StopReport{Id: con.ID()}
   154  		err = con.StopWithTimeout(options.Timeout)
   155  		if err != nil {
   156  			// These first two are considered non-fatal under the right conditions
   157  			if errors.Cause(err) == define.ErrCtrStopped {
   158  				logrus.Debugf("Container %s is already stopped", con.ID())
   159  				reports = append(reports, &report)
   160  				continue
   161  
   162  			} else if options.All && errors.Cause(err) == define.ErrCtrStateInvalid {
   163  				logrus.Debugf("Container %s is not running, could not stop", con.ID())
   164  				reports = append(reports, &report)
   165  				continue
   166  			}
   167  			report.Err = err
   168  			reports = append(reports, &report)
   169  			continue
   170  		}
   171  		reports = append(reports, &report)
   172  	}
   173  	return reports, nil
   174  }
   175  
   176  func (ic *ContainerEngine) ContainerKill(ctx context.Context, namesOrIds []string, options entities.KillOptions) ([]*entities.KillReport, error) {
   177  	var (
   178  		reports []*entities.KillReport
   179  	)
   180  	sig, err := signal.ParseSignalNameOrNumber(options.Signal)
   181  	if err != nil {
   182  		return nil, err
   183  	}
   184  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	for _, con := range ctrs {
   189  		reports = append(reports, &entities.KillReport{
   190  			Id:  con.ID(),
   191  			Err: con.Kill(uint(sig)),
   192  		})
   193  	}
   194  	return reports, nil
   195  }
   196  func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []string, options entities.RestartOptions) ([]*entities.RestartReport, error) {
   197  	var (
   198  		reports []*entities.RestartReport
   199  	)
   200  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	for _, con := range ctrs {
   205  		timeout := con.StopTimeout()
   206  		if options.Timeout != nil {
   207  			timeout = *options.Timeout
   208  		}
   209  		reports = append(reports, &entities.RestartReport{
   210  			Id:  con.ID(),
   211  			Err: con.RestartWithTimeout(ctx, timeout),
   212  		})
   213  	}
   214  	return reports, nil
   215  }
   216  
   217  func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
   218  	var (
   219  		reports []*entities.RmReport
   220  	)
   221  	if options.Storage {
   222  		for _, ctr := range namesOrIds {
   223  			report := entities.RmReport{Id: ctr}
   224  			if err := ic.Libpod.RemoveStorageContainer(ctr, options.Force); err != nil {
   225  				report.Err = err
   226  			}
   227  			reports = append(reports, &report)
   228  		}
   229  		return reports, nil
   230  	}
   231  
   232  	names := namesOrIds
   233  	for _, cidFile := range options.CIDFiles {
   234  		content, err := ioutil.ReadFile(cidFile)
   235  		if err != nil {
   236  			return nil, errors.Wrap(err, "error reading CIDFile")
   237  		}
   238  		id := strings.Split(string(content), "\n")[0]
   239  		names = append(names, id)
   240  	}
   241  
   242  	ctrs, err := getContainersByContext(options.All, options.Latest, names, ic.Libpod)
   243  	if err != nil && !(options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr) {
   244  		// Failed to get containers. If force is specified, get the containers ID
   245  		// and evict them
   246  		if !options.Force {
   247  			return nil, err
   248  		}
   249  
   250  		for _, ctr := range namesOrIds {
   251  			logrus.Debugf("Evicting container %q", ctr)
   252  			report := entities.RmReport{Id: ctr}
   253  			id, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
   254  			if err != nil {
   255  				if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
   256  					logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   257  					reports = append(reports, &report)
   258  					continue
   259  				}
   260  				report.Err = errors.Wrapf(err, "Failed to evict container: %q", id)
   261  				reports = append(reports, &report)
   262  				continue
   263  			}
   264  			reports = append(reports, &report)
   265  		}
   266  		return reports, nil
   267  	}
   268  
   269  	for _, c := range ctrs {
   270  		report := entities.RmReport{Id: c.ID()}
   271  		err := ic.Libpod.RemoveContainer(ctx, c, options.Force, options.Volumes)
   272  		if err != nil {
   273  			if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
   274  				logrus.Debugf("Ignoring error (--allow-missing): %v", err)
   275  				reports = append(reports, &report)
   276  				continue
   277  			}
   278  			logrus.Debugf("Failed to remove container %s: %s", c.ID(), err.Error())
   279  			report.Err = err
   280  			reports = append(reports, &report)
   281  			continue
   282  		}
   283  		reports = append(reports, &report)
   284  	}
   285  	return reports, nil
   286  }
   287  
   288  func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, error) {
   289  	var reports []*entities.ContainerInspectReport
   290  	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   291  	if err != nil {
   292  		return nil, err
   293  	}
   294  	for _, c := range ctrs {
   295  		data, err := c.Inspect(options.Size)
   296  		if err != nil {
   297  			return nil, err
   298  		}
   299  		reports = append(reports, &entities.ContainerInspectReport{InspectContainerData: data})
   300  	}
   301  	return reports, nil
   302  }
   303  
   304  func (ic *ContainerEngine) ContainerTop(ctx context.Context, options entities.TopOptions) (*entities.StringSliceReport, error) {
   305  	var (
   306  		container *libpod.Container
   307  		err       error
   308  	)
   309  
   310  	// Look up the container.
   311  	if options.Latest {
   312  		container, err = ic.Libpod.GetLatestContainer()
   313  	} else {
   314  		container, err = ic.Libpod.LookupContainer(options.NameOrID)
   315  	}
   316  	if err != nil {
   317  		return nil, errors.Wrap(err, "unable to lookup requested container")
   318  	}
   319  
   320  	// Run Top.
   321  	report := &entities.StringSliceReport{}
   322  	report.Value, err = container.Top(options.Descriptors)
   323  	return report, err
   324  }
   325  
   326  func (ic *ContainerEngine) ContainerCommit(ctx context.Context, nameOrId string, options entities.CommitOptions) (*entities.CommitReport, error) {
   327  	var (
   328  		mimeType string
   329  	)
   330  	ctr, err := ic.Libpod.LookupContainer(nameOrId)
   331  	if err != nil {
   332  		return nil, err
   333  	}
   334  	rtc, err := ic.Libpod.GetConfig()
   335  	if err != nil {
   336  		return nil, err
   337  	}
   338  	switch options.Format {
   339  	case "oci":
   340  		mimeType = buildah.OCIv1ImageManifest
   341  		if len(options.Message) > 0 {
   342  			return nil, errors.Errorf("messages are only compatible with the docker image format (-f docker)")
   343  		}
   344  	case "docker":
   345  		mimeType = manifest.DockerV2Schema2MediaType
   346  	default:
   347  		return nil, errors.Errorf("unrecognized image format %q", options.Format)
   348  	}
   349  	sc := image.GetSystemContext(rtc.Engine.SignaturePolicyPath, "", false)
   350  	coptions := buildah.CommitOptions{
   351  		SignaturePolicyPath:   rtc.Engine.SignaturePolicyPath,
   352  		ReportWriter:          options.Writer,
   353  		SystemContext:         sc,
   354  		PreferredManifestType: mimeType,
   355  	}
   356  	opts := libpod.ContainerCommitOptions{
   357  		CommitOptions:  coptions,
   358  		Pause:          options.Pause,
   359  		IncludeVolumes: options.IncludeVolumes,
   360  		Message:        options.Message,
   361  		Changes:        options.Changes,
   362  		Author:         options.Author,
   363  	}
   364  	newImage, err := ctr.Commit(ctx, options.ImageName, opts)
   365  	if err != nil {
   366  		return nil, err
   367  	}
   368  	return &entities.CommitReport{Id: newImage.ID()}, nil
   369  }
   370  
   371  func (ic *ContainerEngine) ContainerExport(ctx context.Context, nameOrId string, options entities.ContainerExportOptions) error {
   372  	ctr, err := ic.Libpod.LookupContainer(nameOrId)
   373  	if err != nil {
   374  		return err
   375  	}
   376  	return ctr.Export(options.Output)
   377  }
   378  
   379  func (ic *ContainerEngine) ContainerCheckpoint(ctx context.Context, namesOrIds []string, options entities.CheckpointOptions) ([]*entities.CheckpointReport, error) {
   380  	var (
   381  		err     error
   382  		cons    []*libpod.Container
   383  		reports []*entities.CheckpointReport
   384  	)
   385  	checkOpts := libpod.ContainerCheckpointOptions{
   386  		Keep:           options.Keep,
   387  		TCPEstablished: options.TCPEstablished,
   388  		TargetFile:     options.Export,
   389  		IgnoreRootfs:   options.IgnoreRootFS,
   390  	}
   391  
   392  	if options.All {
   393  		running := func(c *libpod.Container) bool {
   394  			state, _ := c.State()
   395  			return state == define.ContainerStateRunning
   396  		}
   397  		cons, err = ic.Libpod.GetContainers(running)
   398  	} else {
   399  		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   400  	}
   401  	if err != nil {
   402  		return nil, err
   403  	}
   404  	for _, con := range cons {
   405  		err = con.Checkpoint(ctx, checkOpts)
   406  		reports = append(reports, &entities.CheckpointReport{
   407  			Err: err,
   408  			Id:  con.ID(),
   409  		})
   410  	}
   411  	return reports, nil
   412  }
   413  
   414  func (ic *ContainerEngine) ContainerRestore(ctx context.Context, namesOrIds []string, options entities.RestoreOptions) ([]*entities.RestoreReport, error) {
   415  	var (
   416  		cons        []*libpod.Container
   417  		err         error
   418  		filterFuncs []libpod.ContainerFilter
   419  		reports     []*entities.RestoreReport
   420  	)
   421  
   422  	restoreOptions := libpod.ContainerCheckpointOptions{
   423  		Keep:            options.Keep,
   424  		TCPEstablished:  options.TCPEstablished,
   425  		TargetFile:      options.Import,
   426  		Name:            options.Name,
   427  		IgnoreRootfs:    options.IgnoreRootFS,
   428  		IgnoreStaticIP:  options.IgnoreStaticIP,
   429  		IgnoreStaticMAC: options.IgnoreStaticMAC,
   430  	}
   431  
   432  	filterFuncs = append(filterFuncs, func(c *libpod.Container) bool {
   433  		state, _ := c.State()
   434  		return state == define.ContainerStateExited
   435  	})
   436  
   437  	switch {
   438  	case options.Import != "":
   439  		cons, err = checkpoint.CRImportCheckpoint(ctx, ic.Libpod, options.Import, options.Name)
   440  	case options.All:
   441  		cons, err = ic.Libpod.GetContainers(filterFuncs...)
   442  	default:
   443  		cons, err = getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   444  	}
   445  	if err != nil {
   446  		return nil, err
   447  	}
   448  	for _, con := range cons {
   449  		err := con.Restore(ctx, restoreOptions)
   450  		reports = append(reports, &entities.RestoreReport{
   451  			Err: err,
   452  			Id:  con.ID(),
   453  		})
   454  	}
   455  	return reports, nil
   456  }
   457  
   458  func (ic *ContainerEngine) ContainerCreate(ctx context.Context, s *specgen.SpecGenerator) (*entities.ContainerCreateReport, error) {
   459  	if err := generate.CompleteSpec(ctx, ic.Libpod, s); err != nil {
   460  		return nil, err
   461  	}
   462  	ctr, err := generate.MakeContainer(ic.Libpod, s)
   463  	if err != nil {
   464  		return nil, err
   465  	}
   466  	return &entities.ContainerCreateReport{Id: ctr.ID()}, nil
   467  }
   468  
   469  func (ic *ContainerEngine) ContainerAttach(ctx context.Context, nameOrId string, options entities.AttachOptions) error {
   470  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
   471  	if err != nil {
   472  		return err
   473  	}
   474  	ctr := ctrs[0]
   475  	conState, err := ctr.State()
   476  	if err != nil {
   477  		return errors.Wrapf(err, "unable to determine state of %s", ctr.ID())
   478  	}
   479  	if conState != define.ContainerStateRunning {
   480  		return errors.Errorf("you can only attach to running containers")
   481  	}
   482  
   483  	// If the container is in a pod, also set to recursively start dependencies
   484  	if err := terminal.StartAttachCtr(ctx, ctr, options.Stdin, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, false, ctr.PodID() != ""); err != nil && errors.Cause(err) != define.ErrDetach {
   485  		return errors.Wrapf(err, "error attaching to container %s", ctr.ID())
   486  	}
   487  	return nil
   488  }
   489  
   490  func (ic *ContainerEngine) ContainerExec(ctx context.Context, nameOrId string, options entities.ExecOptions) (int, error) {
   491  	ec := define.ExecErrorCodeGeneric
   492  	if options.PreserveFDs > 0 {
   493  		entries, err := ioutil.ReadDir("/proc/self/fd")
   494  		if err != nil {
   495  			return ec, errors.Wrapf(err, "unable to read /proc/self/fd")
   496  		}
   497  
   498  		m := make(map[int]bool)
   499  		for _, e := range entries {
   500  			i, err := strconv.Atoi(e.Name())
   501  			if err != nil {
   502  				return ec, errors.Wrapf(err, "cannot parse %s in /proc/self/fd", e.Name())
   503  			}
   504  			m[i] = true
   505  		}
   506  
   507  		for i := 3; i < 3+int(options.PreserveFDs); i++ {
   508  			if _, found := m[i]; !found {
   509  				return ec, errors.New("invalid --preserve-fds=N specified. Not enough FDs available")
   510  			}
   511  		}
   512  	}
   513  	ctrs, err := getContainersByContext(false, options.Latest, []string{nameOrId}, ic.Libpod)
   514  	if err != nil {
   515  		return ec, err
   516  	}
   517  	ctr := ctrs[0]
   518  	ec, err = terminal.ExecAttachCtr(ctx, ctr, options.Tty, options.Privileged, options.Envs, options.Cmd, options.User, options.WorkDir, &options.Streams, options.PreserveFDs, options.DetachKeys)
   519  	return define.TranslateExecErrorToExitCode(ec, err), err
   520  }
   521  
   522  func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
   523  	var reports []*entities.ContainerStartReport
   524  	var exitCode = define.ExecErrorCodeGeneric
   525  	ctrs, err := getContainersByContext(false, options.Latest, namesOrIds, ic.Libpod)
   526  	if err != nil {
   527  		return nil, err
   528  	}
   529  	// There can only be one container if attach was used
   530  	for _, ctr := range ctrs {
   531  		ctrState, err := ctr.State()
   532  		if err != nil {
   533  			return nil, err
   534  		}
   535  		ctrRunning := ctrState == define.ContainerStateRunning
   536  
   537  		if options.Attach {
   538  			err = terminal.StartAttachCtr(ctx, ctr, options.Stdout, options.Stderr, options.Stdin, options.DetachKeys, options.SigProxy, !ctrRunning, ctr.PodID() != "")
   539  			if errors.Cause(err) == define.ErrDetach {
   540  				// User manually detached
   541  				// Exit cleanly immediately
   542  				reports = append(reports, &entities.ContainerStartReport{
   543  					Id:       ctr.ID(),
   544  					Err:      nil,
   545  					ExitCode: 0,
   546  				})
   547  				return reports, nil
   548  			}
   549  
   550  			if errors.Cause(err) == define.ErrWillDeadlock {
   551  				logrus.Debugf("Deadlock error: %v", err)
   552  				reports = append(reports, &entities.ContainerStartReport{
   553  					Id:       ctr.ID(),
   554  					Err:      err,
   555  					ExitCode: define.ExitCode(err),
   556  				})
   557  				return reports, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
   558  			}
   559  
   560  			if ctrRunning {
   561  				reports = append(reports, &entities.ContainerStartReport{
   562  					Id:       ctr.ID(),
   563  					Err:      nil,
   564  					ExitCode: 0,
   565  				})
   566  				return reports, err
   567  			}
   568  
   569  			if err != nil {
   570  				reports = append(reports, &entities.ContainerStartReport{
   571  					Id:       ctr.ID(),
   572  					Err:      err,
   573  					ExitCode: exitCode,
   574  				})
   575  				return reports, errors.Wrapf(err, "unable to start container %s", ctr.ID())
   576  			}
   577  
   578  			if ecode, err := ctr.Wait(); err != nil {
   579  				if errors.Cause(err) == define.ErrNoSuchCtr {
   580  					// Check events
   581  					event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited)
   582  					if err != nil {
   583  						logrus.Errorf("Cannot get exit code: %v", err)
   584  						exitCode = define.ExecErrorCodeNotFound
   585  					} else {
   586  						exitCode = event.ContainerExitCode
   587  					}
   588  				}
   589  			} else {
   590  				exitCode = int(ecode)
   591  			}
   592  			reports = append(reports, &entities.ContainerStartReport{
   593  				Id:       ctr.ID(),
   594  				Err:      err,
   595  				ExitCode: exitCode,
   596  			})
   597  			return reports, nil
   598  		} // end attach
   599  
   600  		// Start the container if it's not running already.
   601  		if !ctrRunning {
   602  			// Handle non-attach start
   603  			// If the container is in a pod, also set to recursively start dependencies
   604  			report := &entities.ContainerStartReport{
   605  				Id:       ctr.ID(),
   606  				ExitCode: 125,
   607  			}
   608  			if err := ctr.Start(ctx, ctr.PodID() != ""); err != nil {
   609  				// if lastError != nil {
   610  				//	fmt.Fprintln(os.Stderr, lastError)
   611  				// }
   612  				report.Err = err
   613  				if errors.Cause(err) == define.ErrWillDeadlock {
   614  					report.Err = errors.Wrapf(err, "please run 'podman system renumber' to resolve deadlocks")
   615  					reports = append(reports, report)
   616  					continue
   617  				}
   618  				report.Err = errors.Wrapf(err, "unable to start container %q", ctr.ID())
   619  				reports = append(reports, report)
   620  				continue
   621  			}
   622  			report.ExitCode = 0
   623  			reports = append(reports, report)
   624  		}
   625  	}
   626  	return reports, nil
   627  }
   628  
   629  func (ic *ContainerEngine) ContainerList(ctx context.Context, options entities.ContainerListOptions) ([]entities.ListContainer, error) {
   630  	return ps.GetContainerLists(ic.Libpod, options)
   631  }
   632  
   633  // ContainerDiff provides changes to given container
   634  func (ic *ContainerEngine) ContainerDiff(ctx context.Context, nameOrId string, opts entities.DiffOptions) (*entities.DiffReport, error) {
   635  	if opts.Latest {
   636  		ctnr, err := ic.Libpod.GetLatestContainer()
   637  		if err != nil {
   638  			return nil, errors.Wrap(err, "unable to get latest container")
   639  		}
   640  		nameOrId = ctnr.ID()
   641  	}
   642  	changes, err := ic.Libpod.GetDiff("", nameOrId)
   643  	return &entities.DiffReport{Changes: changes}, err
   644  }
   645  
   646  func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.ContainerRunOptions) (*entities.ContainerRunReport, error) {
   647  	var (
   648  		joinPod bool
   649  	)
   650  	if err := generate.CompleteSpec(ctx, ic.Libpod, opts.Spec); err != nil {
   651  		return nil, err
   652  	}
   653  	ctr, err := generate.MakeContainer(ic.Libpod, opts.Spec)
   654  	if err != nil {
   655  		return nil, err
   656  	}
   657  
   658  	if len(ctr.PodID()) > 0 {
   659  		joinPod = true
   660  	}
   661  	report := entities.ContainerRunReport{Id: ctr.ID()}
   662  
   663  	if logrus.GetLevel() == logrus.DebugLevel {
   664  		cgroupPath, err := ctr.CGroupPath()
   665  		if err == nil {
   666  			logrus.Debugf("container %q has CgroupParent %q", ctr.ID(), cgroupPath)
   667  		}
   668  	}
   669  	if opts.Detach {
   670  		// if the container was created as part of a pod, also start its dependencies, if any.
   671  		if err := ctr.Start(ctx, joinPod); err != nil {
   672  			// This means the command did not exist
   673  			report.ExitCode = define.ExitCode(err)
   674  			return &report, err
   675  		}
   676  
   677  		return &report, nil
   678  	}
   679  
   680  	// if the container was created as part of a pod, also start its dependencies, if any.
   681  	if err := terminal.StartAttachCtr(ctx, ctr, opts.OutputStream, opts.ErrorStream, opts.InputStream, opts.DetachKeys, opts.SigProxy, true, joinPod); err != nil {
   682  		// We've manually detached from the container
   683  		// Do not perform cleanup, or wait for container exit code
   684  		// Just exit immediately
   685  		if errors.Cause(err) == define.ErrDetach {
   686  			report.ExitCode = 0
   687  			return &report, nil
   688  		}
   689  		if opts.Rm {
   690  			if deleteError := ic.Libpod.RemoveContainer(ctx, ctr, true, false); deleteError != nil {
   691  				logrus.Debugf("unable to remove container %s after failing to start and attach to it", ctr.ID())
   692  			}
   693  		}
   694  		if errors.Cause(err) == define.ErrWillDeadlock {
   695  			logrus.Debugf("Deadlock error on %q: %v", ctr.ID(), err)
   696  			report.ExitCode = define.ExitCode(err)
   697  			return &report, errors.Errorf("attempting to start container %s would cause a deadlock; please run 'podman system renumber' to resolve", ctr.ID())
   698  		}
   699  		report.ExitCode = define.ExitCode(err)
   700  		return &report, err
   701  	}
   702  
   703  	if ecode, err := ctr.Wait(); err != nil {
   704  		if errors.Cause(err) == define.ErrNoSuchCtr {
   705  			// Check events
   706  			event, err := ic.Libpod.GetLastContainerEvent(ctr.ID(), events.Exited)
   707  			if err != nil {
   708  				logrus.Errorf("Cannot get exit code: %v", err)
   709  				report.ExitCode = define.ExecErrorCodeNotFound
   710  			} else {
   711  				report.ExitCode = event.ContainerExitCode
   712  			}
   713  		}
   714  	} else {
   715  		report.ExitCode = int(ecode)
   716  	}
   717  	return &report, nil
   718  }
   719  
   720  func (ic *ContainerEngine) ContainerLogs(ctx context.Context, containers []string, options entities.ContainerLogsOptions) error {
   721  	if options.Writer == nil {
   722  		return errors.New("no io.Writer set for container logs")
   723  	}
   724  
   725  	var wg sync.WaitGroup
   726  
   727  	ctrs, err := getContainersByContext(false, options.Latest, containers, ic.Libpod)
   728  	if err != nil {
   729  		return err
   730  	}
   731  
   732  	logOpts := &logs.LogOptions{
   733  		Multi:      len(ctrs) > 1,
   734  		Details:    options.Details,
   735  		Follow:     options.Follow,
   736  		Since:      options.Since,
   737  		Tail:       options.Tail,
   738  		Timestamps: options.Timestamps,
   739  		UseName:    options.Names,
   740  		WaitGroup:  &wg,
   741  	}
   742  
   743  	chSize := len(ctrs) * int(options.Tail)
   744  	if chSize <= 0 {
   745  		chSize = 1
   746  	}
   747  	logChannel := make(chan *logs.LogLine, chSize)
   748  
   749  	if err := ic.Libpod.Log(ctrs, logOpts, logChannel); err != nil {
   750  		return err
   751  	}
   752  
   753  	go func() {
   754  		wg.Wait()
   755  		close(logChannel)
   756  	}()
   757  
   758  	for line := range logChannel {
   759  		fmt.Fprintln(options.Writer, line.String(logOpts))
   760  	}
   761  
   762  	return nil
   763  }
   764  
   765  func (ic *ContainerEngine) ContainerCleanup(ctx context.Context, namesOrIds []string, options entities.ContainerCleanupOptions) ([]*entities.ContainerCleanupReport, error) {
   766  	var reports []*entities.ContainerCleanupReport
   767  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   768  	if err != nil {
   769  		return nil, err
   770  	}
   771  	for _, ctr := range ctrs {
   772  		var err error
   773  		report := entities.ContainerCleanupReport{Id: ctr.ID()}
   774  		if options.Remove {
   775  			err = ic.Libpod.RemoveContainer(ctx, ctr, false, true)
   776  			if err != nil {
   777  				report.RmErr = errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
   778  			}
   779  		} else {
   780  			err := ctr.Cleanup(ctx)
   781  			if err != nil {
   782  				report.CleanErr = errors.Wrapf(err, "failed to cleanup container %v", ctr.ID())
   783  			}
   784  		}
   785  
   786  		if options.RemoveImage {
   787  			_, imageName := ctr.Image()
   788  			ctrImage, err := ic.Libpod.ImageRuntime().NewFromLocal(imageName)
   789  			if err != nil {
   790  				report.RmiErr = err
   791  				reports = append(reports, &report)
   792  				continue
   793  			}
   794  			_, err = ic.Libpod.RemoveImage(ctx, ctrImage, false)
   795  			report.RmiErr = err
   796  		}
   797  		reports = append(reports, &report)
   798  	}
   799  	return reports, nil
   800  }
   801  
   802  func (ic *ContainerEngine) ContainerInit(ctx context.Context, namesOrIds []string, options entities.ContainerInitOptions) ([]*entities.ContainerInitReport, error) {
   803  	var reports []*entities.ContainerInitReport
   804  	ctrs, err := getContainersByContext(options.All, options.Latest, namesOrIds, ic.Libpod)
   805  	if err != nil {
   806  		return nil, err
   807  	}
   808  	for _, ctr := range ctrs {
   809  		report := entities.ContainerInitReport{Id: ctr.ID()}
   810  		report.Err = ctr.Init(ctx)
   811  		reports = append(reports, &report)
   812  	}
   813  	return reports, nil
   814  }
   815  
   816  func (ic *ContainerEngine) ContainerMount(ctx context.Context, nameOrIds []string, options entities.ContainerMountOptions) ([]*entities.ContainerMountReport, error) {
   817  	if os.Geteuid() != 0 {
   818  		if driver := ic.Libpod.StorageConfig().GraphDriverName; driver != "vfs" {
   819  			// Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part
   820  			// of the mount command.
   821  			return nil, fmt.Errorf("cannot mount using driver %s in rootless mode", driver)
   822  		}
   823  
   824  		became, ret, err := rootless.BecomeRootInUserNS("")
   825  		if err != nil {
   826  			return nil, err
   827  		}
   828  		if became {
   829  			os.Exit(ret)
   830  		}
   831  	}
   832  	var reports []*entities.ContainerMountReport
   833  	ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
   834  	if err != nil {
   835  		return nil, err
   836  	}
   837  	for _, ctr := range ctrs {
   838  		report := entities.ContainerMountReport{Id: ctr.ID()}
   839  		report.Path, report.Err = ctr.Mount()
   840  		reports = append(reports, &report)
   841  	}
   842  	if len(reports) > 0 {
   843  		return reports, nil
   844  	}
   845  
   846  	// No containers were passed, so we send back what is mounted
   847  	ctrs, err = getContainersByContext(true, false, []string{}, ic.Libpod)
   848  	if err != nil {
   849  		return nil, err
   850  	}
   851  	for _, ctr := range ctrs {
   852  		mounted, path, err := ctr.Mounted()
   853  		if err != nil {
   854  			return nil, err
   855  		}
   856  
   857  		if mounted {
   858  			reports = append(reports, &entities.ContainerMountReport{
   859  				Id:   ctr.ID(),
   860  				Name: ctr.Name(),
   861  				Path: path,
   862  			})
   863  		}
   864  	}
   865  	return reports, nil
   866  }
   867  
   868  func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []string, options entities.ContainerUnmountOptions) ([]*entities.ContainerUnmountReport, error) {
   869  	var reports []*entities.ContainerUnmountReport
   870  	ctrs, err := getContainersByContext(options.All, options.Latest, nameOrIds, ic.Libpod)
   871  	if err != nil {
   872  		return nil, err
   873  	}
   874  	for _, ctr := range ctrs {
   875  		state, err := ctr.State()
   876  		if err != nil {
   877  			logrus.Debugf("Error umounting container %s state: %s", ctr.ID(), err.Error())
   878  			continue
   879  		}
   880  		if state == define.ContainerStateRunning {
   881  			logrus.Debugf("Error umounting container %s, is running", ctr.ID())
   882  			continue
   883  		}
   884  
   885  		report := entities.ContainerUnmountReport{Id: ctr.ID()}
   886  		if err := ctr.Unmount(options.Force); err != nil {
   887  			if options.All && errors.Cause(err) == storage.ErrLayerNotMounted {
   888  				logrus.Debugf("Error umounting container %s, storage.ErrLayerNotMounted", ctr.ID())
   889  				continue
   890  			}
   891  			report.Err = errors.Wrapf(err, "error unmounting container %s", ctr.ID())
   892  		}
   893  		reports = append(reports, &report)
   894  	}
   895  	return reports, nil
   896  }
   897  
   898  // GetConfig returns a copy of the configuration used by the runtime
   899  func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
   900  	return ic.Libpod.GetConfig()
   901  }