diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index e9afcbc06a..5b2581216c 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -16,7 +16,6 @@ func getMainCommands() []*cobra.Command {
 		_execCommand,
 		_generateCommand,
 		_playCommand,
-		&_psCommand,
 		_loginCommand,
 		_logoutCommand,
 		_mountCommand,
diff --git a/cmd/podman/main.go b/cmd/podman/main.go
index b44cf9f0a4..52bf2daf0a 100644
--- a/cmd/podman/main.go
+++ b/cmd/podman/main.go
@@ -52,6 +52,7 @@ var mainCommands = []*cobra.Command{
 	_loadCommand,
 	_logsCommand,
 	podCommand.Command,
+	&_psCommand,
 	_pullCommand,
 	_pushCommand,
 	&_rmiCommand,
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 759a03b86b..59376b6aa0 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -6,7 +6,6 @@ import (
 	"os"
 	"reflect"
 	"sort"
-	"strconv"
 	"strings"
 	"text/tabwriter"
 	"time"
@@ -14,15 +13,12 @@ import (
 	tm "github.com/buger/goterm"
 	"github.com/containers/buildah/pkg/formats"
 	"github.com/containers/libpod/cmd/podman/cliconfig"
-	"github.com/containers/libpod/cmd/podman/libpodruntime"
 	"github.com/containers/libpod/cmd/podman/shared"
-	"github.com/containers/libpod/libpod"
-	"github.com/containers/libpod/pkg/util"
+	"github.com/containers/libpod/pkg/adapter"
 	"github.com/cri-o/ocicni/pkg/ocicni"
 	"github.com/docker/go-units"
 	"github.com/opentracing/opentracing-go"
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"github.com/spf13/cobra"
 	"k8s.io/apimachinery/pkg/fields"
 )
@@ -224,7 +220,7 @@ func psCmd(c *cliconfig.PsValues) error {
 		return errors.Wrapf(err, "error with flags passed")
 	}
 
-	runtime, err := libpodruntime.GetRuntime(&c.PodmanCommand)
+	runtime, err := adapter.GetRuntime(&c.PodmanCommand)
 	if err != nil {
 		return errors.Wrapf(err, "error creating libpod runtime")
 	}
@@ -279,128 +275,6 @@ func checkFlagsPassed(c *cliconfig.PsValues) error {
 	return nil
 }
 
-func generateContainerFilterFuncs(filter, filterValue string, runtime *libpod.Runtime) (func(container *libpod.Container) bool, error) {
-	switch filter {
-	case "id":
-		return func(c *libpod.Container) bool {
-			return strings.Contains(c.ID(), filterValue)
-		}, nil
-	case "label":
-		var filterArray []string = strings.SplitN(filterValue, "=", 2)
-		var filterKey string = filterArray[0]
-		if len(filterArray) > 1 {
-			filterValue = filterArray[1]
-		} else {
-			filterValue = ""
-		}
-		return func(c *libpod.Container) bool {
-			for labelKey, labelValue := range c.Labels() {
-				if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
-					return true
-				}
-			}
-			return false
-		}, nil
-	case "name":
-		return func(c *libpod.Container) bool {
-			return strings.Contains(c.Name(), filterValue)
-		}, nil
-	case "exited":
-		exitCode, err := strconv.ParseInt(filterValue, 10, 32)
-		if err != nil {
-			return nil, errors.Wrapf(err, "exited code out of range %q", filterValue)
-		}
-		return func(c *libpod.Container) bool {
-			ec, exited, err := c.ExitCode()
-			if ec == int32(exitCode) && err == nil && exited == true {
-				return true
-			}
-			return false
-		}, nil
-	case "status":
-		if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
-			return nil, errors.Errorf("%s is not a valid status", filterValue)
-		}
-		return func(c *libpod.Container) bool {
-			status, err := c.State()
-			if err != nil {
-				return false
-			}
-			if filterValue == "stopped" {
-				filterValue = "exited"
-			}
-			state := status.String()
-			if status == libpod.ContainerStateConfigured {
-				state = "created"
-			} else if status == libpod.ContainerStateStopped {
-				state = "exited"
-			}
-			return state == filterValue
-		}, nil
-	case "ancestor":
-		// This needs to refine to match docker
-		// - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
-		return func(c *libpod.Container) bool {
-			containerConfig := c.Config()
-			if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
-				return true
-			}
-			return false
-		}, nil
-	case "before":
-		ctr, err := runtime.LookupContainer(filterValue)
-		if err != nil {
-			return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
-		}
-		containerConfig := ctr.Config()
-		createTime := containerConfig.CreatedTime
-		return func(c *libpod.Container) bool {
-			cc := c.Config()
-			return createTime.After(cc.CreatedTime)
-		}, nil
-	case "since":
-		ctr, err := runtime.LookupContainer(filterValue)
-		if err != nil {
-			return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
-		}
-		containerConfig := ctr.Config()
-		createTime := containerConfig.CreatedTime
-		return func(c *libpod.Container) bool {
-			cc := c.Config()
-			return createTime.Before(cc.CreatedTime)
-		}, nil
-	case "volume":
-		//- volume=(<volume-name>|<mount-point-destination>)
-		return func(c *libpod.Container) bool {
-			containerConfig := c.Config()
-			var dest string
-			arr := strings.Split(filterValue, ":")
-			source := arr[0]
-			if len(arr) == 2 {
-				dest = arr[1]
-			}
-			for _, mount := range containerConfig.Spec.Mounts {
-				if dest != "" && (mount.Source == source && mount.Destination == dest) {
-					return true
-				}
-				if dest == "" && mount.Source == source {
-					return true
-				}
-			}
-			return false
-		}, nil
-	case "health":
-		return func(c *libpod.Container) bool {
-			hcStatus, err := c.HealthCheckStatus()
-			if err != nil {
-				return false
-			}
-			return hcStatus == filterValue
-		}, nil
-	}
-	return nil, errors.Errorf("%s is an invalid filter", filter)
-}
-
 // generate the accurate header based on template given
 func (p *psTemplateParams) headerMap() map[string]string {
 	v := reflect.Indirect(reflect.ValueOf(p))
@@ -550,11 +424,9 @@ func dumpJSON(containers []shared.PsContainerOutput) error {
 	return nil
 }
 
-func psDisplay(c *cliconfig.PsValues, runtime *libpod.Runtime) error {
+func psDisplay(c *cliconfig.PsValues, runtime *adapter.LocalRuntime) error {
 	var (
-		filterFuncs      []libpod.ContainerFilter
-		outputContainers []*libpod.Container
-		err              error
+		err error
 	)
 	opts := shared.PsOptions{
 		All:       c.All,
@@ -570,51 +442,8 @@ func psDisplay(c *cliconfig.PsValues, runtime *libpod.Runtime) error {
 		Sync:      c.Sync,
 	}
 
-	maxWorkers := shared.Parallelize("ps")
-	if c.GlobalIsSet("max-workers") {
-		maxWorkers = c.GlobalFlags.MaxWorks
-	}
-	logrus.Debugf("Setting maximum workers to %d", maxWorkers)
-
-	filters := c.Filter
-	if len(filters) > 0 {
-		for _, f := range filters {
-			filterSplit := strings.SplitN(f, "=", 2)
-			if len(filterSplit) < 2 {
-				return errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
-			}
-			generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], runtime)
-			if err != nil {
-				return errors.Wrapf(err, "invalid filter")
-			}
-			filterFuncs = append(filterFuncs, generatedFunc)
-		}
-	}
-	if !opts.Latest {
-		// Get all containers
-		containers, err := runtime.GetContainers(filterFuncs...)
-		if err != nil {
-			return err
-		}
-
-		// We only want the last few containers
-		if opts.Last > 0 && opts.Last <= len(containers) {
-			return errors.Errorf("--last not yet supported")
-		} else {
-			outputContainers = containers
-		}
-	} else {
-		// Get just the latest container
-		// Ignore filters
-		latestCtr, err := runtime.GetLatestContainer()
-		if err != nil {
-			return err
-		}
-
-		outputContainers = []*libpod.Container{latestCtr}
-	}
-
-	pss := shared.PBatch(outputContainers, maxWorkers, opts)
+	pss, err := runtime.Ps(c, opts)
+	// Here and down
 	if opts.Sort != "" {
 		pss, err = sortPsOutput(opts.Sort, pss)
 		if err != nil {
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index 6826191c52..7bef623555 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -44,7 +44,6 @@ type PsOptions struct {
 	Quiet     bool
 	Size      bool
 	Sort      string
-	Label     string
 	Namespace bool
 	Sync      bool
 }
@@ -274,6 +273,176 @@ func worker(wg *sync.WaitGroup, jobs <-chan workerInput, results chan<- PsContai
 	}
 }
 
+func generateContainerFilterFuncs(filter, filterValue string, r *libpod.Runtime) (func(container *libpod.Container) bool, error) {
+	switch filter {
+	case "id":
+		return func(c *libpod.Container) bool {
+			return strings.Contains(c.ID(), filterValue)
+		}, nil
+	case "label":
+		var filterArray []string = strings.SplitN(filterValue, "=", 2)
+		var filterKey string = filterArray[0]
+		if len(filterArray) > 1 {
+			filterValue = filterArray[1]
+		} else {
+			filterValue = ""
+		}
+		return func(c *libpod.Container) bool {
+			for labelKey, labelValue := range c.Labels() {
+				if labelKey == filterKey && ("" == filterValue || labelValue == filterValue) {
+					return true
+				}
+			}
+			return false
+		}, nil
+	case "name":
+		return func(c *libpod.Container) bool {
+			return strings.Contains(c.Name(), filterValue)
+		}, nil
+	case "exited":
+		exitCode, err := strconv.ParseInt(filterValue, 10, 32)
+		if err != nil {
+			return nil, errors.Wrapf(err, "exited code out of range %q", filterValue)
+		}
+		return func(c *libpod.Container) bool {
+			ec, exited, err := c.ExitCode()
+			if ec == int32(exitCode) && err == nil && exited == true {
+				return true
+			}
+			return false
+		}, nil
+	case "status":
+		if !util.StringInSlice(filterValue, []string{"created", "running", "paused", "stopped", "exited", "unknown"}) {
+			return nil, errors.Errorf("%s is not a valid status", filterValue)
+		}
+		return func(c *libpod.Container) bool {
+			status, err := c.State()
+			if err != nil {
+				return false
+			}
+			if filterValue == "stopped" {
+				filterValue = "exited"
+			}
+			state := status.String()
+			if status == libpod.ContainerStateConfigured {
+				state = "created"
+			} else if status == libpod.ContainerStateStopped {
+				state = "exited"
+			}
+			return state == filterValue
+		}, nil
+	case "ancestor":
+		// This needs to refine to match docker
+		// - ancestor=(<image-name>[:tag]|<image-id>| ⟨image@digest⟩) - containers created from an image or a descendant.
+		return func(c *libpod.Container) bool {
+			containerConfig := c.Config()
+			if strings.Contains(containerConfig.RootfsImageID, filterValue) || strings.Contains(containerConfig.RootfsImageName, filterValue) {
+				return true
+			}
+			return false
+		}, nil
+	case "before":
+		ctr, err := r.LookupContainer(filterValue)
+		if err != nil {
+			return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
+		}
+		containerConfig := ctr.Config()
+		createTime := containerConfig.CreatedTime
+		return func(c *libpod.Container) bool {
+			cc := c.Config()
+			return createTime.After(cc.CreatedTime)
+		}, nil
+	case "since":
+		ctr, err := r.LookupContainer(filterValue)
+		if err != nil {
+			return nil, errors.Errorf("unable to find container by name or id of %s", filterValue)
+		}
+		containerConfig := ctr.Config()
+		createTime := containerConfig.CreatedTime
+		return func(c *libpod.Container) bool {
+			cc := c.Config()
+			return createTime.Before(cc.CreatedTime)
+		}, nil
+	case "volume":
+		//- volume=(<volume-name>|<mount-point-destination>)
+		return func(c *libpod.Container) bool {
+			containerConfig := c.Config()
+			var dest string
+			arr := strings.Split(filterValue, ":")
+			source := arr[0]
+			if len(arr) == 2 {
+				dest = arr[1]
+			}
+			for _, mount := range containerConfig.Spec.Mounts {
+				if dest != "" && (mount.Source == source && mount.Destination == dest) {
+					return true
+				}
+				if dest == "" && mount.Source == source {
+					return true
+				}
+			}
+			return false
+		}, nil
+	case "health":
+		return func(c *libpod.Container) bool {
+			hcStatus, err := c.HealthCheckStatus()
+			if err != nil {
+				return false
+			}
+			return hcStatus == filterValue
+		}, nil
+	}
+	return nil, errors.Errorf("%s is an invalid filter", filter)
+}
+
+// GetPsContainerOutput returns a slice of containers specifically for ps output
+func GetPsContainerOutput(r *libpod.Runtime, opts PsOptions, filters []string, maxWorkers int) ([]PsContainerOutput, error) {
+	var (
+		filterFuncs      []libpod.ContainerFilter
+		outputContainers []*libpod.Container
+	)
+
+	if len(filters) > 0 {
+		for _, f := range filters {
+			filterSplit := strings.SplitN(f, "=", 2)
+			if len(filterSplit) < 2 {
+				return nil, errors.Errorf("filter input must be in the form of filter=value: %s is invalid", f)
+			}
+			generatedFunc, err := generateContainerFilterFuncs(filterSplit[0], filterSplit[1], r)
+			if err != nil {
+				return nil, errors.Wrapf(err, "invalid filter")
+			}
+			filterFuncs = append(filterFuncs, generatedFunc)
+		}
+	}
+	if !opts.Latest {
+		// Get all containers
+		containers, err := r.GetContainers(filterFuncs...)
+		if err != nil {
+			return nil, err
+		}
+
+		// We only want the last few containers
+		if opts.Last > 0 && opts.Last <= len(containers) {
+			return nil, errors.Errorf("--last not yet supported")
+		} else {
+			outputContainers = containers
+		}
+	} else {
+		// Get just the latest container
+		// Ignore filters
+		latestCtr, err := r.GetLatestContainer()
+		if err != nil {
+			return nil, err
+		}
+
+		outputContainers = []*libpod.Container{latestCtr}
+	}
+
+	pss := PBatch(outputContainers, maxWorkers, opts)
+	return pss, nil
+}
+
 // PBatch is performs batch operations on a container in parallel. It spawns the number of workers
 // relative to the the number of parallel operations desired.
 func PBatch(containers []*libpod.Container, workers int, opts PsOptions) []PsContainerOutput {
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 9098a9297a..d8905326c3 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -133,6 +133,47 @@ type ContainerStats (
     pids: int
 )
 
+type PsOpts (
+    all: bool,
+    filters: ?[]string,
+    last: ?int,
+    latest: ?bool,
+    noTrunc: ?bool,
+	pod: ?bool,
+	quiet: ?bool,
+	sort: ?string,
+	sync: ?bool
+)
+
+type PsContainer (
+    id: string,
+    image: string,
+    command: string,
+    created: string,
+    ports: string,
+    names: string,
+    isInfra: bool,
+    status: string,
+    state: string,
+    pidNum: int,
+    rootFsSize: int,
+    rwSize: int,
+    pod: string,
+    createdAt: string,
+    exitedAt: string,
+    startedAt: string,
+    labels: [string]string,
+    nsPid: string,
+    cgroup: string,
+    ipc: string,
+    mnt: string,
+    net: string,
+    pidNs: string,
+    user: string,
+    uts: string,
+    mounts: string
+)
+
 # ContainerMount describes the struct for mounts in a container
 type ContainerMount (
     destination: string,
@@ -474,6 +515,8 @@ method GetInfo() -> (info: PodmanInfo)
 # See also [GetContainer](#GetContainer).
 method ListContainers() -> (containers: []Container)
 
+method Ps(opts: PsOpts) -> (containers: []PsContainer)
+
 # GetContainer returns information about a single container.  If a container
 # with the given id doesn't exist, a [ContainerNotFound](#ContainerNotFound)
 # error will be returned.  See also [ListContainers](ListContainers) and
diff --git a/libpod/container.go b/libpod/container.go
index 6d5e063ab0..523e571b1d 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -401,6 +401,29 @@ func (t ContainerStatus) String() string {
 	return "bad state"
 }
 
+// StringToContainerStatus converts a string representation of a containers
+// status into an actual container status type
+func StringToContainerStatus(status string) (ContainerStatus, error) {
+	switch status {
+	case ContainerStateUnknown.String():
+		return ContainerStateUnknown, nil
+	case ContainerStateConfigured.String():
+		return ContainerStateConfigured, nil
+	case ContainerStateCreated.String():
+		return ContainerStateCreated, nil
+	case ContainerStateRunning.String():
+		return ContainerStateRunning, nil
+	case ContainerStateStopped.String():
+		return ContainerStateStopped, nil
+	case ContainerStatePaused.String():
+		return ContainerStatePaused, nil
+	case ContainerStateExited.String():
+		return ContainerStateExited, nil
+	default:
+		return ContainerStateUnknown, errors.Wrapf(ErrInvalidArg, "unknown container state: %s", status)
+	}
+}
+
 // Config accessors
 // Unlocked
 
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 1bca99cecc..598cde98e6 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -304,3 +304,13 @@ func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
 
 	return exitCode, nil
 }
+
+// Ps ...
+func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) {
+	maxWorkers := shared.Parallelize("ps")
+	if c.GlobalIsSet("max-workers") {
+		maxWorkers = c.GlobalFlags.MaxWorks
+	}
+	logrus.Debugf("Setting maximum workers to %d", maxWorkers)
+	return shared.GetPsContainerOutput(r.Runtime, opts, c.Filter, maxWorkers)
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 3730827c73..79177f5ff4 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -292,3 +292,75 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
 func ReadExitFile(runtimeTmp, ctrID string) (int, error) {
 	return 0, libpod.ErrNotImplemented
 }
+
+// Ps ...
+func (r *LocalRuntime) Ps(c *cliconfig.PsValues, opts shared.PsOptions) ([]shared.PsContainerOutput, error) {
+	var psContainers []shared.PsContainerOutput
+	last := int64(c.Last)
+	PsOpts := iopodman.PsOpts{
+		All:     c.All,
+		Filters: &c.Filter,
+		Last:    &last,
+		Latest:  &c.Latest,
+		NoTrunc: &c.NoTrunct,
+		Pod:     &c.Pod,
+		Quiet:   &c.Quiet,
+		Sort:    &c.Sort,
+		Sync:    &c.Sync,
+	}
+	containers, err := iopodman.Ps().Call(r.Conn, PsOpts)
+	if err != nil {
+		return nil, err
+	}
+	for _, ctr := range containers {
+		createdAt, err := time.Parse(time.RFC3339Nano, ctr.CreatedAt)
+		if err != nil {
+			return nil, err
+		}
+		exitedAt, err := time.Parse(time.RFC3339Nano, ctr.ExitedAt)
+		if err != nil {
+			return nil, err
+		}
+		startedAt, err := time.Parse(time.RFC3339Nano, ctr.StartedAt)
+		if err != nil {
+			return nil, err
+		}
+		containerSize := shared.ContainerSize{
+			RootFsSize: ctr.RootFsSize,
+			RwSize:     ctr.RwSize,
+		}
+		state, err := libpod.StringToContainerStatus(ctr.State)
+		if err != nil {
+			return nil, err
+		}
+		psc := shared.PsContainerOutput{
+			ID:        ctr.Id,
+			Image:     ctr.Image,
+			Command:   ctr.Command,
+			Created:   ctr.Created,
+			Ports:     ctr.Ports,
+			Names:     ctr.Names,
+			IsInfra:   ctr.IsInfra,
+			Status:    ctr.Status,
+			State:     state,
+			Pid:       int(ctr.PidNum),
+			Size:      &containerSize,
+			Pod:       ctr.Pod,
+			CreatedAt: createdAt,
+			ExitedAt:  exitedAt,
+			StartedAt: startedAt,
+			Labels:    ctr.Labels,
+			PID:       ctr.NsPid,
+			Cgroup:    ctr.Cgroup,
+			IPC:       ctr.Ipc,
+			MNT:       ctr.Mnt,
+			NET:       ctr.Net,
+			PIDNS:     ctr.PidNs,
+			User:      ctr.User,
+			UTS:       ctr.Uts,
+			Mounts:    ctr.Mounts,
+		}
+		psContainers = append(psContainers, psc)
+	}
+	return psContainers, nil
+}
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index ac1352dac3..816a729535 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -47,6 +47,55 @@ func (i *LibpodAPI) ListContainers(call iopodman.VarlinkCall) error {
 	return call.ReplyListContainers(listContainers)
 }
 
+func (i *LibpodAPI) Ps(call iopodman.VarlinkCall, opts iopodman.PsOpts) error {
+	var (
+		containers []iopodman.PsContainer
+	)
+	maxWorkers := shared.Parallelize("ps")
+	psOpts := makePsOpts(opts)
+	filters := []string{}
+	if opts.Filters != nil {
+		filters = *opts.Filters
+	}
+	psContainerOutputs, err := shared.GetPsContainerOutput(i.Runtime, psOpts, filters, maxWorkers)
+	if err != nil {
+		return call.ReplyErrorOccurred(err.Error())
+	}
+
+	for _, ctr := range psContainerOutputs {
+		container := iopodman.PsContainer{
+			Id:         ctr.ID,
+			Image:      ctr.Image,
+			Command:    ctr.Command,
+			Created:    ctr.Created,
+			Ports:      ctr.Ports,
+			Names:      ctr.Names,
+			IsInfra:    ctr.IsInfra,
+			Status:     ctr.Status,
+			State:      ctr.State.String(),
+			PidNum:     int64(ctr.Pid),
+			RootFsSize: ctr.Size.RootFsSize,
+			RwSize:     ctr.Size.RwSize,
+			Pod:        ctr.Pod,
+			CreatedAt:  ctr.CreatedAt.Format(time.RFC3339Nano),
+			ExitedAt:   ctr.ExitedAt.Format(time.RFC3339Nano),
+			StartedAt:  ctr.StartedAt.Format(time.RFC3339Nano),
+			Labels:     ctr.Labels,
+			NsPid:      ctr.PID,
+			Cgroup:     ctr.Cgroup,
+			Ipc:        ctr.Cgroup,
+			Mnt:        ctr.MNT,
+			Net:        ctr.NET,
+			PidNs:      ctr.PIDNS,
+			User:       ctr.User,
+			Uts:        ctr.UTS,
+			Mounts:     ctr.Mounts,
+		}
+		containers = append(containers, container)
+	}
+	return call.ReplyPs(containers)
+}
+
 // GetContainer ...
 func (i *LibpodAPI) GetContainer(call iopodman.VarlinkCall, id string) error {
 	ctr, err := i.Runtime.LookupContainer(id)
diff --git a/pkg/varlinkapi/util.go b/pkg/varlinkapi/util.go
index 3c4b9b79ae..8716c963a5 100644
--- a/pkg/varlinkapi/util.go
+++ b/pkg/varlinkapi/util.go
@@ -162,3 +162,36 @@ func stringPullPolicyToType(s string) buildah.PullPolicy {
 	}
 	return buildah.PullIfMissing
 }
+
+func derefBool(inBool *bool) bool {
+	if inBool == nil {
+		return false
+	}
+	return *inBool
+}
+
+func derefString(in *string) string {
+	if in == nil {
+		return ""
+	}
+	return *in
+}
+
+func makePsOpts(inOpts iopodman.PsOpts) shared.PsOptions {
+	last := 0
+	if inOpts.Last != nil {
+		lastT := *inOpts.Last
+		last = int(lastT)
+	}
+	return shared.PsOptions{
+		All:       inOpts.All,
+		Last:      last,
+		Latest:    derefBool(inOpts.Latest),
+		NoTrunc:   derefBool(inOpts.NoTrunc),
+		Pod:       derefBool(inOpts.Pod),
+		Size:      true,
+		Sort:      derefString(inOpts.Sort),
+		Namespace: true,
+		Sync:      derefBool(inOpts.Sync),
+	}
+}