Repository: opencontainers/runc
File: libcontainer/init_linux.go (Go)

Code before:
	UID              int                   `json:"uid"`
	GID              int                   `json:"gid"`
	AdditionalGroups []int                 `json:"additional_groups"`
	Config           *configs.Config       `json:"config"`
	Networks         []*network            `json:"network"`
	PassedFilesCount int                   `json:"passed_files_count"`
	ContainerID      string                `json:"containerid"`
	Rlimits          []configs.Rlimit      `json:"rlimits"`
	CreateConsole    bool                  `json:"create_console"`
	ConsoleWidth     uint16                `json:"console_width"`
	ConsoleHeight    uint16                `json:"console_height"`
	RootlessEUID     bool                  `json:"rootless_euid,omitempty"`
	RootlessCgroups  bool                  `json:"rootless_cgroups,omitempty"`
	SpecState        *specs.State          `json:"spec_state,omitempty"`
	Cgroup2Path      string                `json:"cgroup2_path,omitempty"`
}

// Init is part of "runc init" implementation.
func Init() {
	runtime.GOMAXPROCS(1)
	runtime.LockOSThread()

	if err := startInitialization(); err != nil {
		// If the error is returned, it was not communicated
		// back to the parent (which is not a common case),
		// so print it to stderr here as a last resort.
		//
		// Do not use logrus as we are not sure if it has been
		// set up yet, but most important, if the parent is
		// alive (and its log forwarding is working).
		fmt.Fprintln(os.Stderr, err)
	}
	// Normally, StartInitialization() never returns, meaning
	// if we are here, it had failed.
	os.Exit(255)
}

// Normally, this function does not return. If it returns, with or without an
// error, it means the initialization has failed. If the error is returned,
// it means the error can not be communicated back to the parent.
func startInitialization() (retErr error) {
	// Get the synchronisation pipe.
	envSyncPipe := os.Getenv("_LIBCONTAINER_SYNCPIPE")
	syncPipeFd, err := strconv.Atoi(envSyncPipe)
	if err != nil {
		return fmt.Errorf("unable to convert _LIBCONTAINER_SYNCPIPE: %w", err)
	}
	syncPipe := newSyncSocket(os.NewFile(uintptr(syncPipeFd), "sync"))
	defer syncPipe.Close()

	defer func() {

Review comment (bug):
I think it is easy to cause these similar bugs when we are adding some fields to process config. Maybe we can change the struct initConfig to:
```
type initConfig struct {
	// Config is the original container config.
	Config *configs.Config `json:"config"`

	// Config is the original container config.
	Process *Process `json:"process"`

        // Some other fields which are neither in container config nor in process config
        ......
}
```

But maybe we can do this refactor in another PR.

Code after:
type initConfig struct {
	// Config is the original container config.
	Config *configs.Config `json:"config"`

	// Properties that are unique to and come from [Process].

	Args             []string `json:"args"`
	Env              []string `json:"env"`
	UID              int      `json:"uid"`
	GID              int      `json:"gid"`
	AdditionalGroups []int    `json:"additional_groups"`
	Cwd              string   `json:"cwd"`
	CreateConsole    bool     `json:"create_console"`
	ConsoleWidth     uint16   `json:"console_width"`
	ConsoleHeight    uint16   `json:"console_height"`
	PassedFilesCount int      `json:"passed_files_count"`

	// Properties that exists both in the container config and the process,
	// as merged by [Container.newInitConfig] (process properties has preference).

	AppArmorProfile string                `json:"apparmor_profile"`
	Capabilities    *configs.Capabilities `json:"capabilities"`
	NoNewPrivileges bool                  `json:"no_new_privileges"`
	ProcessLabel    string                `json:"process_label"`
	Rlimits         []configs.Rlimit      `json:"rlimits"`
	IOPriority      *configs.IOPriority   `json:"io_priority,omitempty"`
	Scheduler       *configs.Scheduler    `json:"scheduler,omitempty"`

	// Miscellaneous properties, filled in by [Container.newInitConfig]
	// unless documented otherwise.

	ContainerID string `json:"containerid"`
	Cgroup2Path string `json:"cgroup2_path,omitempty"`

	// Networks is filled in from container config by [initProcess.createNetworkInterfaces].
	Networks []*network `json:"network"`

	// SpecState is filled in by [initProcess.Start].
	SpecState *specs.State `json:"spec_state,omitempty"`
}

// Init is part of "runc init" implementation.
func Init() {
	runtime.GOMAXPROCS(1)
	runtime.LockOSThread()

	if err := startInitialization(); err != nil {
		// If the error is returned, it was not communicated
		// back to the parent (which is not a common case),
		// so print it to stderr here as a last resort.
		//