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