]>
Commit | Line | Data |
---|---|---|
4a308d66 CB |
1 | #### General Notes |
2 | ||
3 | - The coding style guide refers to new code. But legacy code can be cleaned up | |
4 | and we are happy to take those patches. | |
5 | - Just because there is still code in LXC that doesn't adhere to the coding | |
6 | standards outlined here does not license not adhering to the coding style. In | |
7 | other words: please stick to the coding style. | |
8 | - Maintainers are free to ignore rules specified here when merging pull | |
9 | requests. This guideline might seem a little weird but it exits to ease new | |
10 | developers into the code base and to prevent unnecessary bikeshedding. If | |
11 | a maintainer feels hat enforcing a specific rule in a given commit would do | |
12 | more harm than good they should always feel free to ignore the rule. | |
13 | ||
14 | Furthermore, when merging pull requests that do not adhere to our coding | |
15 | style maintainers should feel free to grab the commit, adapt it to our coding | |
16 | style and add their Signed-off-by line to it. This is especially helpful to | |
17 | make it easier for first-time contributors and to prevent having pull | |
18 | requests being stuck in the merge queue because of minor details. | |
c67cb619 CB |
19 | - We currently do not provide automatic coding style checks but if a suitable |
20 | tool is found we are happy to integrate it into our test suite. It is | |
21 | possible and recommended to use the `clang-format` binary to check your code. | |
22 | The following options are an approximation of the coding style used here. | |
23 | Simply create a file called `.clang-format` in your home directory with the | |
24 | following options: | |
25 | ```sh | |
26 | cat << EOF > "${HOME}"/.clang-format | |
b629739c | 27 | AlignEscapedNewlines: Left |
c67cb619 CB |
28 | BreakBeforeBraces: Attach |
29 | AlwaysBreakBeforeMultilineStrings: false | |
30 | BreakBeforeBinaryOperators: None | |
31 | MaxEmptyLinesToKeep: 1 | |
32 | PenaltyBreakBeforeFirstCallParameter: 1000000 | |
33 | BinPackArguments: true | |
34 | BinPackParameters: true | |
35 | AllowAllParametersOfDeclarationOnNextLine: false | |
36 | AlignAfterOpenBracket: true | |
37 | SpacesInSquareBrackets: false | |
38 | SpacesInCStyleCastParentheses: false | |
39 | SpaceInEmptyParentheses: false | |
40 | SpaceBeforeParens: ControlStatements | |
41 | SpaceAfterCStyleCast: false | |
42 | SortIncludes: true | |
43 | PenaltyReturnTypeOnItsOwnLine: 10000 | |
44 | PenaltyExcessCharacter: 10 | |
45 | Language: Cpp | |
46 | ForEachMacros: ['lxc_list_for_each', 'lxc_list_for_each_safe'] | |
47 | AllowShortLoopsOnASingleLine: false | |
48 | AllowShortIfStatementsOnASingleLine: false | |
49 | AllowShortFunctionsOnASingleLine: None | |
50 | AllowShortCaseLabelsOnASingleLine: false | |
51 | AllowShortBlocksOnASingleLine: false | |
52 | BasedOnStyle: LLVM | |
53 | TabWidth: 8 | |
54 | IndentWidth: 8 | |
55 | UseTab: Always | |
56 | BreakBeforeBraces: Linux | |
57 | AllowShortIfStatementsOnASingleLine: false | |
58 | IndentCaseLabels: false | |
59 | EOF | |
60 | ``` | |
61 | However, it will not handle all cases correctly. For example, most `struct` | |
62 | initializations will not be correct. In such cases please refer to the coding | |
63 | style here. | |
4a308d66 CB |
64 | |
65 | #### Only Use Tabs | |
66 | ||
67 | - LXC uses tabs. | |
68 | ||
69 | #### Only use `/* */` Style Comments | |
70 | ||
71 | - Any comments that are added must use `/* */`. | |
72 | - All comments should start on the same line as the opening `/*`. | |
73 | - Single-line comments should simply be placed between `/* */`. For example: | |
b0c407f7 | 74 | ```C |
4a308d66 CB |
75 | /* Define pivot_root() if missing from the C library */ |
76 | ``` | |
77 | - Multi-line comments should end with the closing `*/` on a separate line. For | |
78 | example: | |
b0c407f7 | 79 | ```C |
4a308d66 CB |
80 | /* At this point the old-root is mounted on top of our new-root |
81 | * To unmounted it we must not be chdir()ed into it, so escape back | |
82 | * to old-root. | |
83 | */ | |
84 | ``` | |
85 | ||
86 | #### Try To Wrap At 80chars | |
87 | ||
88 | - This is not strictly enforced. It is perfectly valid to sometimes | |
89 | overflow this limit if it helps clarity. Nonetheless, try to stick to it | |
90 | and use common sense to decide when not to. | |
91 | ||
92 | #### Error Messages | |
93 | ||
94 | - Error messages must start with a capital letter and must **not** end with a | |
95 | punctuation sign. | |
96 | - They should be descriptive, without being needlessly long. It is best to just | |
97 | use already existing error messages as examples. | |
98 | - Examples of acceptable error messages are: | |
b0c407f7 | 99 | ```C |
4a308d66 CB |
100 | SYSERROR("Failed to create directory \"%s\"", path); |
101 | WARN("\"/dev\" directory does not exist. Proceeding without autodev being set up"); | |
102 | ``` | |
103 | ||
104 | #### Return Error Codes | |
105 | ||
106 | - When writing a function that can fail in a non-binary way try to return | |
107 | meaningful negative error codes (e.g. `return -EINVAL;`). | |
108 | ||
109 | #### All Unexported Functions Must Be Declared `static` | |
110 | ||
111 | - Functions which are only used in the current file and are not exported | |
112 | within the codebase need to be declared with the `static` attribute. | |
113 | ||
114 | #### All Exported Functions Must Be Declared `extern` In A Header File | |
115 | ||
116 | - Functions which are used in different files in the library should be declared | |
117 | in a suitable `*.c` file and exposed in a suitable `*.h` file. When defining | |
118 | the function in the `*.c` file the function signature should not be preceded | |
119 | by the `extern` keyword. When declaring the function signature in the `*.h` | |
120 | file it must be preceded by the `extern` keyword. For example: | |
b0c407f7 | 121 | ```C |
4a308d66 CB |
122 | /* Valid function definition in a *.c file */ |
123 | ssize_t lxc_write_nointr(int fd, const void* buf, size_t count) | |
124 | { | |
125 | ssize_t ret; | |
126 | again: | |
127 | ret = write(fd, buf, count); | |
128 | if (ret < 0 && errno == EINTR) | |
129 | goto again; | |
130 | return ret; | |
131 | } | |
132 | ||
133 | /* Valid function declaration in a *.h file */ | |
134 | extern ssize_t lxc_write_nointr(int fd, const void* buf, size_t count); | |
135 | ``` | |
136 | ||
137 | #### All Names Must Be In lower_case | |
138 | ||
139 | - All functions and variable names must use lower case. | |
140 | ||
141 | #### Declaring Variables | |
142 | ||
143 | - variables should be declared at the top of the function or at the beginning | |
144 | of a new scope but **never** in the middle of a scope | |
145 | 1. uninitialized variables | |
146 | - put base types before complex types | |
147 | - put standard types defined by libc before types defined by LXC | |
148 | - put multiple declarations of the same type on the same line | |
149 | 2. initialized variables | |
150 | - put base types before complex types | |
151 | - put standard types defined by libc before types defined by LXC | |
152 | - put multiple declarations of the same type on the same line | |
153 | - Examples of good declarations can be seen in the following function: | |
b0c407f7 | 154 | ```C |
4a308d66 CB |
155 | int lxc_clear_procs(struct lxc_conf *c, const char *key) |
156 | { | |
157 | struct lxc_list *it, *next; | |
158 | bool all = false; | |
159 | const char *k = NULL; | |
160 | ||
161 | if (strcmp(key, "lxc.proc") == 0) | |
162 | all = true; | |
163 | else if (strncmp(key, "lxc.proc.", sizeof("lxc.proc.") - 1) == 0) | |
164 | k = key + sizeof("lxc.proc.") - 1; | |
165 | else | |
166 | return -1; | |
167 | ||
168 | lxc_list_for_each_safe(it, &c->procs, next) { | |
169 | struct lxc_proc *proc = it->elem; | |
170 | ||
171 | if (!all && strcmp(proc->filename, k) != 0) | |
172 | continue; | |
173 | lxc_list_del(it); | |
174 | free(proc->filename); | |
175 | free(proc->value); | |
176 | free(proc); | |
177 | free(it); | |
178 | } | |
179 | ||
180 | return 0; | |
181 | } | |
182 | ``` | |
183 | ||
184 | #### Single-line `if` blocks should not be enclosed in `{}` | |
185 | ||
186 | - This also affects `if-else` ladders if and only if all constituting | |
187 | conditions are | |
188 | single-line conditions. If there is at least one non-single-line | |
189 | condition `{}` must be used. | |
190 | - For example: | |
b0c407f7 | 191 | ```C |
4a308d66 CB |
192 | /* no brackets needed */ |
193 | if (size > INT_MAX) | |
194 | return -EFBIG; | |
195 | ||
196 | /* The else branch has more than one-line and so needs {}. This entails that | |
197 | * the if branch also needs to have {}. | |
198 | */ | |
199 | if ( errno == EROFS ) { | |
200 | WARN("Warning: Read Only file system while creating %s", path); | |
201 | } else { | |
202 | SYSERROR("Error creating %s", path); | |
203 | return -1; | |
204 | } | |
205 | ||
206 | /* also fine */ | |
207 | for (i = 0; list[i]; i++) | |
208 | if (strcmp(list[i], entry) == 0) | |
209 | return true; | |
210 | ||
211 | /* also fine */ | |
212 | if (ret < 0) | |
213 | WARN("Failed to set FD_CLOEXEC flag on slave fd %d of " | |
214 | "pty device \"%s\": %s", pty_info->slave, | |
215 | pty_info->name, strerror(errno)); | |
216 | ||
217 | /* also fine */ | |
218 | if (ret == 0) | |
219 | for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) { | |
220 | if (strcmp(res, limit_opt[i].name) == 0) | |
221 | return limit_opt[i].value; | |
222 | } | |
223 | ``` | |
224 | ||
ed06b69c | 225 | #### Functions Not Returning Booleans Must Assign Return Value Before Performing Checks |
4a308d66 CB |
226 | |
227 | - When checking whether a function not returning booleans was successful or not | |
228 | the returned value must be assigned before it is checked (`str{n}cmp()` | |
229 | functions being one notable exception). For example: | |
b0c407f7 | 230 | ```C |
4a308d66 CB |
231 | /* assign value to "ret" first */ |
232 | ret = mount(sourcepath, cgpath, "cgroup", remount_flags, NULL); | |
233 | /* check whether function was successful */ | |
234 | if (ret < 0) { | |
235 | SYSERROR("Failed to remount \"%s\" ro", cgpath); | |
236 | free(sourcepath); | |
237 | return -1; | |
238 | } | |
239 | ``` | |
240 | Functions returning booleans can be checked directly. For example: | |
b0c407f7 | 241 | ```C |
4a308d66 CB |
242 | extern bool lxc_string_in_array(const char *needle, const char **haystack); |
243 | ||
244 | /* check right away */ | |
245 | if (lxc_string_in_array("ns", (const char **)h->subsystems)) | |
246 | continue; | |
247 | ``` | |
248 | ||
ed06b69c CB |
249 | #### Non-Boolean Functions That Behave Like Boolean Functions Must Explicitly Check Against A Value |
250 | ||
251 | - This rule mainly exists for `str{n}cmp()` type functions. In most cases they | |
252 | are used like a boolean function to check whether a string matches or not. | |
253 | But they return an integer. It is perfectly fine to check `str{n}cmp()` | |
254 | functions directly but you must compare explicitly against a value. That is | |
255 | to say, while they are conceptually boolean functions they shouldn't be | |
256 | treated as such since they don't really behave like boolean functions. So | |
257 | `if (!str{n}cmp())` and `if (str{n}cmp())` checks must not be used. Good | |
258 | examples are found in the following functions: | |
b0c407f7 | 259 | ```C |
ed06b69c CB |
260 | static int set_config_hooks(const char *key, const char *value, |
261 | struct lxc_conf *lxc_conf, void *data) | |
262 | ||
263 | char *copy; | |
264 | ||
265 | if (lxc_config_value_empty(value)) | |
266 | return lxc_clear_hooks(lxc_conf, key); | |
267 | ||
268 | if (strcmp(key + 4, "hook") == 0) { | |
269 | ERROR("lxc.hook must not have a value"); | |
270 | return -1; | |
271 | } | |
272 | ||
273 | copy = strdup(value); | |
274 | if (!copy) | |
275 | return -1; | |
276 | ||
277 | if (strcmp(key + 9, "pre-start") == 0) | |
278 | return add_hook(lxc_conf, LXCHOOK_PRESTART, copy); | |
279 | else if (strcmp(key + 9, "start-host") == 0) | |
280 | return add_hook(lxc_conf, LXCHOOK_START_HOST, copy); | |
281 | else if (strcmp(key + 9, "pre-mount") == 0) | |
282 | return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy); | |
283 | else if (strcmp(key + 9, "autodev") == 0) | |
284 | return add_hook(lxc_conf, LXCHOOK_AUTODEV, copy); | |
285 | else if (strcmp(key + 9, "mount") == 0) | |
286 | return add_hook(lxc_conf, LXCHOOK_MOUNT, copy); | |
287 | else if (strcmp(key + 9, "start") == 0) | |
288 | return add_hook(lxc_conf, LXCHOOK_START, copy); | |
289 | else if (strcmp(key + 9, "stop") == 0) | |
290 | return add_hook(lxc_conf, LXCHOOK_STOP, copy); | |
291 | else if (strcmp(key + 9, "post-stop") == 0) | |
292 | return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy); | |
293 | else if (strcmp(key + 9, "clone") == 0) | |
294 | return add_hook(lxc_conf, LXCHOOK_CLONE, copy); | |
295 | else if (strcmp(key + 9, "destroy") == 0) | |
296 | return add_hook(lxc_conf, LXCHOOK_DESTROY, copy); | |
297 | ||
298 | free(copy); | |
299 | return -1; | |
300 | } | |
301 | ``` | |
302 | ||
4a308d66 CB |
303 | #### Do Not Use C99 Variable Length Arrays (VLA) |
304 | ||
305 | - They are made optional and there is no guarantee that future C standards | |
306 | will support them. | |
307 | ||
308 | #### Use Standard libc Macros When Exiting | |
309 | ||
310 | - libc provides `EXIT_FAILURE` and `EXIT_SUCCESS`. Use them whenever possible | |
311 | in the child of `fork()`ed process or when exiting from a `main()` function. | |
312 | ||
313 | #### Use `goto`s | |
314 | ||
315 | `goto`s are an essential language construct of C and are perfect to perform | |
316 | cleanup operations or simplify the logic of functions. However, here are the | |
317 | rules to use them: | |
318 | - use descriptive `goto` labels. | |
319 | For example, if you know that this label is only used as an error path you | |
320 | should use something like `on_error` instead of `out` as label name. | |
321 | - **only** jump downwards unless you are handling `EAGAIN` errors and want to | |
322 | avoid `do-while` constructs. | |
323 | - An example of a good usage of `goto` is: | |
b0c407f7 | 324 | ```C |
4a308d66 CB |
325 | static int set_config_idmaps(const char *key, const char *value, |
326 | struct lxc_conf *lxc_conf, void *data) | |
327 | { | |
328 | unsigned long hostid, nsid, range; | |
329 | char type; | |
330 | int ret; | |
331 | struct lxc_list *idmaplist = NULL; | |
332 | struct id_map *idmap = NULL; | |
333 | ||
334 | if (lxc_config_value_empty(value)) | |
335 | return lxc_clear_idmaps(lxc_conf); | |
336 | ||
337 | idmaplist = malloc(sizeof(*idmaplist)); | |
338 | if (!idmaplist) | |
339 | goto on_error; | |
340 | ||
341 | idmap = malloc(sizeof(*idmap)); | |
342 | if (!idmap) | |
343 | goto on_error; | |
344 | memset(idmap, 0, sizeof(*idmap)); | |
345 | ||
346 | ret = parse_idmaps(value, &type, &nsid, &hostid, &range); | |
347 | if (ret < 0) { | |
348 | ERROR("Failed to parse id mappings"); | |
349 | goto on_error; | |
350 | } | |
351 | ||
352 | INFO("Read uid map: type %c nsid %lu hostid %lu range %lu", type, nsid, hostid, range); | |
353 | if (type == 'u') | |
354 | idmap->idtype = ID_TYPE_UID; | |
355 | else if (type == 'g') | |
356 | idmap->idtype = ID_TYPE_GID; | |
357 | else | |
358 | goto on_error; | |
359 | ||
360 | idmap->hostid = hostid; | |
361 | idmap->nsid = nsid; | |
362 | idmap->range = range; | |
363 | idmaplist->elem = idmap; | |
364 | lxc_list_add_tail(&lxc_conf->id_map, idmaplist); | |
365 | ||
366 | if (!lxc_conf->root_nsuid_map && idmap->idtype == ID_TYPE_UID) | |
367 | if (idmap->nsid == 0) | |
368 | lxc_conf->root_nsuid_map = idmap; | |
369 | ||
370 | ||
371 | if (!lxc_conf->root_nsgid_map && idmap->idtype == ID_TYPE_GID) | |
372 | if (idmap->nsid == 0) | |
373 | lxc_conf->root_nsgid_map = idmap; | |
374 | ||
375 | idmap = NULL; | |
376 | ||
377 | return 0; | |
378 | ||
379 | on_error: | |
380 | free(idmaplist); | |
381 | free(idmap); | |
382 | ||
383 | return -1; | |
384 | } | |
385 | ``` | |
386 | ||
387 | #### Use Booleans instead of integers | |
388 | ||
389 | - When something can be conceptualized in a binary way use a boolean not | |
390 | an integer. | |
391 | ||
392 | #### Cleanup Functions Must Handle The Object's Null Type And Being Passed Already Cleaned Up Objects | |
393 | ||
394 | - If you implement a custom cleanup function to e.g. free a complex type | |
395 | you declared you must ensure that the object's null type is handled and | |
396 | treated as a NOOP. For example: | |
b0c407f7 | 397 | ```C |
4a308d66 CB |
398 | void lxc_free_array(void **array, lxc_free_fn element_free_fn) |
399 | { | |
400 | void **p; | |
401 | for (p = array; p && *p; p++) | |
402 | element_free_fn(*p); | |
403 | free((void*)array); | |
404 | } | |
405 | ``` | |
406 | - Cleanup functions should also expect to be passed already cleaned up objects. | |
407 | One way to handle this cleanly is to initialize the cleaned up variable to | |
408 | a special value that signals the function that the element has already been | |
409 | freed on the next call. For example, the following function cleans up file | |
410 | descriptors and sets the already closed file descriptors to `-EBADF`. On the | |
411 | next call it can simply check whether the file descriptor is positive and | |
412 | move on if it isn't: | |
b0c407f7 | 413 | ```C |
4a308d66 CB |
414 | static void lxc_put_attach_clone_payload(struct attach_clone_payload *p) |
415 | { | |
416 | if (p->ipc_socket >= 0) { | |
417 | shutdown(p->ipc_socket, SHUT_RDWR); | |
418 | close(p->ipc_socket); | |
419 | p->ipc_socket = -EBADF; | |
420 | } | |
421 | ||
422 | if (p->pty_fd >= 0) { | |
423 | close(p->pty_fd); | |
424 | p->pty_fd = -EBADF; | |
425 | } | |
426 | ||
427 | if (p->init_ctx) { | |
428 | lxc_proc_put_context_info(p->init_ctx); | |
429 | p->init_ctx = NULL; | |
430 | } | |
431 | } | |
432 | ``` | |
433 | ||
434 | ### Cast to `(void)` When Intentionally Ignoring Return Values | |
435 | ||
436 | - There are cases where you do not care about the return value of a function. | |
437 | Please cast the return value to `(void)` when doing so. | |
438 | - Standard library functions or functions which are known to be ignored by | |
439 | default do not need to be cast to `(void)`. Classical candidates are | |
440 | `close()` and `fclose()`. | |
441 | - A good example is: | |
b0c407f7 | 442 | ```C |
4a308d66 CB |
443 | for (i = 0; hierarchies[i]; i++) { |
444 | char *fullpath; | |
445 | char *path = hierarchies[i]->fullcgpath; | |
446 | ||
447 | ret = chowmod(path, destuid, nsgid, 0755); | |
448 | if (ret < 0) | |
449 | return -1; | |
450 | ||
451 | /* failures to chown() these are inconvenient but not | |
452 | * detrimental we leave these owned by the container launcher, | |
453 | * so that container root can write to the files to attach. we | |
454 | * chmod() them 664 so that container systemd can write to the | |
455 | * files (which systemd in wily insists on doing). | |
456 | */ | |
457 | ||
458 | if (hierarchies[i]->version == cgroup_super_magic) { | |
459 | fullpath = must_make_path(path, "tasks", null); | |
460 | (void)chowmod(fullpath, destuid, nsgid, 0664); | |
461 | free(fullpath); | |
462 | } | |
463 | ||
464 | fullpath = must_make_path(path, "cgroup.procs", null); | |
465 | (void)chowmod(fullpath, destuid, 0, 0664); | |
466 | free(fullpath); | |
467 | ||
468 | if (hierarchies[i]->version != cgroup2_super_magic) | |
469 | continue; | |
470 | ||
471 | fullpath = must_make_path(path, "cgroup.subtree_control", null); | |
472 | (void)chowmod(fullpath, destuid, nsgid, 0664); | |
473 | free(fullpath); | |
474 | ||
475 | fullpath = must_make_path(path, "cgroup.threads", null); | |
476 | (void)chowmod(fullpath, destuid, nsgid, 0664); | |
477 | free(fullpath); | |
478 | } | |
479 | ``` | |
480 | ||
4a308d66 CB |
481 | #### Use `for (;;)` instead of `while (1)` or `while (true)` |
482 | ||
483 | - Let's be honest, it is really the only sensible way to do this. | |
484 | ||
485 | #### Use The Set Of Supported DCO Statements | |
486 | ||
487 | - Signed-off-by: Random J Developer <random@developer.org> | |
488 | - You did write this code or have the right to contribute it to LXC. | |
489 | - Acked-by: Random J Developer <random@developer.org> | |
490 | - You did read the code and think it is correct. This is usually only used by | |
491 | maintainers or developers that have made significant contributions and can | |
492 | vouch for the correctness of someone else's code. | |
493 | - Reviewed-by: Random J Developer <random@developer.org> | |
494 | - You did review the code and vouch for its correctness, i.e. you'd be | |
495 | prepared to fix bugs it might cause. This is usually only used by | |
496 | maintainers or developers that have made significant contributions and can | |
497 | vouch for the correctness of someone else's code. | |
498 | - Co-developed-by: Random J Developer <random@developer.org> | |
499 | - The code can not be reasonably attributed to a single developer, i.e. | |
500 | you worked on this together. | |
501 | - Tested-by: Random J Developer <random@developer.org> | |
502 | - You verified that the code fixes a given bug or is behaving as advertised. | |
503 | - Reported-by: Random J Developer <random@developer.org> | |
504 | - You found and reported the bug. | |
505 | - Suggested-by: Random J Developer <random@developer.org> | |
506 | - You wrote the code but someone contributed the idea. This line is usually | |
507 | overlooked but it is a sign of good etiquette and coding ethics: if someone | |
508 | helped you solve a problem or had a clever idea do not silently claim it by | |
509 | slapping your Signed-off-by underneath. Be honest and add a Suggested-by. | |
510 | ||
511 | #### Commit Message Outline | |
512 | ||
513 | - You **must** stick to the 80chars limit especially in the title of the commit | |
514 | message. | |
515 | - Please use English commit messages only. | |
516 | - use meaningful commit messages. | |
517 | - Use correct spelling and grammar. | |
518 | If you are not a native speaker and/or feel yourself struggling with this it | |
519 | is perfectly fine to point this out and there's no need to apologize. Usually | |
520 | developers will be happy to pull your branch and adopt the commit message. | |
521 | - Please always use the affected file (without the file type suffix) or module | |
522 | as a prefix in the commit message. | |
523 | - Examples of good commit messages are: | |
b0c407f7 | 524 | ```Diff |
4a308d66 CB |
525 | commit b87243830e3b5e95fa31a17cf1bfebe55353bf13 |
526 | Author: Felix Abecassis <fabecassis@nvidia.com> | |
527 | Date: Fri Feb 2 06:19:13 2018 -0800 | |
528 | ||
529 | hooks: change the semantic of NVIDIA_VISIBLE_DEVICES="" | |
530 | ||
531 | With LXC, you can override the value of an environment variable to | |
532 | null, but you can't unset an existing variable. | |
533 | ||
534 | The NVIDIA hook was previously activated when NVIDIA_VISIBLE_DEVICES | |
535 | was set to null. As a result, it was not possible to disable the hook | |
536 | by overriding the environment variable in the configuration. | |
537 | ||
538 | The hook can now be disabled by setting NVIDIA_VISIBLE_DEVICES to | |
539 | null or to the new special value "void". | |
540 | ||
541 | Signed-off-by: Felix Abecassis <fabecassis@nvidia.com> | |
542 | ||
543 | ||
544 | commit d6337a5f9dc7311af168aa3d586fdf239f5a10d3 | |
545 | Author: Christian Brauner <christian.brauner@ubuntu.com> | |
546 | Date: Wed Jan 31 16:25:11 2018 +0100 | |
547 | ||
548 | cgroups: get controllers on the unified hierarchy | |
549 | ||
550 | Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com> | |
551 | ||
552 | ``` | |
4ad78f87 CB |
553 | #### Use `_exit()` To Terminate `fork()`ed Child Processes |
554 | ||
555 | - When `fork()`ing off a child process use `_exit()` to terminate it instead of | |
556 | `exit()`. The `exit()` function is not thread-safe and thus not suited for | |
557 | the shared library which must ensure that it is thread-safe. | |
b629739c CB |
558 | |
559 | #### Keep Arrays of `struct`s Aligned Horizontally When Initializing | |
560 | ||
561 | - Arrays of `struct`s are: | |
b0c407f7 | 562 | ```C |
b629739c CB |
563 | struct foo_struct { |
564 | int n; | |
565 | int m; | |
566 | int p; | |
567 | }; | |
568 | ||
569 | struct foo_struct new_instance[] = { | |
570 | { 1, 2, 3 }, | |
571 | { 4, 5, 6 }, | |
572 | { 7, 8, 9 }, | |
573 | }; | |
574 | ``` | |
575 | - Leave a single space after the opening `{` and before closing `}` of the | |
576 | largest member of the last column. | |
577 | - Always leave a single space between the largest member of the current column | |
578 | and the member in the next column. | |
579 | - A good example is | |
b0c407f7 | 580 | ```C |
b629739c CB |
581 | struct signame { |
582 | int num; | |
583 | const char *name; | |
584 | }; | |
585 | ||
586 | static const struct signame signames[] = { | |
587 | { SIGHUP, "HUP" }, | |
588 | { SIGINT, "INT" }, | |
589 | { SIGQUIT, "QUIT" }, | |
590 | { SIGILL, "ILL" }, | |
591 | { SIGABRT, "ABRT" }, | |
592 | { SIGFPE, "FPE" }, | |
593 | { SIGKILL, "KILL" }, | |
594 | { SIGSEGV, "SEGV" }, | |
595 | { SIGPIPE, "PIPE" }, | |
596 | { SIGALRM, "ALRM" }, | |
597 | { SIGTERM, "TERM" }, | |
598 | { SIGUSR1, "USR1" }, | |
599 | { SIGUSR2, "USR2" }, | |
600 | { SIGCHLD, "CHLD" }, | |
601 | { SIGCONT, "CONT" }, | |
602 | { SIGSTOP, "STOP" }, | |
603 | { SIGTSTP, "TSTP" }, | |
604 | { SIGTTIN, "TTIN" }, | |
605 | { SIGTTOU, "TTOU" }, | |
606 | #ifdef SIGTRAP | |
607 | { SIGTRAP, "TRAP" }, | |
608 | #endif | |
609 | #ifdef SIGIOT | |
610 | { SIGIOT, "IOT" }, | |
611 | #endif | |
612 | #ifdef SIGEMT | |
613 | { SIGEMT, "EMT" }, | |
614 | #endif | |
615 | #ifdef SIGBUS | |
616 | { SIGBUS, "BUS" }, | |
617 | #endif | |
618 | #ifdef SIGSTKFLT | |
619 | { SIGSTKFLT, "STKFLT" }, | |
620 | #endif | |
621 | #ifdef SIGCLD | |
622 | { SIGCLD, "CLD" }, | |
623 | #endif | |
624 | #ifdef SIGURG | |
625 | { SIGURG, "URG" }, | |
626 | #endif | |
627 | #ifdef SIGXCPU | |
628 | { SIGXCPU, "XCPU" }, | |
629 | #endif | |
630 | #ifdef SIGXFSZ | |
631 | { SIGXFSZ, "XFSZ" }, | |
632 | #endif | |
633 | #ifdef SIGVTALRM | |
634 | { SIGVTALRM, "VTALRM" }, | |
635 | #endif | |
636 | #ifdef SIGPROF | |
637 | { SIGPROF, "PROF" }, | |
638 | #endif | |
639 | #ifdef SIGWINCH | |
640 | { SIGWINCH, "WINCH" }, | |
641 | #endif | |
642 | #ifdef SIGIO | |
643 | { SIGIO, "IO" }, | |
644 | #endif | |
645 | #ifdef SIGPOLL | |
646 | { SIGPOLL, "POLL" }, | |
647 | #endif | |
648 | #ifdef SIGINFO | |
649 | { SIGINFO, "INFO" }, | |
650 | #endif | |
651 | #ifdef SIGLOST | |
652 | { SIGLOST, "LOST" }, | |
653 | #endif | |
654 | #ifdef SIGPWR | |
655 | { SIGPWR, "PWR" }, | |
656 | #endif | |
657 | #ifdef SIGUNUSED | |
658 | { SIGUNUSED, "UNUSED" }, | |
659 | #endif | |
660 | #ifdef SIGSYS | |
661 | { SIGSYS, "SYS" }, | |
662 | #endif | |
663 | }; | |
664 | ``` | |
80aa6de0 CB |
665 | |
666 | #### Use `strlcpy()` instead of `strncpy()` | |
667 | ||
668 | When copying strings always use `strlcpy()` instead of `strncpy()`. The | |
669 | advantage of `strlcpy()` is that it will always append a `\0` byte to the | |
670 | string. | |
671 | ||
672 | Unless you have a valid reason to accept truncation you must check whether | |
673 | truncation has occurred, treat it as an error, and handle the error | |
674 | appropriately. | |
7fee7804 CB |
675 | |
676 | #### Use `strlcat()` instead of `strncat()` | |
677 | ||
678 | When concatenating strings always use `strlcat()` instead of `strncat()`. The | |
679 | advantage of `strlcat()` is that it will always append a `\0` byte to the | |
680 | string. | |
681 | ||
682 | Unless you have a valid reason to accept truncation you must check whether | |
683 | truncation has occurred, treat it as an error, and handle the error | |
684 | appropriately. |