github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/cluster/convert/container.go (about)

     1  package convert // import "github.com/Prakhar-Agarwal-byte/moby/daemon/cluster/convert"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/containerd/log"
     9  	"github.com/Prakhar-Agarwal-byte/moby/api/types/container"
    10  	mounttypes "github.com/Prakhar-Agarwal-byte/moby/api/types/mount"
    11  	types "github.com/Prakhar-Agarwal-byte/moby/api/types/swarm"
    12  	"github.com/docker/go-units"
    13  	gogotypes "github.com/gogo/protobuf/types"
    14  	swarmapi "github.com/moby/swarmkit/v2/api"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec {
    19  	if c == nil {
    20  		return nil
    21  	}
    22  	containerSpec := &types.ContainerSpec{
    23  		Image:          c.Image,
    24  		Labels:         c.Labels,
    25  		Command:        c.Command,
    26  		Args:           c.Args,
    27  		Hostname:       c.Hostname,
    28  		Env:            c.Env,
    29  		Dir:            c.Dir,
    30  		User:           c.User,
    31  		Groups:         c.Groups,
    32  		StopSignal:     c.StopSignal,
    33  		TTY:            c.TTY,
    34  		OpenStdin:      c.OpenStdin,
    35  		ReadOnly:       c.ReadOnly,
    36  		Hosts:          c.Hosts,
    37  		Secrets:        secretReferencesFromGRPC(c.Secrets),
    38  		Configs:        configReferencesFromGRPC(c.Configs),
    39  		Isolation:      IsolationFromGRPC(c.Isolation),
    40  		Init:           initFromGRPC(c.Init),
    41  		Sysctls:        c.Sysctls,
    42  		CapabilityAdd:  c.CapabilityAdd,
    43  		CapabilityDrop: c.CapabilityDrop,
    44  		Ulimits:        ulimitsFromGRPC(c.Ulimits),
    45  	}
    46  
    47  	if c.DNSConfig != nil {
    48  		containerSpec.DNSConfig = &types.DNSConfig{
    49  			Nameservers: c.DNSConfig.Nameservers,
    50  			Search:      c.DNSConfig.Search,
    51  			Options:     c.DNSConfig.Options,
    52  		}
    53  	}
    54  
    55  	// Privileges
    56  	if c.Privileges != nil {
    57  		containerSpec.Privileges = &types.Privileges{}
    58  
    59  		if c.Privileges.CredentialSpec != nil {
    60  			containerSpec.Privileges.CredentialSpec = credentialSpecFromGRPC(c.Privileges.CredentialSpec)
    61  		}
    62  
    63  		if c.Privileges.SELinuxContext != nil {
    64  			containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{
    65  				Disable: c.Privileges.SELinuxContext.Disable,
    66  				User:    c.Privileges.SELinuxContext.User,
    67  				Type:    c.Privileges.SELinuxContext.Type,
    68  				Role:    c.Privileges.SELinuxContext.Role,
    69  				Level:   c.Privileges.SELinuxContext.Level,
    70  			}
    71  		}
    72  
    73  		if c.Privileges.Seccomp != nil {
    74  			containerSpec.Privileges.Seccomp = &types.SeccompOpts{
    75  				Profile: c.Privileges.Seccomp.Profile,
    76  			}
    77  
    78  			switch c.Privileges.Seccomp.Mode {
    79  			case swarmapi.Privileges_SeccompOpts_DEFAULT:
    80  				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeDefault
    81  			case swarmapi.Privileges_SeccompOpts_UNCONFINED:
    82  				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeUnconfined
    83  			case swarmapi.Privileges_SeccompOpts_CUSTOM:
    84  				containerSpec.Privileges.Seccomp.Mode = types.SeccompModeCustom
    85  			}
    86  		}
    87  
    88  		if c.Privileges.Apparmor != nil {
    89  			containerSpec.Privileges.AppArmor = &types.AppArmorOpts{}
    90  
    91  			switch c.Privileges.Apparmor.Mode {
    92  			case swarmapi.Privileges_AppArmorOpts_DEFAULT:
    93  				containerSpec.Privileges.AppArmor.Mode = types.AppArmorModeDefault
    94  			case swarmapi.Privileges_AppArmorOpts_DISABLED:
    95  				containerSpec.Privileges.AppArmor.Mode = types.AppArmorModeDisabled
    96  			}
    97  		}
    98  
    99  		containerSpec.Privileges.NoNewPrivileges = c.Privileges.NoNewPrivileges
   100  	}
   101  
   102  	// Mounts
   103  	for _, m := range c.Mounts {
   104  		mount := mounttypes.Mount{
   105  			Target:   m.Target,
   106  			Source:   m.Source,
   107  			Type:     mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])),
   108  			ReadOnly: m.ReadOnly,
   109  		}
   110  
   111  		if m.BindOptions != nil {
   112  			mount.BindOptions = &mounttypes.BindOptions{
   113  				Propagation:            mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])),
   114  				NonRecursive:           m.BindOptions.NonRecursive,
   115  				CreateMountpoint:       m.BindOptions.CreateMountpoint,
   116  				ReadOnlyNonRecursive:   m.BindOptions.ReadOnlyNonRecursive,
   117  				ReadOnlyForceRecursive: m.BindOptions.ReadOnlyForceRecursive,
   118  			}
   119  		}
   120  
   121  		if m.VolumeOptions != nil {
   122  			mount.VolumeOptions = &mounttypes.VolumeOptions{
   123  				NoCopy: m.VolumeOptions.NoCopy,
   124  				Labels: m.VolumeOptions.Labels,
   125  			}
   126  			if m.VolumeOptions.DriverConfig != nil {
   127  				mount.VolumeOptions.DriverConfig = &mounttypes.Driver{
   128  					Name:    m.VolumeOptions.DriverConfig.Name,
   129  					Options: m.VolumeOptions.DriverConfig.Options,
   130  				}
   131  			}
   132  		}
   133  
   134  		if m.TmpfsOptions != nil {
   135  			mount.TmpfsOptions = &mounttypes.TmpfsOptions{
   136  				SizeBytes: m.TmpfsOptions.SizeBytes,
   137  				Mode:      m.TmpfsOptions.Mode,
   138  			}
   139  		}
   140  		containerSpec.Mounts = append(containerSpec.Mounts, mount)
   141  	}
   142  
   143  	if c.StopGracePeriod != nil {
   144  		grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod)
   145  		containerSpec.StopGracePeriod = &grace
   146  	}
   147  
   148  	if c.Healthcheck != nil {
   149  		containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck)
   150  	}
   151  
   152  	return containerSpec
   153  }
   154  
   155  func initFromGRPC(v *gogotypes.BoolValue) *bool {
   156  	if v == nil {
   157  		return nil
   158  	}
   159  	value := v.GetValue()
   160  	return &value
   161  }
   162  
   163  func initToGRPC(v *bool) *gogotypes.BoolValue {
   164  	if v == nil {
   165  		return nil
   166  	}
   167  	return &gogotypes.BoolValue{Value: *v}
   168  }
   169  
   170  func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference {
   171  	refs := make([]*swarmapi.SecretReference, 0, len(sr))
   172  	for _, s := range sr {
   173  		ref := &swarmapi.SecretReference{
   174  			SecretID:   s.SecretID,
   175  			SecretName: s.SecretName,
   176  		}
   177  		if s.File != nil {
   178  			ref.Target = &swarmapi.SecretReference_File{
   179  				File: &swarmapi.FileTarget{
   180  					Name: s.File.Name,
   181  					UID:  s.File.UID,
   182  					GID:  s.File.GID,
   183  					Mode: s.File.Mode,
   184  				},
   185  			}
   186  		}
   187  
   188  		refs = append(refs, ref)
   189  	}
   190  
   191  	return refs
   192  }
   193  
   194  func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference {
   195  	refs := make([]*types.SecretReference, 0, len(sr))
   196  	for _, s := range sr {
   197  		target := s.GetFile()
   198  		if target == nil {
   199  			// not a file target
   200  			log.G(context.TODO()).Warnf("secret target not a file: secret=%s", s.SecretID)
   201  			continue
   202  		}
   203  		refs = append(refs, &types.SecretReference{
   204  			File: &types.SecretReferenceFileTarget{
   205  				Name: target.Name,
   206  				UID:  target.UID,
   207  				GID:  target.GID,
   208  				Mode: target.Mode,
   209  			},
   210  			SecretID:   s.SecretID,
   211  			SecretName: s.SecretName,
   212  		})
   213  	}
   214  
   215  	return refs
   216  }
   217  
   218  func configReferencesToGRPC(sr []*types.ConfigReference) ([]*swarmapi.ConfigReference, error) {
   219  	refs := make([]*swarmapi.ConfigReference, 0, len(sr))
   220  	for _, s := range sr {
   221  		ref := &swarmapi.ConfigReference{
   222  			ConfigID:   s.ConfigID,
   223  			ConfigName: s.ConfigName,
   224  		}
   225  		switch {
   226  		case s.Runtime == nil && s.File == nil:
   227  			return nil, errors.New("either File or Runtime should be set")
   228  		case s.Runtime != nil && s.File != nil:
   229  			return nil, errors.New("cannot specify both File and Runtime")
   230  		case s.Runtime != nil:
   231  			// Runtime target was added in API v1.40 and takes precedence over
   232  			// File target. However, File and Runtime targets are mutually exclusive,
   233  			// so we should never have both.
   234  			ref.Target = &swarmapi.ConfigReference_Runtime{
   235  				Runtime: &swarmapi.RuntimeTarget{},
   236  			}
   237  		case s.File != nil:
   238  			ref.Target = &swarmapi.ConfigReference_File{
   239  				File: &swarmapi.FileTarget{
   240  					Name: s.File.Name,
   241  					UID:  s.File.UID,
   242  					GID:  s.File.GID,
   243  					Mode: s.File.Mode,
   244  				},
   245  			}
   246  		}
   247  
   248  		refs = append(refs, ref)
   249  	}
   250  
   251  	return refs, nil
   252  }
   253  
   254  func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference {
   255  	refs := make([]*types.ConfigReference, 0, len(sr))
   256  	for _, s := range sr {
   257  		r := &types.ConfigReference{
   258  			ConfigID:   s.ConfigID,
   259  			ConfigName: s.ConfigName,
   260  		}
   261  		if target := s.GetRuntime(); target != nil {
   262  			r.Runtime = &types.ConfigReferenceRuntimeTarget{}
   263  		} else if target := s.GetFile(); target != nil {
   264  			r.File = &types.ConfigReferenceFileTarget{
   265  				Name: target.Name,
   266  				UID:  target.UID,
   267  				GID:  target.GID,
   268  				Mode: target.Mode,
   269  			}
   270  		} else {
   271  			// not a file target
   272  			log.G(context.TODO()).Warnf("config target not known: config=%s", s.ConfigID)
   273  			continue
   274  		}
   275  		refs = append(refs, r)
   276  	}
   277  
   278  	return refs
   279  }
   280  
   281  func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
   282  	containerSpec := &swarmapi.ContainerSpec{
   283  		Image:          c.Image,
   284  		Labels:         c.Labels,
   285  		Command:        c.Command,
   286  		Args:           c.Args,
   287  		Hostname:       c.Hostname,
   288  		Env:            c.Env,
   289  		Dir:            c.Dir,
   290  		User:           c.User,
   291  		Groups:         c.Groups,
   292  		StopSignal:     c.StopSignal,
   293  		TTY:            c.TTY,
   294  		OpenStdin:      c.OpenStdin,
   295  		ReadOnly:       c.ReadOnly,
   296  		Hosts:          c.Hosts,
   297  		Secrets:        secretReferencesToGRPC(c.Secrets),
   298  		Isolation:      isolationToGRPC(c.Isolation),
   299  		Init:           initToGRPC(c.Init),
   300  		Sysctls:        c.Sysctls,
   301  		CapabilityAdd:  c.CapabilityAdd,
   302  		CapabilityDrop: c.CapabilityDrop,
   303  		Ulimits:        ulimitsToGRPC(c.Ulimits),
   304  	}
   305  
   306  	if c.DNSConfig != nil {
   307  		containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{
   308  			Nameservers: c.DNSConfig.Nameservers,
   309  			Search:      c.DNSConfig.Search,
   310  			Options:     c.DNSConfig.Options,
   311  		}
   312  	}
   313  
   314  	if c.StopGracePeriod != nil {
   315  		containerSpec.StopGracePeriod = gogotypes.DurationProto(*c.StopGracePeriod)
   316  	}
   317  
   318  	// Privileges
   319  	if c.Privileges != nil {
   320  		containerSpec.Privileges = &swarmapi.Privileges{}
   321  
   322  		if c.Privileges.CredentialSpec != nil {
   323  			cs, err := credentialSpecToGRPC(c.Privileges.CredentialSpec)
   324  			if err != nil {
   325  				return nil, errors.Wrap(err, "invalid CredentialSpec")
   326  			}
   327  			containerSpec.Privileges.CredentialSpec = cs
   328  		}
   329  
   330  		if c.Privileges.SELinuxContext != nil {
   331  			containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{
   332  				Disable: c.Privileges.SELinuxContext.Disable,
   333  				User:    c.Privileges.SELinuxContext.User,
   334  				Type:    c.Privileges.SELinuxContext.Type,
   335  				Role:    c.Privileges.SELinuxContext.Role,
   336  				Level:   c.Privileges.SELinuxContext.Level,
   337  			}
   338  		}
   339  
   340  		if c.Privileges.Seccomp != nil {
   341  			containerSpec.Privileges.Seccomp = &swarmapi.Privileges_SeccompOpts{
   342  				Profile: c.Privileges.Seccomp.Profile,
   343  			}
   344  
   345  			switch c.Privileges.Seccomp.Mode {
   346  			case types.SeccompModeDefault:
   347  				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_DEFAULT
   348  			case types.SeccompModeUnconfined:
   349  				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_UNCONFINED
   350  			case types.SeccompModeCustom:
   351  				containerSpec.Privileges.Seccomp.Mode = swarmapi.Privileges_SeccompOpts_CUSTOM
   352  			}
   353  		}
   354  
   355  		if c.Privileges.AppArmor != nil {
   356  			containerSpec.Privileges.Apparmor = &swarmapi.Privileges_AppArmorOpts{}
   357  
   358  			switch c.Privileges.AppArmor.Mode {
   359  			case types.AppArmorModeDefault:
   360  				containerSpec.Privileges.Apparmor.Mode = swarmapi.Privileges_AppArmorOpts_DEFAULT
   361  			case types.AppArmorModeDisabled:
   362  				containerSpec.Privileges.Apparmor.Mode = swarmapi.Privileges_AppArmorOpts_DISABLED
   363  			}
   364  		}
   365  
   366  		containerSpec.Privileges.NoNewPrivileges = c.Privileges.NoNewPrivileges
   367  	}
   368  
   369  	if c.Configs != nil {
   370  		configs, err := configReferencesToGRPC(c.Configs)
   371  		if err != nil {
   372  			return nil, errors.Wrap(err, "invalid Config")
   373  		}
   374  		containerSpec.Configs = configs
   375  	}
   376  
   377  	// Mounts
   378  	for _, m := range c.Mounts {
   379  		mount := swarmapi.Mount{
   380  			Target:   m.Target,
   381  			Source:   m.Source,
   382  			ReadOnly: m.ReadOnly,
   383  		}
   384  
   385  		if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok {
   386  			mount.Type = swarmapi.Mount_MountType(mountType)
   387  		} else if string(m.Type) != "" {
   388  			return nil, fmt.Errorf("invalid MountType: %q", m.Type)
   389  		}
   390  
   391  		if m.BindOptions != nil {
   392  			if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok {
   393  				mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)}
   394  			} else if string(m.BindOptions.Propagation) != "" {
   395  				return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation)
   396  			}
   397  
   398  			if m.BindOptions.NonRecursive {
   399  				if mount.BindOptions == nil {
   400  					// the propagation defaults to rprivate
   401  					mount.BindOptions = &swarmapi.Mount_BindOptions{}
   402  				}
   403  				mount.BindOptions.NonRecursive = m.BindOptions.NonRecursive
   404  			}
   405  		}
   406  
   407  		if m.VolumeOptions != nil {
   408  			mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{
   409  				NoCopy: m.VolumeOptions.NoCopy,
   410  				Labels: m.VolumeOptions.Labels,
   411  			}
   412  			if m.VolumeOptions.DriverConfig != nil {
   413  				mount.VolumeOptions.DriverConfig = &swarmapi.Driver{
   414  					Name:    m.VolumeOptions.DriverConfig.Name,
   415  					Options: m.VolumeOptions.DriverConfig.Options,
   416  				}
   417  			}
   418  		}
   419  
   420  		if m.TmpfsOptions != nil {
   421  			mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{
   422  				SizeBytes: m.TmpfsOptions.SizeBytes,
   423  				Mode:      m.TmpfsOptions.Mode,
   424  			}
   425  		}
   426  
   427  		containerSpec.Mounts = append(containerSpec.Mounts, mount)
   428  	}
   429  
   430  	if c.Healthcheck != nil {
   431  		containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck)
   432  	}
   433  
   434  	return containerSpec, nil
   435  }
   436  
   437  func credentialSpecFromGRPC(c *swarmapi.Privileges_CredentialSpec) *types.CredentialSpec {
   438  	cs := &types.CredentialSpec{}
   439  	switch c.Source.(type) {
   440  	case *swarmapi.Privileges_CredentialSpec_Config:
   441  		cs.Config = c.GetConfig()
   442  	case *swarmapi.Privileges_CredentialSpec_File:
   443  		cs.File = c.GetFile()
   444  	case *swarmapi.Privileges_CredentialSpec_Registry:
   445  		cs.Registry = c.GetRegistry()
   446  	}
   447  	return cs
   448  }
   449  
   450  func credentialSpecToGRPC(c *types.CredentialSpec) (*swarmapi.Privileges_CredentialSpec, error) {
   451  	var opts []string
   452  
   453  	if c.Config != "" {
   454  		opts = append(opts, `"config"`)
   455  	}
   456  	if c.File != "" {
   457  		opts = append(opts, `"file"`)
   458  	}
   459  	if c.Registry != "" {
   460  		opts = append(opts, `"registry"`)
   461  	}
   462  	l := len(opts)
   463  	switch {
   464  	case l == 0:
   465  		return nil, errors.New(`must either provide "file", "registry", or "config" for credential spec`)
   466  	case l == 2:
   467  		return nil, fmt.Errorf("cannot specify both %s and %s credential specs", opts[0], opts[1])
   468  	case l > 2:
   469  		return nil, fmt.Errorf("cannot specify both %s, and %s credential specs", strings.Join(opts[:l-1], ", "), opts[l-1])
   470  	}
   471  
   472  	spec := &swarmapi.Privileges_CredentialSpec{}
   473  	switch {
   474  	case c.Config != "":
   475  		spec.Source = &swarmapi.Privileges_CredentialSpec_Config{
   476  			Config: c.Config,
   477  		}
   478  	case c.File != "":
   479  		spec.Source = &swarmapi.Privileges_CredentialSpec_File{
   480  			File: c.File,
   481  		}
   482  	case c.Registry != "":
   483  		spec.Source = &swarmapi.Privileges_CredentialSpec_Registry{
   484  			Registry: c.Registry,
   485  		}
   486  	}
   487  
   488  	return spec, nil
   489  }
   490  
   491  func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig {
   492  	interval, _ := gogotypes.DurationFromProto(h.Interval)
   493  	timeout, _ := gogotypes.DurationFromProto(h.Timeout)
   494  	startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod)
   495  	startInterval, _ := gogotypes.DurationFromProto(h.StartInterval)
   496  	return &container.HealthConfig{
   497  		Test:          h.Test,
   498  		Interval:      interval,
   499  		Timeout:       timeout,
   500  		Retries:       int(h.Retries),
   501  		StartPeriod:   startPeriod,
   502  		StartInterval: startInterval,
   503  	}
   504  }
   505  
   506  func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig {
   507  	return &swarmapi.HealthConfig{
   508  		Test:          h.Test,
   509  		Interval:      gogotypes.DurationProto(h.Interval),
   510  		Timeout:       gogotypes.DurationProto(h.Timeout),
   511  		Retries:       int32(h.Retries),
   512  		StartPeriod:   gogotypes.DurationProto(h.StartPeriod),
   513  		StartInterval: gogotypes.DurationProto(h.StartInterval),
   514  	}
   515  }
   516  
   517  // IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation
   518  func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation {
   519  	switch i {
   520  	case swarmapi.ContainerIsolationHyperV:
   521  		return container.IsolationHyperV
   522  	case swarmapi.ContainerIsolationProcess:
   523  		return container.IsolationProcess
   524  	case swarmapi.ContainerIsolationDefault:
   525  		return container.IsolationDefault
   526  	}
   527  	return container.IsolationEmpty
   528  }
   529  
   530  func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation {
   531  	if i.IsHyperV() {
   532  		return swarmapi.ContainerIsolationHyperV
   533  	}
   534  	if i.IsProcess() {
   535  		return swarmapi.ContainerIsolationProcess
   536  	}
   537  	return swarmapi.ContainerIsolationDefault
   538  }
   539  
   540  func ulimitsFromGRPC(u []*swarmapi.ContainerSpec_Ulimit) []*units.Ulimit {
   541  	ulimits := make([]*units.Ulimit, len(u))
   542  
   543  	for i, ulimit := range u {
   544  		ulimits[i] = &units.Ulimit{
   545  			Name: ulimit.Name,
   546  			Soft: ulimit.Soft,
   547  			Hard: ulimit.Hard,
   548  		}
   549  	}
   550  
   551  	return ulimits
   552  }
   553  
   554  func ulimitsToGRPC(u []*units.Ulimit) []*swarmapi.ContainerSpec_Ulimit {
   555  	ulimits := make([]*swarmapi.ContainerSpec_Ulimit, len(u))
   556  
   557  	for i, ulimit := range u {
   558  		ulimits[i] = &swarmapi.ContainerSpec_Ulimit{
   559  			Name: ulimit.Name,
   560  			Soft: ulimit.Soft,
   561  			Hard: ulimit.Hard,
   562  		}
   563  	}
   564  
   565  	return ulimits
   566  }