github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/libcontainer/specconv/spec_linux.go (about) 1 // +build linux 2 3 // Package specconv implements conversion of specifications to libcontainer 4 // configurations 5 package specconv 6 7 import ( 8 "fmt" 9 "os" 10 "path/filepath" 11 "strings" 12 "syscall" 13 "time" 14 15 "github.com/opencontainers/runc/libcontainer/configs" 16 "github.com/opencontainers/runc/libcontainer/seccomp" 17 libcontainerUtils "github.com/opencontainers/runc/libcontainer/utils" 18 "github.com/opencontainers/runtime-spec/specs-go" 19 ) 20 21 const wildcard = -1 22 23 var namespaceMapping = map[specs.NamespaceType]configs.NamespaceType{ 24 specs.PIDNamespace: configs.NEWPID, 25 specs.NetworkNamespace: configs.NEWNET, 26 specs.MountNamespace: configs.NEWNS, 27 specs.UserNamespace: configs.NEWUSER, 28 specs.IPCNamespace: configs.NEWIPC, 29 specs.UTSNamespace: configs.NEWUTS, 30 } 31 32 var mountPropagationMapping = map[string]int{ 33 "rprivate": syscall.MS_PRIVATE | syscall.MS_REC, 34 "private": syscall.MS_PRIVATE, 35 "rslave": syscall.MS_SLAVE | syscall.MS_REC, 36 "slave": syscall.MS_SLAVE, 37 "rshared": syscall.MS_SHARED | syscall.MS_REC, 38 "shared": syscall.MS_SHARED, 39 "": syscall.MS_PRIVATE | syscall.MS_REC, 40 } 41 42 var allowedDevices = []*configs.Device{ 43 // allow mknod for any device 44 { 45 Type: 'c', 46 Major: wildcard, 47 Minor: wildcard, 48 Permissions: "m", 49 Allow: true, 50 }, 51 { 52 Type: 'b', 53 Major: wildcard, 54 Minor: wildcard, 55 Permissions: "m", 56 Allow: true, 57 }, 58 { 59 Type: 'c', 60 Path: "/dev/null", 61 Major: 1, 62 Minor: 3, 63 Permissions: "rwm", 64 Allow: true, 65 }, 66 { 67 Type: 'c', 68 Path: "/dev/random", 69 Major: 1, 70 Minor: 8, 71 Permissions: "rwm", 72 Allow: true, 73 }, 74 { 75 Type: 'c', 76 Path: "/dev/full", 77 Major: 1, 78 Minor: 7, 79 Permissions: "rwm", 80 Allow: true, 81 }, 82 { 83 Type: 'c', 84 Path: "/dev/tty", 85 Major: 5, 86 Minor: 0, 87 Permissions: "rwm", 88 Allow: true, 89 }, 90 { 91 Type: 'c', 92 Path: "/dev/zero", 93 Major: 1, 94 Minor: 5, 95 Permissions: "rwm", 96 Allow: true, 97 }, 98 { 99 Type: 'c', 100 Path: "/dev/urandom", 101 Major: 1, 102 Minor: 9, 103 Permissions: "rwm", 104 Allow: true, 105 }, 106 { 107 Path: "/dev/console", 108 Type: 'c', 109 Major: 5, 110 Minor: 1, 111 Permissions: "rwm", 112 Allow: true, 113 }, 114 // /dev/pts/ - pts namespaces are "coming soon" 115 { 116 Path: "", 117 Type: 'c', 118 Major: 136, 119 Minor: wildcard, 120 Permissions: "rwm", 121 Allow: true, 122 }, 123 { 124 Path: "", 125 Type: 'c', 126 Major: 5, 127 Minor: 2, 128 Permissions: "rwm", 129 Allow: true, 130 }, 131 // tuntap 132 { 133 Path: "", 134 Type: 'c', 135 Major: 10, 136 Minor: 200, 137 Permissions: "rwm", 138 Allow: true, 139 }, 140 } 141 142 type CreateOpts struct { 143 CgroupName string 144 UseSystemdCgroup bool 145 NoPivotRoot bool 146 NoNewKeyring bool 147 Spec *specs.Spec 148 } 149 150 // CreateLibcontainerConfig creates a new libcontainer configuration from a 151 // given specification and a cgroup name 152 func CreateLibcontainerConfig(opts *CreateOpts) (*configs.Config, error) { 153 // runc's cwd will always be the bundle path 154 rcwd, err := os.Getwd() 155 if err != nil { 156 return nil, err 157 } 158 cwd, err := filepath.Abs(rcwd) 159 if err != nil { 160 return nil, err 161 } 162 spec := opts.Spec 163 rootfsPath := spec.Root.Path 164 if !filepath.IsAbs(rootfsPath) { 165 rootfsPath = filepath.Join(cwd, rootfsPath) 166 } 167 labels := []string{} 168 for k, v := range spec.Annotations { 169 labels = append(labels, fmt.Sprintf("%s=%s", k, v)) 170 } 171 config := &configs.Config{ 172 Rootfs: rootfsPath, 173 NoPivotRoot: opts.NoPivotRoot, 174 Readonlyfs: spec.Root.Readonly, 175 Hostname: spec.Hostname, 176 Labels: append(labels, fmt.Sprintf("bundle=%s", cwd)), 177 NoNewKeyring: opts.NoNewKeyring, 178 } 179 180 exists := false 181 if config.RootPropagation, exists = mountPropagationMapping[spec.Linux.RootfsPropagation]; !exists { 182 return nil, fmt.Errorf("rootfsPropagation=%v is not supported", spec.Linux.RootfsPropagation) 183 } 184 185 for _, ns := range spec.Linux.Namespaces { 186 t, exists := namespaceMapping[ns.Type] 187 if !exists { 188 return nil, fmt.Errorf("namespace %q does not exist", ns) 189 } 190 if config.Namespaces.Contains(t) { 191 return nil, fmt.Errorf("malformed spec file: duplicated ns %q", ns) 192 } 193 config.Namespaces.Add(t, ns.Path) 194 } 195 if config.Namespaces.Contains(configs.NEWNET) { 196 config.Networks = []*configs.Network{ 197 { 198 Type: "loopback", 199 }, 200 } 201 } 202 for _, m := range spec.Mounts { 203 config.Mounts = append(config.Mounts, createLibcontainerMount(cwd, m)) 204 } 205 if err := createDevices(spec, config); err != nil { 206 return nil, err 207 } 208 if err := setupUserNamespace(spec, config); err != nil { 209 return nil, err 210 } 211 c, err := createCgroupConfig(opts.CgroupName, opts.UseSystemdCgroup, spec) 212 if err != nil { 213 return nil, err 214 } 215 config.Cgroups = c 216 // set extra path masking for libcontainer for the various unsafe places in proc 217 config.MaskPaths = spec.Linux.MaskedPaths 218 config.ReadonlyPaths = spec.Linux.ReadonlyPaths 219 if spec.Linux.Seccomp != nil { 220 seccomp, err := setupSeccomp(spec.Linux.Seccomp) 221 if err != nil { 222 return nil, err 223 } 224 config.Seccomp = seccomp 225 } 226 if spec.Process.SelinuxLabel != "" { 227 config.ProcessLabel = spec.Process.SelinuxLabel 228 } 229 config.Sysctl = spec.Linux.Sysctl 230 if spec.Linux.Resources != nil && spec.Linux.Resources.OOMScoreAdj != nil { 231 config.OomScoreAdj = *spec.Linux.Resources.OOMScoreAdj 232 } 233 createHooks(spec, config) 234 config.MountLabel = spec.Linux.MountLabel 235 config.Version = specs.Version 236 return config, nil 237 } 238 239 func createLibcontainerMount(cwd string, m specs.Mount) *configs.Mount { 240 flags, pgflags, data, ext := parseMountOptions(m.Options) 241 source := m.Source 242 if m.Type == "bind" { 243 if !filepath.IsAbs(source) { 244 source = filepath.Join(cwd, m.Source) 245 } 246 } 247 return &configs.Mount{ 248 Device: m.Type, 249 Source: source, 250 Destination: m.Destination, 251 Data: data, 252 Flags: flags, 253 PropagationFlags: pgflags, 254 Extensions: ext, 255 } 256 } 257 258 func createCgroupConfig(name string, useSystemdCgroup bool, spec *specs.Spec) (*configs.Cgroup, error) { 259 var myCgroupPath string 260 261 c := &configs.Cgroup{ 262 Resources: &configs.Resources{}, 263 } 264 265 if spec.Linux != nil && spec.Linux.CgroupsPath != nil { 266 myCgroupPath = libcontainerUtils.CleanPath(*spec.Linux.CgroupsPath) 267 if useSystemdCgroup { 268 myCgroupPath = *spec.Linux.CgroupsPath 269 } 270 } 271 272 if useSystemdCgroup { 273 if myCgroupPath == "" { 274 c.Parent = "system.slice" 275 c.ScopePrefix = "runc" 276 c.Name = name 277 } else { 278 // Parse the path from expected "slice:prefix:name" 279 // for e.g. "system.slice:docker:1234" 280 parts := strings.Split(myCgroupPath, ":") 281 if len(parts) != 3 { 282 return nil, fmt.Errorf("expected cgroupsPath to be of format \"slice:prefix:name\" for systemd cgroups") 283 } 284 c.Parent = parts[0] 285 c.ScopePrefix = parts[1] 286 c.Name = parts[2] 287 } 288 } else { 289 if myCgroupPath == "" { 290 c.Name = name 291 } 292 c.Path = myCgroupPath 293 } 294 295 c.Resources.AllowedDevices = allowedDevices 296 if spec.Linux == nil { 297 return c, nil 298 } 299 r := spec.Linux.Resources 300 if r == nil { 301 return c, nil 302 } 303 for i, d := range spec.Linux.Resources.Devices { 304 var ( 305 t = "a" 306 major = int64(-1) 307 minor = int64(-1) 308 ) 309 if d.Type != nil { 310 t = *d.Type 311 } 312 if d.Major != nil { 313 major = *d.Major 314 } 315 if d.Minor != nil { 316 minor = *d.Minor 317 } 318 if d.Access == nil || *d.Access == "" { 319 return nil, fmt.Errorf("device access at %d field cannot be empty", i) 320 } 321 dt, err := stringToDeviceRune(t) 322 if err != nil { 323 return nil, err 324 } 325 dd := &configs.Device{ 326 Type: dt, 327 Major: major, 328 Minor: minor, 329 Permissions: *d.Access, 330 Allow: d.Allow, 331 } 332 c.Resources.Devices = append(c.Resources.Devices, dd) 333 } 334 // append the default allowed devices to the end of the list 335 c.Resources.Devices = append(c.Resources.Devices, allowedDevices...) 336 if r.Memory != nil { 337 if r.Memory.Limit != nil { 338 c.Resources.Memory = int64(*r.Memory.Limit) 339 } 340 if r.Memory.Reservation != nil { 341 c.Resources.MemoryReservation = int64(*r.Memory.Reservation) 342 } 343 if r.Memory.Swap != nil { 344 c.Resources.MemorySwap = int64(*r.Memory.Swap) 345 } 346 if r.Memory.Kernel != nil { 347 c.Resources.KernelMemory = int64(*r.Memory.Kernel) 348 } 349 if r.Memory.KernelTCP != nil { 350 c.Resources.KernelMemoryTCP = int64(*r.Memory.KernelTCP) 351 } 352 if r.Memory.Swappiness != nil { 353 swappiness := int64(*r.Memory.Swappiness) 354 c.Resources.MemorySwappiness = &swappiness 355 } 356 } 357 if r.CPU != nil { 358 if r.CPU.Shares != nil { 359 c.Resources.CpuShares = int64(*r.CPU.Shares) 360 } 361 if r.CPU.Quota != nil { 362 c.Resources.CpuQuota = int64(*r.CPU.Quota) 363 } 364 if r.CPU.Period != nil { 365 c.Resources.CpuPeriod = int64(*r.CPU.Period) 366 } 367 if r.CPU.RealtimeRuntime != nil { 368 c.Resources.CpuRtRuntime = int64(*r.CPU.RealtimeRuntime) 369 } 370 if r.CPU.RealtimePeriod != nil { 371 c.Resources.CpuRtPeriod = int64(*r.CPU.RealtimePeriod) 372 } 373 if r.CPU.Cpus != nil { 374 c.Resources.CpusetCpus = *r.CPU.Cpus 375 } 376 if r.CPU.Mems != nil { 377 c.Resources.CpusetMems = *r.CPU.Mems 378 } 379 } 380 if r.Pids != nil && r.Pids.Limit != nil { 381 c.Resources.PidsLimit = *r.Pids.Limit 382 } 383 if r.BlockIO != nil { 384 if r.BlockIO.Weight != nil { 385 c.Resources.BlkioWeight = *r.BlockIO.Weight 386 } 387 if r.BlockIO.LeafWeight != nil { 388 c.Resources.BlkioLeafWeight = *r.BlockIO.LeafWeight 389 } 390 if r.BlockIO.WeightDevice != nil { 391 for _, wd := range r.BlockIO.WeightDevice { 392 var weight, leafWeight uint16 393 if wd.Weight != nil { 394 weight = *wd.Weight 395 } 396 if wd.LeafWeight != nil { 397 leafWeight = *wd.LeafWeight 398 } 399 weightDevice := configs.NewWeightDevice(wd.Major, wd.Minor, weight, leafWeight) 400 c.Resources.BlkioWeightDevice = append(c.Resources.BlkioWeightDevice, weightDevice) 401 } 402 } 403 if r.BlockIO.ThrottleReadBpsDevice != nil { 404 for _, td := range r.BlockIO.ThrottleReadBpsDevice { 405 var rate uint64 406 if td.Rate != nil { 407 rate = *td.Rate 408 } 409 throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) 410 c.Resources.BlkioThrottleReadBpsDevice = append(c.Resources.BlkioThrottleReadBpsDevice, throttleDevice) 411 } 412 } 413 if r.BlockIO.ThrottleWriteBpsDevice != nil { 414 for _, td := range r.BlockIO.ThrottleWriteBpsDevice { 415 var rate uint64 416 if td.Rate != nil { 417 rate = *td.Rate 418 } 419 throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) 420 c.Resources.BlkioThrottleWriteBpsDevice = append(c.Resources.BlkioThrottleWriteBpsDevice, throttleDevice) 421 } 422 } 423 if r.BlockIO.ThrottleReadIOPSDevice != nil { 424 for _, td := range r.BlockIO.ThrottleReadIOPSDevice { 425 var rate uint64 426 if td.Rate != nil { 427 rate = *td.Rate 428 } 429 throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) 430 c.Resources.BlkioThrottleReadIOPSDevice = append(c.Resources.BlkioThrottleReadIOPSDevice, throttleDevice) 431 } 432 } 433 if r.BlockIO.ThrottleWriteIOPSDevice != nil { 434 for _, td := range r.BlockIO.ThrottleWriteIOPSDevice { 435 var rate uint64 436 if td.Rate != nil { 437 rate = *td.Rate 438 } 439 throttleDevice := configs.NewThrottleDevice(td.Major, td.Minor, rate) 440 c.Resources.BlkioThrottleWriteIOPSDevice = append(c.Resources.BlkioThrottleWriteIOPSDevice, throttleDevice) 441 } 442 } 443 } 444 for _, l := range r.HugepageLimits { 445 if l.Pagesize == nil || l.Limit == nil { 446 return nil, fmt.Errorf("pagesize and limit can not be empty") 447 } 448 c.Resources.HugetlbLimit = append(c.Resources.HugetlbLimit, &configs.HugepageLimit{ 449 Pagesize: *l.Pagesize, 450 Limit: *l.Limit, 451 }) 452 } 453 if r.DisableOOMKiller != nil { 454 c.Resources.OomKillDisable = *r.DisableOOMKiller 455 } 456 if r.Network != nil { 457 if r.Network.ClassID != nil { 458 c.Resources.NetClsClassid = *r.Network.ClassID 459 } 460 for _, m := range r.Network.Priorities { 461 c.Resources.NetPrioIfpriomap = append(c.Resources.NetPrioIfpriomap, &configs.IfPrioMap{ 462 Interface: m.Name, 463 Priority: int64(m.Priority), 464 }) 465 } 466 } 467 return c, nil 468 } 469 470 func stringToDeviceRune(s string) (rune, error) { 471 switch s { 472 case "a": 473 return 'a', nil 474 case "b": 475 return 'b', nil 476 case "c": 477 return 'c', nil 478 default: 479 return 0, fmt.Errorf("invalid device type %q", s) 480 } 481 } 482 483 func createDevices(spec *specs.Spec, config *configs.Config) error { 484 // add whitelisted devices 485 config.Devices = []*configs.Device{ 486 { 487 Type: 'c', 488 Path: "/dev/null", 489 Major: 1, 490 Minor: 3, 491 FileMode: 0666, 492 Uid: 0, 493 Gid: 0, 494 }, 495 { 496 Type: 'c', 497 Path: "/dev/random", 498 Major: 1, 499 Minor: 8, 500 FileMode: 0666, 501 Uid: 0, 502 Gid: 0, 503 }, 504 { 505 Type: 'c', 506 Path: "/dev/full", 507 Major: 1, 508 Minor: 7, 509 FileMode: 0666, 510 Uid: 0, 511 Gid: 0, 512 }, 513 { 514 Type: 'c', 515 Path: "/dev/tty", 516 Major: 5, 517 Minor: 0, 518 FileMode: 0666, 519 Uid: 0, 520 Gid: 0, 521 }, 522 { 523 Type: 'c', 524 Path: "/dev/zero", 525 Major: 1, 526 Minor: 5, 527 FileMode: 0666, 528 Uid: 0, 529 Gid: 0, 530 }, 531 { 532 Type: 'c', 533 Path: "/dev/urandom", 534 Major: 1, 535 Minor: 9, 536 FileMode: 0666, 537 Uid: 0, 538 Gid: 0, 539 }, 540 } 541 // merge in additional devices from the spec 542 for _, d := range spec.Linux.Devices { 543 var uid, gid uint32 544 var filemode os.FileMode = 0666 545 546 if d.UID != nil { 547 uid = *d.UID 548 } 549 if d.GID != nil { 550 gid = *d.GID 551 } 552 dt, err := stringToDeviceRune(d.Type) 553 if err != nil { 554 return err 555 } 556 if d.FileMode != nil { 557 filemode = *d.FileMode 558 } 559 device := &configs.Device{ 560 Type: dt, 561 Path: d.Path, 562 Major: d.Major, 563 Minor: d.Minor, 564 FileMode: filemode, 565 Uid: uid, 566 Gid: gid, 567 } 568 config.Devices = append(config.Devices, device) 569 } 570 return nil 571 } 572 573 func setupUserNamespace(spec *specs.Spec, config *configs.Config) error { 574 if len(spec.Linux.UIDMappings) == 0 { 575 return nil 576 } 577 create := func(m specs.IDMapping) configs.IDMap { 578 return configs.IDMap{ 579 HostID: int(m.HostID), 580 ContainerID: int(m.ContainerID), 581 Size: int(m.Size), 582 } 583 } 584 for _, m := range spec.Linux.UIDMappings { 585 config.UidMappings = append(config.UidMappings, create(m)) 586 } 587 for _, m := range spec.Linux.GIDMappings { 588 config.GidMappings = append(config.GidMappings, create(m)) 589 } 590 rootUID, err := config.HostUID() 591 if err != nil { 592 return err 593 } 594 rootGID, err := config.HostGID() 595 if err != nil { 596 return err 597 } 598 for _, node := range config.Devices { 599 node.Uid = uint32(rootUID) 600 node.Gid = uint32(rootGID) 601 } 602 return nil 603 } 604 605 // parseMountOptions parses the string and returns the flags, propagation 606 // flags and any mount data that it contains. 607 func parseMountOptions(options []string) (int, []int, string, int) { 608 var ( 609 flag int 610 pgflag []int 611 data []string 612 extFlags int 613 ) 614 flags := map[string]struct { 615 clear bool 616 flag int 617 }{ 618 "async": {true, syscall.MS_SYNCHRONOUS}, 619 "atime": {true, syscall.MS_NOATIME}, 620 "bind": {false, syscall.MS_BIND}, 621 "defaults": {false, 0}, 622 "dev": {true, syscall.MS_NODEV}, 623 "diratime": {true, syscall.MS_NODIRATIME}, 624 "dirsync": {false, syscall.MS_DIRSYNC}, 625 "exec": {true, syscall.MS_NOEXEC}, 626 "mand": {false, syscall.MS_MANDLOCK}, 627 "noatime": {false, syscall.MS_NOATIME}, 628 "nodev": {false, syscall.MS_NODEV}, 629 "nodiratime": {false, syscall.MS_NODIRATIME}, 630 "noexec": {false, syscall.MS_NOEXEC}, 631 "nomand": {true, syscall.MS_MANDLOCK}, 632 "norelatime": {true, syscall.MS_RELATIME}, 633 "nostrictatime": {true, syscall.MS_STRICTATIME}, 634 "nosuid": {false, syscall.MS_NOSUID}, 635 "rbind": {false, syscall.MS_BIND | syscall.MS_REC}, 636 "relatime": {false, syscall.MS_RELATIME}, 637 "remount": {false, syscall.MS_REMOUNT}, 638 "ro": {false, syscall.MS_RDONLY}, 639 "rw": {true, syscall.MS_RDONLY}, 640 "strictatime": {false, syscall.MS_STRICTATIME}, 641 "suid": {true, syscall.MS_NOSUID}, 642 "sync": {false, syscall.MS_SYNCHRONOUS}, 643 } 644 propagationFlags := map[string]int{ 645 "private": syscall.MS_PRIVATE, 646 "shared": syscall.MS_SHARED, 647 "slave": syscall.MS_SLAVE, 648 "unbindable": syscall.MS_UNBINDABLE, 649 "rprivate": syscall.MS_PRIVATE | syscall.MS_REC, 650 "rshared": syscall.MS_SHARED | syscall.MS_REC, 651 "rslave": syscall.MS_SLAVE | syscall.MS_REC, 652 "runbindable": syscall.MS_UNBINDABLE | syscall.MS_REC, 653 } 654 extensionFlags := map[string]struct { 655 clear bool 656 flag int 657 }{ 658 "tmpcopyup": {false, configs.EXT_COPYUP}, 659 } 660 for _, o := range options { 661 // If the option does not exist in the flags table or the flag 662 // is not supported on the platform, 663 // then it is a data value for a specific fs type 664 if f, exists := flags[o]; exists && f.flag != 0 { 665 if f.clear { 666 flag &= ^f.flag 667 } else { 668 flag |= f.flag 669 } 670 } else if f, exists := propagationFlags[o]; exists && f != 0 { 671 pgflag = append(pgflag, f) 672 } else if f, exists := extensionFlags[o]; exists && f.flag != 0 { 673 if f.clear { 674 extFlags &= ^f.flag 675 } else { 676 extFlags |= f.flag 677 } 678 } else { 679 data = append(data, o) 680 } 681 } 682 return flag, pgflag, strings.Join(data, ","), extFlags 683 } 684 685 func setupSeccomp(config *specs.Seccomp) (*configs.Seccomp, error) { 686 if config == nil { 687 return nil, nil 688 } 689 690 // No default action specified, no syscalls listed, assume seccomp disabled 691 if config.DefaultAction == "" && len(config.Syscalls) == 0 { 692 return nil, nil 693 } 694 695 newConfig := new(configs.Seccomp) 696 newConfig.Syscalls = []*configs.Syscall{} 697 698 if len(config.Architectures) > 0 { 699 newConfig.Architectures = []string{} 700 for _, arch := range config.Architectures { 701 newArch, err := seccomp.ConvertStringToArch(string(arch)) 702 if err != nil { 703 return nil, err 704 } 705 newConfig.Architectures = append(newConfig.Architectures, newArch) 706 } 707 } 708 709 // Convert default action from string representation 710 newDefaultAction, err := seccomp.ConvertStringToAction(string(config.DefaultAction)) 711 if err != nil { 712 return nil, err 713 } 714 newConfig.DefaultAction = newDefaultAction 715 716 // Loop through all syscall blocks and convert them to libcontainer format 717 for _, call := range config.Syscalls { 718 newAction, err := seccomp.ConvertStringToAction(string(call.Action)) 719 if err != nil { 720 return nil, err 721 } 722 723 newCall := configs.Syscall{ 724 Name: call.Name, 725 Action: newAction, 726 Args: []*configs.Arg{}, 727 } 728 729 // Loop through all the arguments of the syscall and convert them 730 for _, arg := range call.Args { 731 newOp, err := seccomp.ConvertStringToOperator(string(arg.Op)) 732 if err != nil { 733 return nil, err 734 } 735 736 newArg := configs.Arg{ 737 Index: arg.Index, 738 Value: arg.Value, 739 ValueTwo: arg.ValueTwo, 740 Op: newOp, 741 } 742 743 newCall.Args = append(newCall.Args, &newArg) 744 } 745 746 newConfig.Syscalls = append(newConfig.Syscalls, &newCall) 747 } 748 749 return newConfig, nil 750 } 751 752 func createHooks(rspec *specs.Spec, config *configs.Config) { 753 config.Hooks = &configs.Hooks{} 754 for _, h := range rspec.Hooks.Prestart { 755 cmd := createCommandHook(h) 756 config.Hooks.Prestart = append(config.Hooks.Prestart, configs.NewCommandHook(cmd)) 757 } 758 for _, h := range rspec.Hooks.Poststart { 759 cmd := createCommandHook(h) 760 config.Hooks.Poststart = append(config.Hooks.Poststart, configs.NewCommandHook(cmd)) 761 } 762 for _, h := range rspec.Hooks.Poststop { 763 cmd := createCommandHook(h) 764 config.Hooks.Poststop = append(config.Hooks.Poststop, configs.NewCommandHook(cmd)) 765 } 766 } 767 768 func createCommandHook(h specs.Hook) configs.Command { 769 cmd := configs.Command{ 770 Path: h.Path, 771 Args: h.Args, 772 Env: h.Env, 773 } 774 if h.Timeout != nil { 775 d := time.Duration(*h.Timeout) * time.Second 776 cmd.Timeout = &d 777 } 778 return cmd 779 }