PageRenderTime 70ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/src/common/xcgroup.c

https://github.com/cfenoy/slurm
C | 1194 lines | 855 code | 170 blank | 169 comment | 193 complexity | 37659aacee6ceb2e73735c7ae8072062 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0
  1. /*****************************************************************************\
  2. * xcgroup.c - cgroup related primitives
  3. *****************************************************************************
  4. * Copyright (C) 2009 CEA/DAM/DIF
  5. * Written by Matthieu Hautreux <matthieu.hautreux@cea.fr>
  6. *
  7. * This file is part of SLURM, a resource management program.
  8. * For details, see <http://www.schedmd.com/slurmdocs/>.
  9. * Please also read the included file: DISCLAIMER.
  10. *
  11. * SLURM is free software; you can redistribute it and/or modify it under
  12. * the terms of the GNU General Public License as published by the Free
  13. * Software Foundation; either version 2 of the License, or (at your option)
  14. * any later version.
  15. *
  16. * In addition, as a special exception, the copyright holders give permission
  17. * to link the code of portions of this program with the OpenSSL library under
  18. * certain conditions as described in each individual source file, and
  19. * distribute linked combinations including the two. You must obey the GNU
  20. * General Public License in all respects for all of the code used other than
  21. * OpenSSL. If you modify file(s) with this exception, you may extend this
  22. * exception to your version of the file(s), but you are not obligated to do
  23. * so. If you do not wish to do so, delete this exception statement from your
  24. * version. If you delete this exception statement from all source files in
  25. * the program, then also delete it here.
  26. *
  27. * SLURM is distributed in the hope that it will be useful, but WITHOUT ANY
  28. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  29. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  30. * details.
  31. *
  32. * You should have received a copy of the GNU General Public License along
  33. * with SLURM; if not, write to the Free Software Foundation, Inc.,
  34. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  35. \*****************************************************************************/
  36. #if HAVE_CONFIG_H
  37. # include "config.h"
  38. #endif
  39. #if HAVE_STDINT_H
  40. # include <stdint.h>
  41. #endif
  42. #if HAVE_INTTYPES_H
  43. # include <inttypes.h>
  44. #endif
  45. #include <sys/file.h>
  46. #include <sys/types.h>
  47. #include <sys/stat.h>
  48. #include <unistd.h>
  49. #include <fcntl.h>
  50. #include <stdlib.h>
  51. #include <string.h>
  52. #include <strings.h>
  53. #include <dirent.h>
  54. #include <sys/mount.h>
  55. #include "slurm/slurm.h"
  56. #include "slurm/slurm_errno.h"
  57. #include "src/common/log.h"
  58. #include "src/common/xmalloc.h"
  59. #include "src/common/xstring.h"
  60. #include "src/slurmd/slurmstepd/slurmstepd_job.h"
  61. #include "xcgroup.h"
  62. #ifndef PATH_MAX
  63. #define PATH_MAX 256
  64. #endif
  65. /* internal functions */
  66. size_t _file_getsize(int fd);
  67. int _file_read_uint32s(char* file_path, uint32_t** pvalues, int* pnb);
  68. int _file_write_uint32s(char* file_path, uint32_t* values, int nb);
  69. int _file_read_uint64s(char* file_path, uint64_t** pvalues, int* pnb);
  70. int _file_write_uint64s(char* file_path, uint64_t* values, int nb);
  71. int _file_read_content(char* file_path, char** content, size_t *csize);
  72. int _file_write_content(char* file_path, char* content, size_t csize);
  73. /*
  74. * -----------------------------------------------------------------------------
  75. * xcgroup_ns primitives xcgroup_ns primitives xcgroup_ns primitives
  76. * xcgroup_ns primitives xcgroup_ns primitives xcgroup_ns primitives
  77. * xcgroup_ns primitives xcgroup_ns primitives xcgroup_ns primitives
  78. * -----------------------------------------------------------------------------
  79. */
  80. /*
  81. * create a cgroup namespace for tasks containment
  82. *
  83. * returned values:
  84. * - XCGROUP_ERROR
  85. * - XCGROUP_SUCCESS
  86. */
  87. int xcgroup_ns_create(slurm_cgroup_conf_t *conf,
  88. xcgroup_ns_t *cgns, char *mnt_args, char *subsys) {
  89. cgns->mnt_point = xstrdup_printf("%s/%s",
  90. conf->cgroup_mountpoint, subsys);
  91. cgns->mnt_args = xstrdup(mnt_args);
  92. cgns->subsystems = xstrdup(subsys);
  93. cgns->notify_prog = xstrdup_printf("%s/release_%s",
  94. conf->cgroup_release_agent, subsys);
  95. /* check that freezer cgroup namespace is available */
  96. if (!xcgroup_ns_is_available(cgns)) {
  97. if (conf->cgroup_automount) {
  98. if (xcgroup_ns_mount(cgns)) {
  99. error("unable to mount %s cgroup "
  100. "namespace: %s",
  101. subsys, slurm_strerror(errno));
  102. goto clean;
  103. }
  104. info("cgroup namespace '%s' is now mounted", subsys);
  105. } else {
  106. error("cgroup namespace '%s' not mounted. aborting",
  107. subsys);
  108. goto clean;
  109. }
  110. }
  111. return XCGROUP_SUCCESS;
  112. clean:
  113. xcgroup_ns_destroy(cgns);
  114. return XCGROUP_ERROR;
  115. }
  116. /*
  117. * destroy a cgroup namespace
  118. *
  119. * returned values:
  120. * - XCGROUP_ERROR
  121. * - XCGROUP_SUCCESS
  122. */
  123. int xcgroup_ns_destroy(xcgroup_ns_t* cgns)
  124. {
  125. xfree(cgns->mnt_point);
  126. xfree(cgns->mnt_args);
  127. xfree(cgns->subsystems);
  128. xfree(cgns->notify_prog);
  129. return XCGROUP_SUCCESS;
  130. }
  131. /*
  132. * mount a cgroup namespace
  133. *
  134. * returned values:
  135. * - XCGROUP_ERROR
  136. * - XCGROUP_SUCCESS
  137. *
  138. * If an error occurs, errno will be set.
  139. */
  140. int xcgroup_ns_mount(xcgroup_ns_t* cgns)
  141. {
  142. int fstatus;
  143. char* options;
  144. char opt_combined[1024];
  145. char* mnt_point;
  146. char* p;
  147. xcgroup_t cg;
  148. mode_t cmask;
  149. mode_t omask;
  150. cmask = S_IWGRP | S_IWOTH;
  151. omask = umask(cmask);
  152. fstatus = mkdir(cgns->mnt_point, 0755);
  153. if (fstatus && errno != EEXIST) {
  154. if (cgns->mnt_point[0] != '/') {
  155. debug("unable to create cgroup ns directory '%s'"
  156. " : do not start with '/'", cgns->mnt_point);
  157. umask(omask);
  158. return XCGROUP_ERROR;
  159. }
  160. mnt_point = xstrdup(cgns->mnt_point);
  161. p = mnt_point;
  162. while ((p = index(p+1, '/')) != NULL) {
  163. *p = '\0';
  164. fstatus = mkdir(mnt_point, 0755);
  165. if (fstatus && errno != EEXIST) {
  166. debug("unable to create cgroup ns required "
  167. "directory '%s'", mnt_point);
  168. xfree(mnt_point);
  169. umask(omask);
  170. return XCGROUP_ERROR;
  171. }
  172. *p='/';
  173. }
  174. xfree(mnt_point);
  175. fstatus = mkdir(cgns->mnt_point, 0755);
  176. }
  177. if (fstatus && errno != EEXIST) {
  178. debug("unable to create cgroup ns directory '%s'"
  179. " : %m", cgns->mnt_point);
  180. umask(omask);
  181. return XCGROUP_ERROR;
  182. }
  183. umask(omask);
  184. if (cgns->mnt_args == NULL ||
  185. strlen(cgns->mnt_args) == 0)
  186. options = cgns->subsystems;
  187. else {
  188. if (snprintf(opt_combined, sizeof(opt_combined), "%s,%s",
  189. cgns->subsystems, cgns->mnt_args)
  190. >= sizeof(opt_combined)) {
  191. debug2("unable to build cgroup options string");
  192. return XCGROUP_ERROR;
  193. }
  194. options = opt_combined;
  195. }
  196. if (mount("cgroup", cgns->mnt_point, "cgroup",
  197. MS_NOSUID|MS_NOEXEC|MS_NODEV, options))
  198. return XCGROUP_ERROR;
  199. else {
  200. /* FIXME: this only gets set when we aren't mounted at
  201. all. Since we never umount this may only be loaded
  202. at startup the first time.
  203. */
  204. /* we then set the release_agent if necessary */
  205. if (cgns->notify_prog) {
  206. if (xcgroup_create(cgns, &cg, "/", 0, 0) ==
  207. XCGROUP_ERROR)
  208. return XCGROUP_SUCCESS;
  209. xcgroup_set_param(&cg, "release_agent",
  210. cgns->notify_prog);
  211. xcgroup_destroy(&cg);
  212. }
  213. return XCGROUP_SUCCESS;
  214. }
  215. }
  216. /*
  217. * umount a cgroup namespace
  218. *
  219. * returned values:
  220. * - XCGROUP_ERROR
  221. * - XCGROUP_SUCCESS
  222. *
  223. * If an error occurs, errno will be set.
  224. */
  225. int xcgroup_ns_umount(xcgroup_ns_t* cgns)
  226. {
  227. if (umount(cgns->mnt_point))
  228. return XCGROUP_ERROR;
  229. return XCGROUP_SUCCESS;
  230. }
  231. /*
  232. * check that a cgroup namespace is ready to be used
  233. *
  234. * returned values:
  235. * - XCGROUP_ERROR : not available
  236. * - XCGROUP_SUCCESS : ready to be used
  237. */
  238. int xcgroup_ns_is_available(xcgroup_ns_t* cgns)
  239. {
  240. int fstatus = 0;
  241. char* value;
  242. size_t s;
  243. xcgroup_t cg;
  244. if (xcgroup_create(cgns, &cg, "/", 0, 0) == XCGROUP_ERROR)
  245. return 0;
  246. if (xcgroup_get_param(&cg, "release_agent",
  247. &value, &s) != XCGROUP_SUCCESS)
  248. fstatus = 0;
  249. else {
  250. xfree(value);
  251. fstatus = 1;
  252. }
  253. xcgroup_destroy(&cg);
  254. return fstatus;
  255. }
  256. /*
  257. * Look for the cgroup in a specific cgroup namespace that owns
  258. * a particular pid
  259. *
  260. * returned values:
  261. * - XCGROUP_ERROR
  262. * - XCGROUP_SUCCESS
  263. */
  264. int xcgroup_ns_find_by_pid(xcgroup_ns_t* cgns, xcgroup_t* cg, pid_t pid)
  265. {
  266. int fstatus = SLURM_ERROR;
  267. char file_path[PATH_MAX];
  268. char* buf;
  269. size_t fsize;
  270. char* p;
  271. char* e;
  272. char* entry;
  273. char* subsys;
  274. int found=0;
  275. /* build pid cgroup meta filepath */
  276. if (snprintf(file_path, PATH_MAX, "/proc/%u/cgroup",
  277. pid) >= PATH_MAX) {
  278. debug2("unable to build cgroup meta filepath for pid=%u : %m",
  279. pid);
  280. return XCGROUP_ERROR;
  281. }
  282. /*
  283. * read file content
  284. * multiple lines of the form :
  285. * num_mask:subsystems:relative_path
  286. */
  287. fstatus = _file_read_content(file_path, &buf, &fsize);
  288. if (fstatus == XCGROUP_SUCCESS) {
  289. fstatus = XCGROUP_ERROR;
  290. p = buf;
  291. while (found==0 && (e = index(p, '\n')) != NULL) {
  292. *e='\0';
  293. /* get subsystems entry */
  294. subsys = index(p, ':');
  295. p = e + 1;
  296. if (subsys == NULL)
  297. continue;
  298. subsys++;
  299. /* get relative path entry */
  300. entry = index(subsys, ':');
  301. if (entry == NULL)
  302. continue;
  303. *entry='\0';
  304. /* check subsystem versus ns one */
  305. if (strcmp(cgns->subsystems, subsys) != 0) {
  306. debug("skipping cgroup subsys %s(%s)",
  307. subsys, cgns->subsystems);
  308. continue;
  309. }
  310. else
  311. found=1;
  312. entry++;
  313. fstatus = xcgroup_load(cgns, cg, entry);
  314. break;
  315. }
  316. xfree(buf);
  317. }
  318. return fstatus;
  319. }
  320. /*
  321. * -----------------------------------------------------------------------------
  322. * xcgroup primitives xcgroup primitives xcgroup primitives xcgroup primitives
  323. * xcgroup primitives xcgroup primitives xcgroup primitives xcgroup primitives
  324. * xcgroup primitives xcgroup primitives xcgroup primitives xcgroup primitives
  325. * -----------------------------------------------------------------------------
  326. */
  327. int xcgroup_create(xcgroup_ns_t* cgns, xcgroup_t* cg,
  328. char* uri, uid_t uid, gid_t gid)
  329. {
  330. int fstatus = XCGROUP_ERROR;
  331. char file_path[PATH_MAX];
  332. /* build cgroup absolute path*/
  333. if (snprintf(file_path, PATH_MAX, "%s%s", cgns->mnt_point,
  334. uri) >= PATH_MAX) {
  335. debug2("unable to build cgroup '%s' absolute path in ns '%s' "
  336. ": %m", uri, cgns->subsystems);
  337. return fstatus;
  338. }
  339. /* fill xcgroup structure */
  340. cg->ns = cgns;
  341. cg->name = xstrdup(uri);
  342. cg->path = xstrdup(file_path);
  343. cg->uid = uid;
  344. cg->gid = gid;
  345. cg->notify = 1;
  346. return XCGROUP_SUCCESS;
  347. }
  348. int xcgroup_destroy(xcgroup_t* cg)
  349. {
  350. cg->ns = NULL;
  351. xfree(cg->name);
  352. xfree(cg->path);
  353. cg->uid = -1;
  354. cg->gid = -1;
  355. return XCGROUP_SUCCESS;
  356. }
  357. int xcgroup_lock(xcgroup_t* cg)
  358. {
  359. int fstatus = XCGROUP_ERROR;
  360. if ((cg->fd = open(cg->path, O_RDONLY)) < 0) {
  361. debug2("xcgroup_lock: error from open of cgroup '%s' : %m",
  362. cg->path);
  363. return fstatus;
  364. }
  365. if (flock(cg->fd, LOCK_EX) < 0) {
  366. debug2("xcgroup_lock: error locking cgroup '%s' : %m",
  367. cg->path);
  368. close(cg->fd);
  369. }
  370. else
  371. fstatus = XCGROUP_SUCCESS;
  372. return fstatus;
  373. }
  374. int xcgroup_unlock(xcgroup_t* cg)
  375. {
  376. int fstatus = XCGROUP_ERROR;
  377. if (flock(cg->fd, LOCK_UN) < 0) {
  378. debug2("xcgroup_lock: error unlocking cgroup '%s' : %m",
  379. cg->path);
  380. }
  381. else
  382. fstatus = XCGROUP_SUCCESS;
  383. close(cg->fd);
  384. return fstatus;
  385. }
  386. int xcgroup_instanciate(xcgroup_t* cg)
  387. {
  388. int fstatus = XCGROUP_ERROR;
  389. mode_t cmask;
  390. mode_t omask;
  391. xcgroup_ns_t* cgns;
  392. char* file_path;
  393. uid_t uid;
  394. gid_t gid;
  395. int create_only;
  396. uint32_t notify;
  397. /* init variables based on input cgroup */
  398. cgns = cg->ns;
  399. file_path = cg->path;
  400. uid = cg->uid;
  401. gid = cg->gid;
  402. create_only=0;
  403. notify = cg->notify;
  404. /* save current mask and apply working one */
  405. cmask = S_IWGRP | S_IWOTH;
  406. omask = umask(cmask);
  407. /* build cgroup */
  408. if (mkdir(file_path, 0755)) {
  409. if (create_only || errno != EEXIST) {
  410. debug2("unable to create cgroup '%s' : %m",
  411. file_path);
  412. umask(omask);
  413. return fstatus;
  414. }
  415. }
  416. umask(omask);
  417. /* change cgroup ownership as requested */
  418. if (chown(file_path, uid, gid)) {
  419. debug2("unable to chown %d:%d cgroup '%s' : %m",
  420. uid, gid, file_path);
  421. return fstatus;
  422. }
  423. /* following operations failure might not result in a general
  424. * failure so set output status to success */
  425. fstatus = XCGROUP_SUCCESS;
  426. /* set notify on release flag */
  427. if (notify == 1 && cgns->notify_prog)
  428. xcgroup_set_params(cg, "notify_on_release=1");
  429. else
  430. xcgroup_set_params(cg, "notify_on_release=0");
  431. return fstatus;
  432. }
  433. int xcgroup_load(xcgroup_ns_t* cgns, xcgroup_t* cg, char* uri)
  434. {
  435. int fstatus = XCGROUP_ERROR;
  436. char file_path[PATH_MAX];
  437. struct stat buf;
  438. /* build cgroup absolute path*/
  439. if (snprintf(file_path, PATH_MAX, "%s%s", cgns->mnt_point,
  440. uri) >= PATH_MAX) {
  441. debug2("unable to build cgroup '%s' absolute path in ns '%s' "
  442. ": %m", uri, cgns->subsystems);
  443. return fstatus;
  444. }
  445. if (stat((const char*)file_path, &buf)) {
  446. debug2("unable to get cgroup '%s' entry '%s' properties"
  447. ": %m", cgns->mnt_point, file_path);
  448. return fstatus;
  449. }
  450. /* fill xcgroup structure */
  451. cg->ns = cgns;
  452. cg->name = xstrdup(uri);
  453. cg->path = xstrdup(file_path);
  454. cg->uid = buf.st_uid;
  455. cg->gid = buf.st_gid;
  456. /* read the content of the notify flag */
  457. xcgroup_get_uint32_param(cg,"notify_on_release",&(cg->notify));
  458. return XCGROUP_SUCCESS;
  459. }
  460. int xcgroup_delete(xcgroup_t* cg)
  461. {
  462. if (rmdir(cg->path))
  463. return XCGROUP_ERROR;
  464. else
  465. return XCGROUP_SUCCESS;
  466. }
  467. static int cgroup_procs_readable (xcgroup_t *cg)
  468. {
  469. struct stat st;
  470. char *path = NULL;
  471. int rc = 0;
  472. xstrfmtcat (path, "%s/%s", cg->path, "cgroup.procs");
  473. if ((stat (path, &st) >= 0) && (st.st_mode & S_IRUSR))
  474. rc = 1;
  475. xfree (path);
  476. return (rc);
  477. }
  478. static int cgroup_procs_writable (xcgroup_t *cg)
  479. {
  480. struct stat st;
  481. char *path = NULL;
  482. int rc = 0;
  483. xstrfmtcat (path, "%s/%s", cg->path, "cgroup.procs");
  484. if ((stat (path, &st) >= 0) && (st.st_mode & S_IWUSR))
  485. rc = 1;
  486. xfree (path);
  487. return (rc);
  488. }
  489. // This call is not intended to be used to move thread pids
  490. int xcgroup_add_pids(xcgroup_t* cg, pid_t* pids, int npids)
  491. {
  492. int fstatus = XCGROUP_ERROR;
  493. char* path = NULL;
  494. // If possible use cgroup.procs to add the processes atomically
  495. if (cgroup_procs_writable (cg))
  496. xstrfmtcat (path, "%s/%s", cg->path, "cgroup.procs");
  497. else
  498. xstrfmtcat (path, "%s/%s", cg->path, "tasks");
  499. fstatus = _file_write_uint32s(path, (uint32_t*)pids, npids);
  500. if (fstatus != XCGROUP_SUCCESS)
  501. debug2("unable to add pids to '%s'", cg->path);
  502. xfree(path);
  503. return fstatus;
  504. }
  505. // This call is not intended to be used to get thread pids
  506. int xcgroup_get_pids(xcgroup_t* cg, pid_t **pids, int *npids)
  507. {
  508. int fstatus = XCGROUP_ERROR;
  509. char* path = NULL;
  510. if (pids == NULL || npids == NULL)
  511. return SLURM_ERROR;
  512. if (cgroup_procs_readable (cg))
  513. xstrfmtcat (path, "%s/%s", cg->path, "cgroup.procs");
  514. else
  515. xstrfmtcat (path, "%s/%s", cg->path, "tasks");
  516. fstatus = _file_read_uint32s(path, (uint32_t**)pids, npids);
  517. if (fstatus != XCGROUP_SUCCESS)
  518. debug2("unable to get pids of '%s'", cg->path);
  519. xfree(path);
  520. return fstatus;
  521. }
  522. int xcgroup_set_params(xcgroup_t* cg, char* parameters)
  523. {
  524. int fstatus = XCGROUP_ERROR;
  525. char file_path[PATH_MAX];
  526. char* cpath = cg->path;
  527. char* params;
  528. char* value;
  529. char* p;
  530. char* next;
  531. params = (char*) xstrdup(parameters);
  532. p = params;
  533. while (p != NULL && *p != '\0') {
  534. next = index(p, ' ');
  535. if (next) {
  536. *next='\0';
  537. next++;
  538. while (*next == ' ')
  539. next++;
  540. }
  541. value = index(p, '=');
  542. if (value != NULL) {
  543. *value='\0';
  544. value++;
  545. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, p)
  546. >= PATH_MAX) {
  547. debug2("unable to build filepath for '%s' and"
  548. " parameter '%s' : %m", cpath, p);
  549. goto next_loop;
  550. }
  551. fstatus = _file_write_content(file_path, value,
  552. strlen(value));
  553. if (fstatus != XCGROUP_SUCCESS)
  554. debug2("unable to set parameter '%s' to "
  555. "'%s' for '%s'", p, value, cpath);
  556. else
  557. debug3("parameter '%s' set to '%s' for '%s'",
  558. p, value, cpath);
  559. }
  560. else
  561. debug2("bad parameters format for entry '%s'", p);
  562. next_loop:
  563. p = next;
  564. }
  565. xfree(params);
  566. return fstatus;
  567. }
  568. int xcgroup_set_param(xcgroup_t* cg, char* param, char* content)
  569. {
  570. int fstatus = XCGROUP_ERROR;
  571. char file_path[PATH_MAX];
  572. char* cpath = cg->path;
  573. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  574. debug2("unable to build filepath for '%s' and"
  575. " parameter '%s' : %m", cpath, param);
  576. return fstatus;
  577. }
  578. fstatus = _file_write_content(file_path, content, strlen(content));
  579. if (fstatus != XCGROUP_SUCCESS)
  580. debug2("unable to set parameter '%s' to "
  581. "'%s' for '%s'", param, content, cpath);
  582. else
  583. debug3("parameter '%s' set to '%s' for '%s'",
  584. param, content, cpath);
  585. return fstatus;
  586. }
  587. int xcgroup_get_param(xcgroup_t* cg, char* param, char **content, size_t *csize)
  588. {
  589. int fstatus = XCGROUP_ERROR;
  590. char file_path[PATH_MAX];
  591. char* cpath = cg->path;
  592. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  593. debug2("unable to build filepath for '%s' and"
  594. " parameter '%s' : %m", cpath, param);
  595. }
  596. else {
  597. fstatus = _file_read_content(file_path, content, csize);
  598. if (fstatus != XCGROUP_SUCCESS)
  599. debug2("unable to get parameter '%s' for '%s'",
  600. param, cpath);
  601. }
  602. return fstatus;
  603. }
  604. int xcgroup_set_uint32_param(xcgroup_t* cg, char* param, uint32_t value)
  605. {
  606. int fstatus = XCGROUP_ERROR;
  607. char file_path[PATH_MAX];
  608. char* cpath = cg->path;
  609. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  610. debug2("unable to build filepath for '%s' and"
  611. " parameter '%s' : %m", cpath, param);
  612. return fstatus;
  613. }
  614. fstatus = _file_write_uint32s(file_path, &value, 1);
  615. if (fstatus != XCGROUP_SUCCESS)
  616. debug2("unable to set parameter '%s' to "
  617. "'%u' for '%s'", param, value, cpath);
  618. else
  619. debug3("parameter '%s' set to '%u' for '%s'",
  620. param, value, cpath);
  621. return fstatus;
  622. }
  623. int xcgroup_get_uint32_param(xcgroup_t* cg, char* param, uint32_t* value)
  624. {
  625. int fstatus = XCGROUP_ERROR;
  626. char file_path[PATH_MAX];
  627. char* cpath = cg->path;
  628. uint32_t* values;
  629. int vnb;
  630. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  631. debug2("unable to build filepath for '%s' and"
  632. " parameter '%s' : %m", cpath, param);
  633. }
  634. else {
  635. fstatus = _file_read_uint32s(file_path, &values, &vnb);
  636. if (fstatus != XCGROUP_SUCCESS)
  637. debug2("unable to get parameter '%s' for '%s'",
  638. param, cpath);
  639. else if (vnb < 1) {
  640. debug2("empty parameter '%s' for '%s'",
  641. param, cpath);
  642. }
  643. else {
  644. *value = values[0];
  645. xfree(values);
  646. fstatus = XCGROUP_SUCCESS;
  647. }
  648. }
  649. return fstatus;
  650. }
  651. int xcgroup_set_uint64_param(xcgroup_t* cg, char* param, uint64_t value)
  652. {
  653. int fstatus = XCGROUP_ERROR;
  654. char file_path[PATH_MAX];
  655. char* cpath = cg->path;
  656. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  657. debug2("unable to build filepath for '%s' and"
  658. " parameter '%s' : %m", cpath, param);
  659. return fstatus;
  660. }
  661. fstatus = _file_write_uint64s(file_path, &value, 1);
  662. if (fstatus != XCGROUP_SUCCESS)
  663. debug2("unable to set parameter '%s' to "
  664. "'%"PRIu64"' for '%s'", param, value, cpath);
  665. else
  666. debug3("parameter '%s' set to '%"PRIu64"' for '%s'",
  667. param, value, cpath);
  668. return fstatus;
  669. }
  670. int xcgroup_get_uint64_param(xcgroup_t* cg, char* param, uint64_t* value)
  671. {
  672. int fstatus = XCGROUP_ERROR;
  673. char file_path[PATH_MAX];
  674. char* cpath = cg->path;
  675. uint64_t* values;
  676. int vnb;
  677. if (snprintf(file_path, PATH_MAX, "%s/%s", cpath, param) >= PATH_MAX) {
  678. debug2("unable to build filepath for '%s' and"
  679. " parameter '%s' : %m", cpath, param);
  680. }
  681. else {
  682. fstatus = _file_read_uint64s(file_path, &values, &vnb);
  683. if (fstatus != XCGROUP_SUCCESS)
  684. debug2("unable to get parameter '%s' for '%s'",
  685. param, cpath);
  686. else if (vnb < 1) {
  687. debug2("empty parameter '%s' for '%s'",
  688. param, cpath);
  689. }
  690. else {
  691. *value = values[0];
  692. xfree(values);
  693. fstatus = XCGROUP_SUCCESS;
  694. }
  695. }
  696. return fstatus;
  697. }
  698. static int cgroup_move_process_by_task (xcgroup_t *cg, pid_t pid)
  699. {
  700. DIR *dir;
  701. struct dirent *entry;
  702. char path [PATH_MAX];
  703. if (snprintf (path, PATH_MAX, "/proc/%d/task", (int) pid) >= PATH_MAX) {
  704. error ("xcgroup: move_process_by_task: path overflow!");
  705. return XCGROUP_ERROR;
  706. }
  707. dir = opendir (path);
  708. if (!dir) {
  709. error ("xcgroup: opendir(%s): %m", path);
  710. return XCGROUP_ERROR;
  711. }
  712. while ((entry = readdir (dir))) {
  713. if (entry->d_name[0] != '.')
  714. xcgroup_set_param (cg, "tasks", entry->d_name);
  715. }
  716. closedir (dir);
  717. return XCGROUP_SUCCESS;
  718. }
  719. int xcgroup_move_process (xcgroup_t *cg, pid_t pid)
  720. {
  721. if (!cgroup_procs_writable (cg))
  722. return cgroup_move_process_by_task (cg, pid);
  723. return xcgroup_set_uint32_param (cg, "cgroup.procs", pid);
  724. }
  725. /*
  726. * -----------------------------------------------------------------------------
  727. * internal primitives internal primitives internal primitives
  728. * internal primitives internal primitives internal primitives
  729. * internal primitives internal primitives internal primitives
  730. * -----------------------------------------------------------------------------
  731. */
  732. size_t _file_getsize(int fd)
  733. {
  734. int rc;
  735. size_t fsize;
  736. off_t offset;
  737. char c;
  738. /* store current position and rewind */
  739. offset = lseek(fd, 0, SEEK_CUR);
  740. if (offset < 0)
  741. return -1;
  742. lseek(fd, 0, SEEK_SET);
  743. /* get file size */
  744. fsize=0;
  745. do {
  746. rc = read(fd, (void*)&c, 1);
  747. if (rc > 0)
  748. fsize++;
  749. }
  750. while ((rc < 0 && errno == EINTR) || rc > 0);
  751. /* restore position */
  752. lseek(fd, offset, SEEK_SET);
  753. if (rc < 0)
  754. return -1;
  755. else
  756. return fsize;
  757. }
  758. int _file_write_uint64s(char* file_path, uint64_t* values, int nb)
  759. {
  760. int fstatus;
  761. int rc;
  762. int fd;
  763. char tstr[256];
  764. uint64_t value;
  765. int i;
  766. /* open file for writing */
  767. fd = open(file_path, O_WRONLY, 0700);
  768. if (fd < 0) {
  769. debug2("unable to open '%s' for writing : %m", file_path);
  770. return XCGROUP_ERROR;
  771. }
  772. /* add one value per line */
  773. fstatus = XCGROUP_SUCCESS;
  774. for (i=0 ; i < nb ; i++) {
  775. value = values[i];
  776. rc = snprintf(tstr, sizeof(tstr), "%"PRIu64"", value);
  777. if (rc < 0) {
  778. debug2("unable to build %"PRIu64" string value, "
  779. "skipping", value);
  780. fstatus = XCGROUP_ERROR;
  781. continue;
  782. }
  783. do {
  784. rc = write(fd, tstr, strlen(tstr)+1);
  785. }
  786. while (rc != 0 && errno == EINTR);
  787. if (rc < 1) {
  788. debug2("unable to add value '%s' to file '%s' : %m",
  789. tstr, file_path);
  790. if ( errno != ESRCH )
  791. fstatus = XCGROUP_ERROR;
  792. }
  793. }
  794. /* close file */
  795. close(fd);
  796. return fstatus;
  797. }
  798. int _file_read_uint64s(char* file_path, uint64_t** pvalues, int* pnb)
  799. {
  800. int rc;
  801. int fd;
  802. size_t fsize;
  803. char* buf;
  804. char* p;
  805. uint64_t* pa=NULL;
  806. int i;
  807. /* check input pointers */
  808. if (pvalues == NULL || pnb == NULL)
  809. return XCGROUP_ERROR;
  810. /* open file for reading */
  811. fd = open(file_path, O_RDONLY, 0700);
  812. if (fd < 0) {
  813. debug2("unable to open '%s' for reading : %m", file_path);
  814. return XCGROUP_ERROR;
  815. }
  816. /* get file size */
  817. fsize=_file_getsize(fd);
  818. if (fsize == -1) {
  819. close(fd);
  820. return XCGROUP_ERROR;
  821. }
  822. /* read file contents */
  823. buf = (char*) xmalloc((fsize+1)*sizeof(char));
  824. do {
  825. rc = read(fd, buf, fsize);
  826. }
  827. while (rc < 0 && errno == EINTR);
  828. close(fd);
  829. buf[fsize]='\0';
  830. /* count values (splitted by \n) */
  831. i=0;
  832. if (rc > 0) {
  833. p = buf;
  834. while (index(p, '\n') != NULL) {
  835. i++;
  836. p = index(p, '\n') + 1;
  837. }
  838. }
  839. /* build uint64_t list */
  840. if (i > 0) {
  841. pa = (uint64_t*) xmalloc(sizeof(uint64_t) * i);
  842. p = buf;
  843. i = 0;
  844. while (index(p, '\n') != NULL) {
  845. long long unsigned int ll_tmp;
  846. sscanf(p, "%llu", &ll_tmp);
  847. pa[i++] = ll_tmp;
  848. p = index(p, '\n') + 1;
  849. }
  850. }
  851. /* free buffer */
  852. xfree(buf);
  853. /* set output values */
  854. *pvalues = pa;
  855. *pnb = i;
  856. return XCGROUP_SUCCESS;
  857. }
  858. int _file_write_uint32s(char* file_path, uint32_t* values, int nb)
  859. {
  860. int fstatus;
  861. int rc;
  862. int fd;
  863. char tstr[256];
  864. uint32_t value;
  865. int i;
  866. /* open file for writing */
  867. fd = open(file_path, O_WRONLY, 0700);
  868. if (fd < 0) {
  869. debug2("unable to open '%s' for writing : %m", file_path);
  870. return XCGROUP_ERROR;
  871. }
  872. /* add one value per line */
  873. fstatus = XCGROUP_SUCCESS;
  874. for (i=0 ; i < nb ; i++) {
  875. value = values[i];
  876. rc = snprintf(tstr, sizeof(tstr), "%u", value);
  877. if (rc < 0) {
  878. debug2("unable to build %u string value, skipping",
  879. value);
  880. fstatus = XCGROUP_ERROR;
  881. continue;
  882. }
  883. do {
  884. rc = write(fd, tstr, strlen(tstr)+1);
  885. }
  886. while (rc < 0 && errno == EINTR);
  887. if (rc < 1) {
  888. debug2("unable to add value '%s' to file '%s' : %m",
  889. tstr, file_path);
  890. if ( errno != ESRCH )
  891. fstatus = XCGROUP_ERROR;
  892. }
  893. }
  894. /* close file */
  895. close(fd);
  896. return fstatus;
  897. }
  898. int _file_read_uint32s(char* file_path, uint32_t** pvalues, int* pnb)
  899. {
  900. int rc;
  901. int fd;
  902. size_t fsize;
  903. char* buf;
  904. char* p;
  905. uint32_t* pa=NULL;
  906. int i;
  907. /* check input pointers */
  908. if (pvalues == NULL || pnb == NULL)
  909. return XCGROUP_ERROR;
  910. /* open file for reading */
  911. fd = open(file_path, O_RDONLY, 0700);
  912. if (fd < 0) {
  913. debug2("unable to open '%s' for reading : %m", file_path);
  914. return XCGROUP_ERROR;
  915. }
  916. /* get file size */
  917. fsize=_file_getsize(fd);
  918. if (fsize == -1) {
  919. close(fd);
  920. return XCGROUP_ERROR;
  921. }
  922. /* read file contents */
  923. buf = (char*) xmalloc((fsize+1)*sizeof(char));
  924. do {
  925. rc = read(fd, buf, fsize);
  926. }
  927. while (rc < 0 && errno == EINTR);
  928. close(fd);
  929. buf[fsize]='\0';
  930. /* count values (splitted by \n) */
  931. i=0;
  932. if (rc > 0) {
  933. p = buf;
  934. while (index(p, '\n') != NULL) {
  935. i++;
  936. p = index(p, '\n') + 1;
  937. }
  938. }
  939. /* build uint32_t list */
  940. if (i > 0) {
  941. pa = (uint32_t*) xmalloc(sizeof(uint32_t) * i);
  942. p = buf;
  943. i = 0;
  944. while (index(p, '\n') != NULL) {
  945. sscanf(p, "%u", pa+i);
  946. p = index(p, '\n') + 1;
  947. i++;
  948. }
  949. }
  950. /* free buffer */
  951. xfree(buf);
  952. /* set output values */
  953. *pvalues = pa;
  954. *pnb = i;
  955. return XCGROUP_SUCCESS;
  956. }
  957. int _file_write_content(char* file_path, char* content, size_t csize)
  958. {
  959. int fstatus;
  960. int rc;
  961. int fd;
  962. /* open file for writing */
  963. fd = open(file_path, O_WRONLY, 0700);
  964. if (fd < 0) {
  965. debug2("unable to open '%s' for writing : %m", file_path);
  966. return XCGROUP_ERROR;
  967. }
  968. /* write content */
  969. do {
  970. rc = write(fd, content, csize);
  971. }
  972. while (rc != 0 && errno == EINTR);
  973. /* check read size */
  974. if (rc < csize) {
  975. debug2("unable to write %lu bytes to file '%s' : %m",
  976. (long unsigned int) csize, file_path);
  977. fstatus = XCGROUP_ERROR;
  978. }
  979. else
  980. fstatus = XCGROUP_SUCCESS;
  981. /* close file */
  982. close(fd);
  983. return fstatus;
  984. }
  985. int _file_read_content(char* file_path, char** content, size_t *csize)
  986. {
  987. int fstatus;
  988. int rc;
  989. int fd;
  990. size_t fsize;
  991. char* buf;
  992. fstatus = XCGROUP_ERROR;
  993. /* check input pointers */
  994. if (content == NULL || csize == NULL)
  995. return fstatus;
  996. /* open file for reading */
  997. fd = open(file_path, O_RDONLY, 0700);
  998. if (fd < 0) {
  999. debug2("unable to open '%s' for reading : %m", file_path);
  1000. return fstatus;
  1001. }
  1002. /* get file size */
  1003. fsize=_file_getsize(fd);
  1004. if (fsize == -1) {
  1005. close(fd);
  1006. return fstatus;
  1007. }
  1008. /* read file contents */
  1009. buf = (char*) xmalloc((fsize+1)*sizeof(char));
  1010. buf[fsize]='\0';
  1011. do {
  1012. rc = read(fd, buf, fsize);
  1013. }
  1014. while (rc < 0 && errno == EINTR);
  1015. /* set output values */
  1016. if (rc >= 0) {
  1017. *content = buf;
  1018. *csize = rc;
  1019. fstatus = XCGROUP_SUCCESS;
  1020. }
  1021. /* close file */
  1022. close(fd);
  1023. return fstatus;
  1024. }