├── LICENSE ├── README.md ├── cg.go ├── cg_test.go └── main.go /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Vincent Batts , 2014 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this 7 | list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright notice, 9 | this list of conditions and the following disclaimer in the documentation 10 | and/or other materials provided with the distribution. 11 | 3. Neither the name of The author nor the names of its contributors may be 12 | used to endorse or promote products derived from this software without 13 | specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY 16 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR AND CONTRIBUTORS BE LIABLE FOR ANY 19 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 22 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-cgroup 2 | 3 | Bindings to the libcgroup library 4 | 5 | ## Notice 6 | 7 | _these bindings are incomplete_ 8 | 9 | ## Installing 10 | 11 | ```shell 12 | go get github.com/vbatts/go-cgroup 13 | ``` 14 | 15 | on debian, you'll need packages: golang, libcgroup-dev 16 | on fedora, you'll need packages: golang, libcgroup-devel 17 | 18 | ## Sample 19 | 20 | ```golang 21 | package main 22 | 23 | import "github.com/vbatts/go-cgroup" 24 | import "fmt" 25 | 26 | func main() { 27 | cgroup.Init() 28 | 29 | fmt.Println(cgroup.GetSubSysMountPoint("cpu")) 30 | 31 | ctls, err := cgroup.GetAllControllers() 32 | if err != nil { 33 | fmt.Println(err) 34 | return 35 | } 36 | for i := range ctls { 37 | fmt.Println(ctls[i]) 38 | } 39 | 40 | } 41 | ``` 42 | 43 | ## Contributing 44 | 45 | Fork and Pull Request please! 46 | 47 | -------------------------------------------------------------------------------- /cg.go: -------------------------------------------------------------------------------- 1 | package cgroup 2 | 3 | /* 4 | #include 5 | #cgo LDFLAGS: -lcgroup 6 | 7 | // work around for the 'type' special word 8 | enum cgroup_file_type type_from_file_info(struct cgroup_file_info fi) { 9 | return fi.type; 10 | } 11 | */ 12 | import "C" 13 | import ( 14 | "errors" 15 | "runtime" 16 | "strconv" 17 | "unsafe" 18 | ) 19 | 20 | // Init initializes libcgroup. Information about mounted hierarchies are 21 | // examined and cached internally (just what's mounted where, not the groups 22 | // themselves). 23 | func Init() error { 24 | return _err(C.cgroup_init()) 25 | } 26 | 27 | // Cgroup is the structure describing one or more control groups. The structure 28 | // is opaque to applications. 29 | type Cgroup struct { 30 | g *C.struct_cgroup 31 | } 32 | 33 | // NewCgroup allocates a new cgroup structure. This function itself does not create new 34 | // control group in kernel, only new struct cgroup inside libcgroup! 35 | // The caller would still need to Create() or similar to create this group in the kernel. 36 | // 37 | // @param name Path to the group, relative from root group. Use @c "/" or @c "." 38 | // for the root group itself and @c "/foo/bar/baz" or @c "foo/bar/baz" for 39 | // subgroups. 40 | func NewCgroup(name string) Cgroup { 41 | cg := Cgroup{ 42 | C.cgroup_new_cgroup(C.CString(name)), 43 | } 44 | runtime.SetFinalizer(&cg, freeCgroupThings) 45 | return cg 46 | } 47 | 48 | // AddController attaches a new controller to cgroup. This function just 49 | // modifies internal libcgroup structure, not the kernel control group. 50 | func (cg *Cgroup) AddController(name string) *Controller { 51 | return &Controller{ 52 | C.cgroup_add_controller(cg.g, C.CString(name)), 53 | } 54 | } 55 | 56 | // GetController returns appropriate controller from given group. 57 | // The controller must be added before using AddController() or loaded 58 | // from kernel using GetCgroup(). 59 | func (cg Cgroup) GetController(name string) *Controller { 60 | return &Controller{ 61 | C.cgroup_get_controller(cg.g, C.CString(name)), 62 | } 63 | } 64 | 65 | func freeCgroupThings(cg *Cgroup) { 66 | C.cgroup_free(&cg.g) 67 | C.cgroup_free_controllers(cg.g) 68 | } 69 | 70 | /* 71 | Create a control group in kernel. The group is created in all 72 | hierarchies, which cover controllers added by Cgroup.AddController(). 73 | 74 | TODO correct docs for golang implementation 75 | 76 | All parameters set by cgroup_add_value_* functions are written. 77 | The created groups has owner which was set by cgroup_set_uid_gid() and 78 | permissions set by cgroup_set_permissions. 79 | 80 | foo = cgroup.NewCgroup("foo) 81 | foo.Create() 82 | */ 83 | func (cg Cgroup) Create() error { 84 | return _err(C.cgroup_create_cgroup(cg.g, C.int(0))) 85 | } 86 | 87 | // CreateIgnoreOwnership is the same as Create(), but all errors are ignored 88 | // when setting owner of the group and/or its tasks file. 89 | func (cg Cgroup) CreateIgnoreOwnership() error { 90 | return _err(C.cgroup_create_cgroup(cg.g, C.int(1))) 91 | } 92 | 93 | /* 94 | CreateFromParent creates new control group in kernel, with all parameters and 95 | values copied from its parent group. The group is created in all hierarchies, 96 | where the parent group exists. I.e. following code creates subgroup in all 97 | hierarchies, because all of them have root (=parent) group. 98 | 99 | foo = cgroup.NewCgroup("foo) 100 | foo.CreateFromParent() 101 | 102 | */ 103 | func (cg Cgroup) CreateFromParent() error { 104 | return _err(C.cgroup_create_cgroup_from_parent(cg.g, C.int(0))) 105 | } 106 | 107 | // CreateFromParentIgnoreOwnership is the same as CreateFromParent(), but all 108 | // errors are ignored when setting owner of the group and/or its tasks file. 109 | func (cg Cgroup) CreateFromParentIgnoreOwnership() error { 110 | return _err(C.cgroup_create_cgroup_from_parent(cg.g, C.int(1))) 111 | } 112 | 113 | // Modify a control group in kernel. All parameters added by cgroup_add_value_ 114 | // or cgroup_set_value_ are written. Currently it's not possible to change and 115 | // owner of a group. 116 | // 117 | // TODO correct docs for golang implementation 118 | func (cg Cgroup) Modify() error { 119 | return _err(C.cgroup_modify_cgroup(cg.g)) 120 | } 121 | 122 | /* 123 | Delete removes a control group from kernel. The group is removed from 124 | all hierarchies, which cover controllers added by Cgroup.AddController() 125 | or GetCgroup(). All tasks inside the group are automatically moved 126 | to parent group. 127 | 128 | The group being removed must be empty, i.e. without subgroups. Use 129 | cgroup_delete_cgroup_ext() for recursive delete. 130 | 131 | TODO correct docs for golang implementation 132 | */ 133 | func (cg Cgroup) Delete() error { 134 | return _err(C.cgroup_delete_cgroup(cg.g, C.int(0))) 135 | } 136 | 137 | // DeleteIgnoreMigration is the same as Delete(), but ignores errors when 138 | // migrating. 139 | func (cg Cgroup) DeleteIgnoreMigration() error { 140 | return _err(C.cgroup_delete_cgroup(cg.g, C.int(1))) 141 | } 142 | 143 | /* 144 | DeleteExt removes a control group from kernel. 145 | 146 | All tasks are automatically moved to parent group. 147 | If DeleteIgnoreMigration flag is used, the errors that occurred 148 | during the task movement are ignored. 149 | 150 | DeleteRecursive flag specifies that all subgroups should be removed 151 | too. If root group is being removed with this flag specified, all subgroups 152 | are removed but the root group itself is left undeleted. 153 | */ 154 | func (cg Cgroup) DeleteExt(flags DeleteFlag) error { 155 | return _err(C.cgroup_delete_cgroup_ext(cg.g, C.int(flags))) 156 | } 157 | 158 | /* 159 | Get reads all information regarding the group from kernel. 160 | Based on name of the group, list of controllers and all parameters and their 161 | values are read from all hierarchies, where a group with given name exists. 162 | All existing controllers are replaced. I.e. following code will fill root with 163 | controllers from all hierarchies, because the root group is available in all of 164 | them. 165 | 166 | root := cgroup.NewCgroup("/") 167 | err := root.Get() 168 | ... 169 | 170 | */ 171 | func (cg Cgroup) Get() error { 172 | return _err(C.cgroup_get_cgroup(cg.g)) 173 | } 174 | 175 | type ( 176 | // UID is the user ID type. 177 | // cgroup.UID(0) 178 | UID C.uid_t 179 | 180 | // GID is the group ID type. 181 | // cgroup.GID(0) 182 | GID C.gid_t 183 | ) 184 | 185 | /* 186 | SetUIDGID sets owner of the group control files and the @c tasks file. This function 187 | modifies only libcgroup internal cgroup structure, use 188 | Cgroup.Create() afterwards to create the group with given owners. 189 | 190 | @param cgroup 191 | @param tasksUID UID of the owner of group's @c tasks file. 192 | @param tasksGID GID of the owner of group's @c tasks file. 193 | @param controlUID UID of the owner of group's control files (i.e. 194 | parameters). 195 | @param controlGID GID of the owner of group's control files (i.e. 196 | parameters). 197 | */ 198 | func (cg Cgroup) SetUIDGID(tasksUID UID, tasksGID GID, 199 | controlUID UID, controlGID GID) error { 200 | return _err(C.cgroup_set_uid_gid(cg.g, 201 | C.uid_t(tasksUID), C.gid_t(tasksGID), 202 | C.uid_t(controlUID), C.gid_t(controlGID))) 203 | 204 | } 205 | 206 | // GetUIDGID returns owners of the group's @c tasks file and control files. 207 | // The data is read from libcgroup internal cgroup structure, use 208 | // Cgroup.SetUIDGID() or Cgroup.Get() to fill it. 209 | func (cg Cgroup) GetUIDGID() (tasksUID UID, tasksGID GID, controlUID UID, controlGID GID, err error) { 210 | var ( 211 | cTU C.uid_t 212 | cTG C.gid_t 213 | cCU C.uid_t 214 | cCG C.gid_t 215 | ) 216 | err = _err(C.cgroup_get_uid_gid(cg.g, 217 | &cTU, 218 | &cTG, 219 | &cCU, 220 | &cCG)) 221 | return UID(cTU), GID(cTG), UID(cCU), GID(cCG), err 222 | 223 | } 224 | 225 | const ( 226 | // NoPerms is uninitialized file/directory permissions used for task/control files. 227 | NoPerms = C.NO_PERMS 228 | 229 | // NoUIDGID is uninitialized UID/GID used for task/control files. 230 | NoUIDGID = C.NO_UID_GID 231 | ) 232 | 233 | // Mode is the file permissions. Like used in SetPermissions() 234 | type Mode C.mode_t 235 | 236 | /* 237 | SetPermissions stores given file permissions of the group's control and tasks files 238 | into the cgroup data structure. Use NoPerms if permissions shouldn't 239 | be changed or a value which applicable to chmod(2). Please note that 240 | the given permissions are masked with the file owner's permissions. 241 | For example if a control file has permissions 640 and controlFilePerm is 242 | 471 the result will be 460. 243 | 244 | controlDirPerm Directory permission for the group. 245 | controlFilePerm File permission for the control files. 246 | taskFilePerm File permissions for task file. 247 | 248 | g := cgroup.NewCgroup("foo") 249 | g.SetPermissions(cgroup.Mode(0777), cgroup.Mode(0777), cgroup.Mode(0777)) 250 | */ 251 | func (cg Cgroup) SetPermissions(controlDirPerm, controlFilePerm, taskFilePerm Mode) { 252 | C.cgroup_set_permissions(cg.g, C.mode_t(controlDirPerm), 253 | C.mode_t(controlFilePerm), C.mode_t(taskFilePerm)) 254 | } 255 | 256 | // CopyCgroup copies all controllers, parameters and their values. All existing 257 | // controllers in the source group are discarded. 258 | func CopyCgroup(src, dest Cgroup) error { 259 | return _err(C.cgroup_copy_cgroup(src.g, dest.g)) 260 | } 261 | 262 | // CompareCgroup compares names, owners, controllers, parameters and values of two groups. 263 | // 264 | // Return value of: 265 | // * nil - a and b are equal 266 | // * ErrGroupNotEqual - groups are not equal 267 | // * ErrControllerNotEqual - controllers are not equal 268 | func CompareCgroup(a, b Cgroup) error { 269 | return _err(C.cgroup_compare_cgroup(a.g, b.g)) 270 | } 271 | 272 | // Controller is the structure describing a controller attached to one struct 273 | // @c cgroup, including parameters of the group and their values. The structure 274 | // is opaque to applications. 275 | type Controller struct { 276 | c *C.struct_cgroup_controller 277 | } 278 | 279 | // AddValueString adds parameter and its value to internal libcgroup 280 | // structures. Use Cgroup.Modify() or Cgroup.Create() to write it to kernel. 281 | // 282 | // Name of the parameter and its value 283 | func (c Controller) AddValueString(name, value string) error { 284 | return _err(C.cgroup_add_value_string(c.c, C.CString(name), C.CString(value))) 285 | } 286 | 287 | func (c Controller) AddValueInt64(name string, value int64) error { 288 | return _err(C.cgroup_add_value_int64(c.c, C.CString(name), C.int64_t(value))) 289 | } 290 | 291 | func (c Controller) AddValueBool(name string, value bool) error { 292 | return _err(C.cgroup_add_value_bool(c.c, C.CString(name), C.bool(value))) 293 | } 294 | 295 | // GetValueString fetches the values from the controller. Use Cgroup.Get() to 296 | // get the names available to fetch values from the kernel. 297 | func (c Controller) GetValueString(name string) (value string, err error) { 298 | var v *C.char 299 | err = _err(C.cgroup_get_value_string(c.c, C.CString(name), &v)) 300 | return C.GoString(v), err 301 | } 302 | 303 | func (c Controller) GetValueInt64(name string) (value int64, err error) { 304 | var v C.int64_t 305 | err = _err(C.cgroup_get_value_int64(c.c, C.CString(name), &v)) 306 | return int64(v), err 307 | } 308 | 309 | func (c Controller) GetValueBool(name string) (value bool, err error) { 310 | var v C.bool 311 | err = _err(C.cgroup_get_value_bool(c.c, C.CString(name), &v)) 312 | return bool(v), err 313 | } 314 | 315 | // SetValueString sets a parameter value in @c libcgroup internal structures. 316 | // Use Cgroup.Modify() or Cgroup.Create() to write it to kernel. 317 | func (c Controller) SetValueString(name, value string) error { 318 | return _err(C.cgroup_set_value_string(c.c, C.CString(name), C.CString(value))) 319 | } 320 | 321 | func (c Controller) SetValueInt64(name string, value int64) error { 322 | return _err(C.cgroup_set_value_int64(c.c, C.CString(name), C.int64_t(value))) 323 | } 324 | 325 | func (c Controller) SetValueUint64(name string, value uint64) error { 326 | return _err(C.cgroup_set_value_uint64(c.c, C.CString(name), C.u_int64_t(value))) 327 | } 328 | 329 | func (c Controller) SetValueBool(name string, value bool) error { 330 | return _err(C.cgroup_set_value_bool(c.c, C.CString(name), C.bool(value))) 331 | } 332 | 333 | /* 334 | CompareControllers compares names, parameters and values of two controllers. 335 | 336 | Return value of: 337 | * nil - a and b are equal 338 | * ErrControllerNotEqual - controllers are not equal 339 | */ 340 | func CompareControllers(a, b Controller) error { 341 | return _err(C.cgroup_compare_controllers(a.c, b.c)) 342 | } 343 | 344 | // LoadConfig file and mount and create control groups described there. 345 | // See cgconfig.conf(5) man page for format of the file. 346 | func LoadConfig(filename string) error { 347 | return _err(C.cgroup_config_load_config(C.CString(filename))) 348 | } 349 | 350 | // Unload deletes all control groups and unmount all hierarchies. 351 | func Unload() error { 352 | return _err(C.cgroup_unload_cgroups()) 353 | } 354 | 355 | type DeleteFlag int 356 | 357 | const ( 358 | // DeleteIgnoreMigration ignore errors caused by migration of tasks to parent group. 359 | DeleteIgnoreMigration = DeleteFlag(C.CGFLAG_DELETE_IGNORE_MIGRATION) 360 | 361 | // DeleteRecursive recursively delete all child groups. 362 | DeleteRecursive = DeleteFlag(C.CGFLAG_DELETE_RECURSIVE) 363 | 364 | // DeleteEmptyOnly deletes the cgroup only if it is empty, i.e. it has no 365 | // subgroups and no processes inside. This flag cannot be used with 366 | // DeleteRecursive 367 | DeleteEmptyOnly = DeleteFlag(C.CGFLAG_DELETE_EMPTY_ONLY) 368 | ) 369 | 370 | /* 371 | UnloadFromConfig deletes all cgroups and unmount all mount points defined in 372 | specified config file. 373 | 374 | The groups are either removed recursively or only the empty ones, based on 375 | given flags. Mount point are always umounted only if they are empty, regardless 376 | of any flags. 377 | 378 | The groups are sorted before they are removed, so the removal of empty ones 379 | actually works (i.e. subgroups are removed first). 380 | */ 381 | func UnloadFromConfig(filename string, flags DeleteFlag) error { 382 | return _err(C.cgroup_config_unload_config(C.CString(filename), C.int(flags))) 383 | } 384 | 385 | /* 386 | SetDefault permissions of groups created by subsequent 387 | cgroup_config_load_config() calls. If a config file contains a 'default {}' 388 | section, the default permissions from the config file is then used. 389 | 390 | Use cgroup_new_cgroup() to create a dummy group and cgroup_set_uid_gid() and 391 | cgroup_set_permissions() to set its permissions. Use NoUIDGID instead of 392 | GID/UID and NoPerms instead of file/directory permissions to let kernel 393 | decide the default permissions where you don't want specific user and/or 394 | permissions. Kernel then uses current user/group and permissions from umask 395 | then. 396 | 397 | New default permissions from this group are copied to libcgroup internal 398 | structures. 399 | */ 400 | func SetDefault(cg Cgroup) error { 401 | return _err(C.cgroup_config_set_default(cg.g)) 402 | } 403 | 404 | // FileInfo is the Information about found cgroup directory (= a control group). 405 | type FileInfo struct { 406 | fileType FileType 407 | path string 408 | parent string 409 | fullPath string 410 | depth int8 411 | } 412 | 413 | // FileType of this cgroup's 414 | func (fi FileInfo) FileType() FileType { 415 | return fi.fileType 416 | } 417 | 418 | // Path to this cgroup 419 | func (fi FileInfo) Path() string { 420 | return fi.path 421 | } 422 | 423 | // Parent of this cgroup 424 | func (fi FileInfo) Parent() string { 425 | return fi.parent 426 | } 427 | 428 | // FullPath to this cgroup 429 | func (fi FileInfo) FullPath() string { 430 | return fi.fullPath 431 | } 432 | 433 | // Depth of this cgroup 434 | func (fi FileInfo) Depth() int8 { 435 | return fi.depth 436 | } 437 | 438 | func fromCFileInfo(cData C.struct_cgroup_file_info) FileInfo { 439 | return FileInfo{ 440 | fileType: FileType(C.type_from_file_info(cData)), 441 | path: C.GoString(cData.path), 442 | parent: C.GoString(cData.parent), 443 | fullPath: C.GoString(cData.full_path), 444 | depth: int8(cData.depth), 445 | } 446 | } 447 | 448 | type FileType int 449 | 450 | const ( 451 | FileTypeFile = FileType(C.CGROUP_FILE_TYPE_FILE) 452 | FileTypeDir = FileType(C.CGROUP_FILE_TYPE_DIR) 453 | FileTypeOther = FileType(C.CGROUP_FILE_TYPE_OTHER) 454 | ) 455 | 456 | /* 457 | int cgroup_walk_tree_begin(const char *controller, const char *base_path, int depth, 458 | void **handle, struct cgroup_file_info *info, 459 | int *base_level); 460 | */ 461 | 462 | // ControllerData is the information model for controllers available 463 | type ControllerData struct { 464 | name string 465 | hierarchy int 466 | numCgroups int 467 | enabled int 468 | } 469 | 470 | // Name of the this controller 471 | func (cd ControllerData) Name() string { 472 | return cd.name 473 | } 474 | 475 | // Hierarchy is the identification of the controller. Controllers with the same 476 | // hierarchy ID are mounted together as one hierarchy. Controllers with ID 0 477 | // are not currently mounted anywhere. 478 | func (cd ControllerData) Hierarchy() int { 479 | return cd.hierarchy 480 | } 481 | 482 | // NumCgroups is the number of cgroups 483 | func (cd ControllerData) NumCgroups() int { 484 | return cd.numCgroups 485 | } 486 | 487 | // Enabled indicates whether or not this controller is enabled 488 | func (cd ControllerData) Enabled() int { 489 | return cd.enabled 490 | } 491 | 492 | func fromCControllerData(cData C.struct_controller_data) ControllerData { 493 | return ControllerData{ 494 | name: C.GoString(&cData.name[0]), 495 | hierarchy: int(cData.hierarchy), 496 | numCgroups: int(cData.num_cgroups), 497 | enabled: int(cData.enabled), 498 | } 499 | } 500 | 501 | func GetAllControllers() (controllers []ControllerData, err error) { 502 | var ( 503 | cd C.struct_controller_data 504 | handle unsafe.Pointer 505 | ) 506 | err = _err(C.cgroup_get_all_controller_begin(&handle, &cd)) 507 | if err != nil { 508 | return controllers, err 509 | } 510 | defer C.cgroup_get_all_controller_end(&handle) 511 | 512 | controllers = append(controllers, fromCControllerData(cd)) 513 | for { 514 | err = _err(C.cgroup_get_all_controller_next(&handle, &cd)) 515 | if err != nil { 516 | if err == ErrEOF { 517 | break 518 | } 519 | 520 | return controllers, err 521 | } 522 | controllers = append(controllers, fromCControllerData(cd)) 523 | } 524 | return controllers, nil 525 | } 526 | 527 | func GetSubSysMountPoint(controller string) (string, error) { 528 | var mp *C.char 529 | err := _err(C.cgroup_get_subsys_mount_point(C.CString(controller), &mp)) 530 | if err != nil { 531 | return "", err 532 | } 533 | return C.GoString(mp), nil 534 | } 535 | 536 | // Various errors 537 | var ( 538 | ErrEOF = errors.New(C.GoString(C.cgroup_strerror(C.ECGEOF))) 539 | ErrOTHER = errors.New(C.GoString(C.cgroup_strerror(C.ECGOTHER))) 540 | ErrGroupNotEqual = errors.New(C.GoString(C.cgroup_strerror(C.ECGROUPNOTEQUAL))) 541 | ErrControllerNotEqual = errors.New(C.GoString(C.cgroup_strerror(C.ECGCONTROLLERNOTEQUAL))) 542 | ) 543 | 544 | // LastError returns last errno, which caused ErrOTHER error. 545 | func LastError() error { 546 | return _err(C.cgroup_get_last_errno()) 547 | } 548 | 549 | func _err(num C.int) error { 550 | switch num { 551 | case 0: 552 | return nil 553 | case C.ECGEOF: 554 | return ErrEOF 555 | case C.ECGOTHER: 556 | return ErrOTHER 557 | case C.ECGROUPNOTEQUAL: 558 | return ErrGroupNotEqual 559 | case C.ECGCONTROLLERNOTEQUAL: 560 | return ErrControllerNotEqual 561 | } 562 | // There's a lot. We'll create them as they come 563 | return errors.New(C.GoString(C.cgroup_strerror(num))) 564 | } 565 | 566 | // simple helpers to get UID or GID from a given string 567 | func stringToUID(uidStr string) UID { 568 | intVal, err := strconv.Atoi(uidStr) 569 | if err != nil { 570 | return UID(0) 571 | } 572 | 573 | return UID(intVal) 574 | } 575 | 576 | func stringToGID(gidStr string) GID { 577 | intVal, err := strconv.Atoi(gidStr) 578 | if err != nil { 579 | return GID(0) 580 | } 581 | 582 | return GID(intVal) 583 | } 584 | -------------------------------------------------------------------------------- /cg_test.go: -------------------------------------------------------------------------------- 1 | package cgroup 2 | 3 | import ( 4 | "os/user" 5 | "testing" 6 | ) 7 | 8 | func TestUidGid(t *testing.T) { 9 | Init() 10 | 11 | var wantTaskUid, wantCtrlUid UID 12 | var wantTaskGid, wantCtrlGid GID 13 | 14 | curUser, err := user.Current() 15 | if err == nil { 16 | wantTaskUid = stringToUID(curUser.Uid) 17 | wantTaskGid = stringToGID(curUser.Gid) 18 | wantCtrlUid = stringToUID(curUser.Uid) 19 | wantCtrlGid = stringToGID(curUser.Gid) 20 | } else { 21 | t.Logf("cannot get the current user. fall back to 0.\n") 22 | wantTaskUid, wantTaskGid, wantCtrlUid, wantCtrlGid = 0, 0, 0, 0 23 | } 24 | 25 | cg := NewCgroup("test_cgroup") 26 | if err := cg.SetUIDGID(wantTaskUid, wantTaskGid, wantCtrlUid, wantCtrlGid); err != nil { 27 | t.Fatalf("cannot set cgroup uids/gids: %v\n", err) 28 | } 29 | 30 | gotTaskUid, gotTaskGid, gotCtrlUid, gotCtrlGid, err := cg.GetUIDGID() 31 | if err != nil { 32 | t.Fatalf("cannot get cgroup uids/gids: %v\n", err) 33 | } 34 | 35 | if wantTaskUid != gotTaskUid || wantTaskGid != gotTaskGid || 36 | wantCtrlUid != gotCtrlUid || wantCtrlGid != gotCtrlGid { 37 | t.Fatalf("wanted (%d,%d,%d,%d), got (%d,%d,%d,%d)\n", 38 | wantTaskUid, wantTaskGid, wantCtrlUid, wantCtrlGid, 39 | gotTaskUid, gotTaskGid, gotCtrlUid, gotCtrlGid) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // cmpout 2 | // +build ignore 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | 9 | "github.com/vbatts/go-cgroup" 10 | ) 11 | 12 | func main() { 13 | cgroup.Init() 14 | 15 | g := cgroup.NewCgroup("foo") 16 | c := g.AddController("bar") 17 | fmt.Printf("%#v\n", c) 18 | c = g.GetController("bar") 19 | fmt.Printf("%#v\n", c) 20 | 21 | g.SetPermissions(cgroup.Mode(0777), cgroup.Mode(0777), cgroup.Mode(0777)) 22 | 23 | ctls, err := cgroup.GetAllControllers() 24 | if err != nil { 25 | fmt.Println(err) 26 | return 27 | } 28 | for i := range ctls { 29 | fmt.Printf("Hierarchy=%d Enabled=%d NumCgroups=%d Name=%s\n", ctls[i].Hierarchy(), ctls[i].Enabled(), ctls[i].NumCgroups(), ctls[i].Name()) 30 | } 31 | } 32 | --------------------------------------------------------------------------------