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