#s;
375 |
376 | # Synopsis blocks are processed line-by-line, then merged by the global output postprocessing function.
377 | # This may cause spaces to be inserted at unexpected places. Remove them:
378 | s/ *${replacement_token}#BRK# */\n/gs;
379 |
380 | $_
381 | }
382 |
383 | sub reformat_syntax {
384 | # commands to be ignored:
385 | if (m/^\.(?:PD|hy|ad|ft|fi|\s|$)/) {
386 | $_ = '';
387 | return
388 | }
389 |
390 | # replace .ds strings:
391 | for my $sname (keys %strings) {
392 | if (length $sname == 1) { s/\\\*$sname/$strings{$sname}/g; }
393 | elsif (length $sname == 2) { s/\\\*\($sname/$strings{$sname}/g; }
394 | }
395 |
396 | # raw block markers:
397 | if (m/^\.(?:nf|co|cm)/) {
398 | if (has_lineopt('PLAIN')) {
399 | $in_preblock = 2;
400 | } else {
401 | $in_rawblock = 2;
402 | }
403 | if (m/^\.cm(?:\s+($re_token))?/) {
404 | chomp;
405 | $_ = qtok($1);
406 | strip_highlighting();
407 | $_ = "\n**\`$_\`**\n\n"
408 | } elsif (m/^\.co/) {
409 | $_ = "\n"
410 | } else {
411 | $_ = ''
412 | }
413 | return
414 | }
415 |
416 | # command invocation in Synopsis section:
417 | if ($is_synopsis && !line_empty()) {
418 | # only code here
419 | chomp;
420 | if ($code_formatting) {
421 | # synopsis content with formatting
422 | $_ = strip_html($_);
423 | reformat_html();
424 | strip_highlighting();
425 | s/\\(.)/$1/g; # in md
blocks, backslashes are not special!
426 | $_ = "\n$_\n\n"
427 | } else {
428 | strip_highlighting();
429 | $_ = "\n$_\n\n";
430 | }
431 | return
432 | }
433 |
434 | # Usually we can get away with unescaped underscores.
435 | # But they'll lead to problems inside words that use \fI font changes.
436 | # So escape just these occurrences:
437 | s/(?=\S*\\f[IRP12]\S*)_/\\_/g;
438 |
439 | # bold and italics:
440 | # (The special cases * and * are handled after the strip_html() call.)
441 | s/(?:\\f[B3])+([^\*_]|.{2,}?)(?:\\f[RP1])+/**$1**/g;
442 | s/(?:\\f[I2])+([^\*_]|.{2,}?)(?:\\f[RP1])+/_$1_/g;
443 | s/(?:\\f4)+([^\*_]|.{2,}?)(?:\\f[RP1])+/**_$1_**/g;
444 |
445 | # groff concatenates tokens in .B and .I lines with spaces.
446 | # We still have to tokenize and re-join the line
447 | # to get rid of the token doublequote enclosures.
448 | s/^\.B +([^\*].*)/'**' . join(' ', tokenize($1)) . '**'/ge;
449 | s/^\.I +([^\*].*)/'_' . join(' ', tokenize($1)) . '_'/ge;
450 |
451 | s/^\.([BIR])([BIR]) *(.+)/alternating_highlighting($1, $2, $3)/ge;
452 |
453 | # other formatting:
454 | strip_highlighting(1);
455 |
456 | # escape html tags:
457 | $_ = strip_html($_);
458 |
459 | # process highlighting special cases:
460 | s#(?:\\f[B3])+(\*|_)(?:\\f[RP1])+#\\$1#g;
461 | s#(?:\\f[I2])+(\*|_)(?:\\f[RP1])+#\\$1#g;
462 | s#(?:\\f4)+(\*|_)(?:\\f[RP1])+#\\$1#g;
463 | s#^\.B +(\*.*)#'' . join(' ', tokenize($1)) . ''#ge;
464 | s#^\.I +(\*.*)#'' . join(' ', tokenize($1)) . ''#ge;
465 |
466 | # remove remaining highlighting:
467 | s/(?:^\.[BIR]{1,2} |\\f[BIRP1234])//g;
468 |
469 | if ($section eq 'AUTHOR' || $section eq 'AUTHORS') {
470 | # convert e-mail address to link:
471 | s/\b($re_email)\b/[$1](mailto:$1)/u;
472 | }
473 |
474 | # item lists and description lists:
475 | if (m/^\.IP(?: +($re_token))?/ || m/^\.TP/) {
476 | my $tok = defined($1) ? qtok($1) : undef;
477 | my $is_bullet = (!defined($tok) || $tok eq '' || $tok eq '-' || $tok eq 'o');
478 | $is_desclist = !$is_bullet || (m/^\.TP/ && ($section ne 'EXIT CODES' && $section ne 'EXIT STATUS'));
479 | my $indent = ($in_list > 1)
480 | ? ' ' x ($in_list - 1)
481 | : '';
482 | $_ = $indent . '* '; # no trailing break here
483 | if ($is_bullet) {
484 | $start_list_item = 1;
485 | } else {
486 | $_ .= $tok . " \n";
487 | }
488 | if (!$in_list) {
489 | $_ = "\n$_";
490 | $in_list = 1;
491 | }
492 | } elsif ($in_list && m/^\.RS/) {
493 | $in_list++;
494 | $_ = ''
495 | } elsif ($in_list && m/^\.RE/) {
496 | $in_list--;
497 | $_ = ''
498 | } elsif (m/^\.(?:RS|RE)/) {
499 | # ignore
500 | $_ = ''
501 | } elsif ($in_list) {
502 | if ($start_list_item) {
503 | $start_list_item = 0;
504 |
505 | # In description list (probably some CLI options).
506 | # Add extra line break after option name:
507 | s/$/ / if $is_desclist;
508 | } else {
509 | my $indent = ' ' x (2 + (4 * ($in_list - 1)));
510 | s/^/$indent/;
511 | }
512 | } elsif (m/\.UR ($re_url)\s*$/) {
513 | $in_urltitle = $1;
514 | $_ = '['
515 | } elsif (m/\.MT ($re_email)\s*$/) {
516 | $in_mailtitle = $1;
517 | $_ = '['
518 | } elsif (defined $in_urltitle && m/\.UE(?: (\S*)\s*)?$/) {
519 | $_ = "]($in_urltitle)" . ($1 // '') . "\n";
520 | undef $in_urltitle
521 | } elsif (defined $in_mailtitle && m/\.ME(?: (\S*)\s*)?$/) {
522 | $_ = "](mailto:$in_mailtitle)" . ($1 // '') . "\n";
523 | undef $in_mailtitle
524 | } elsif (defined $in_urltitle || defined $in_mailtitle) {
525 | s/[\r\n]+/ /g
526 | }
527 |
528 | s/$/ / if has_lineopt('BRK');
529 | clr_lineopt() unless $line_did_set_options;
530 | }
531 |
532 | sub reformat_html {
533 | s#\\f[B3](.+?)\\f[RP1]#$1#g;
534 | s#\\f[I2](.+?)\\f[RP1]#$1#g;
535 | s#\\f4(.+?)\\f[RP1]#$1#g;
536 | s#^\.B +(.+)#$1#g;
537 | s#^\.I +(.+)#$1#g;
538 | s/^\.([BIR])([BIR]) *(.+)/alternating_highlighting($1, $2, $3, 1)/ge;
539 | }
540 |
541 | # Strips doublequote enclosure from string tokens, if present.
542 | sub qtok {
543 | my @result = map{ defined && m/^"(.+)"$/ ? $1 : $_ } @_;
544 | wantarray ? @result : $result[0]
545 | }
546 |
547 | # Extracts all tokens from the input string and returns them in a list.
548 | # Tokens are things enclosed in unescaped doublequotes or any strings without spaces.
549 | sub tokenize { qtok($_[0] =~ m/$re_token/g) }
550 |
551 |
552 | sub section_slug ($) {
553 | local $_ = lc shift;
554 | s/[^\w\d\-_ ]//g;
555 | s/[ \-]+/-/g;
556 | $_
557 | }
558 |
559 | sub section_anchor ($) { "" }
560 |
561 | sub print_section_title ($) {
562 | my $title = strip_html($_[0]);
563 | my $output = sprintf "\n%s\n\n%s%s\n\n", section_anchor($title), $section_prefix, $title;
564 | utf8::encode($output);
565 | print $output
566 | }
567 |
568 | sub print_subsection_title ($) {
569 | my $title = strip_html($_[0]);
570 | my $output = sprintf "\n%s\n\n%s%s\n\n", section_anchor($title), $subsection_prefix, $title;
571 | utf8::encode($output);
572 | print $output
573 | }
574 |
575 | sub paste_file (%) {
576 | my %args = @_;
577 | return 0 unless -r $args{'file'};
578 |
579 | if ($args{'add_section_title'} && $args{'file'} =~ m/^(?:[a-zA-Z0-9_\-]+\/)*(.+)\.md$/) {
580 | my $section_title = $1;
581 | print_section_title $section_title;
582 | }
583 |
584 | open FH, "< $args{'file'}";
585 | local $/;
586 | my $content = ;
587 | close FH;
588 |
589 | # $content =~ s/\s+$//;
590 | print "$content\n";
591 |
592 | 1
593 | }
594 |
595 | sub alternating_highlighting {
596 | my @hl = @_[0, 1];
597 | my @tokens = tokenize($_[2]);
598 | my $do_html = $_[3] // 0;
599 | my $h = 0;
600 |
601 | # groff concatenates tokens in .B and .I lines with spaces,
602 | # but tokens in .[BIR][BIR] lines are concatenated WITHOUT spaces.
603 | # Therefore we have to join('') the tokens here:
604 |
605 | return join '', map {
606 | my $highlightkey = $hl[$h++ % 2];
607 |
608 | if ($highlightkey eq 'R') {
609 | $_
610 | } elsif ($highlightkey eq 'I') {
611 | ($do_html)
612 | ? '' . $_ . ''
613 | : '_' . $_ . '_'
614 | } elsif ($highlightkey eq 'B') {
615 | ($do_html)
616 | ? '' . $_ . ''
617 | : '**' . $_ . '**'
618 | }
619 | } @tokens
620 | }
621 |
622 | sub titlecase {
623 | local $_ = $_[0];
624 | my $re_word = '(\pL[\pL\d\'_]*)';
625 |
626 | # lowercase stop words, keep casing of known words, else titlecase
627 | s!$re_word!$stopwords{lc $1} ? lc($1) : ($words{lc $1} // ucfirst(lc($1)))!ge;
628 | # capitalize first word following colon or semicolon
629 | s/ ( [:;] \s+ ) $re_word /$1\u$2/x;
630 | # titlecase first word (even a stopword), except if it's a known word
631 | s!^\s*$re_word!$words{lc $1} // ucfirst(lc($1))!e;
632 |
633 | $_
634 | }
635 |
636 | sub read_version {
637 | if ($_[0] eq '') {
638 | # no version string found
639 | $version = '';
640 | return 1
641 | }
642 |
643 | if ($_[0] =~ m/^(?:$progname(?: \(\d\))?\s+)(?:v|ver\.?|version)? ?(\d[\w\.\-\+]*)$/i) {
644 | # found explicit version following known progname
645 | $is_bare_version = 1;
646 | $version = $1;
647 | return 1
648 | }
649 |
650 | # found something else
651 | $version = $_[0];
652 | return 1
653 | }
654 |
655 | ##############################
656 |
657 | # eat first line, extract progname, version, and man section
658 | nextline() or die "could not read first line";
659 | m/^.(?:Dd|Dt)\b/ and die "man page is in mdoc format which is not supported";
660 | m/^\.TH\b/ or die "first line does not contain '.TH' macro";
661 | m/^\.TH ($re_token)(?:\s|$)/ or die ".TH line doesn't contain page title";
662 | m/^\.TH ($re_token) ($re_token)(?: ($re_token)(?: ($re_token))?)?/ or die ".TH line doesn't contain man section";
663 |
664 | ($progname, $mansection, $verdate) = (lc(qtok($1)), qtok($2), qtok($3));
665 | read_version(qtok($4 // ''));
666 |
667 | # skip NAME headline, extract description
668 | if (nextline() && section_title() && $section eq 'NAME') {
669 | if (nextline() && m/ \\?(?:-|\\\(em|\\\(en) +(.+)$/) {
670 | $description = $1;
671 | nextline();
672 | }
673 | }
674 |
675 | print "[//]: # ($add_comment)\n\n" if defined $add_comment;
676 | printf "%s%s(%s)", $headline_prefix, strip_html($progname), $mansection;
677 | printf " - %s", strip_html($description) if defined $description;
678 | print "\n\n";
679 |
680 | # Fake section name 'HEADLINE' can be used
681 | # to paste additional content right after the headline
682 | # (but not before)
683 | if (defined $paste_after_section{'HEADLINE'}) {
684 | paste_file(%$_) foreach (@{ $paste_after_section{'HEADLINE'} });
685 | undef $paste_after_section{'HEADLINE'};
686 | }
687 |
688 | if ($version || $verdate) {
689 | if ($version) {
690 | print "Version " if $is_bare_version;
691 | print $version;
692 | }
693 | if ($version && $verdate) {
694 | print ", ";
695 | }
696 | if ($verdate) {
697 | print $verdate;
698 | }
699 | print "\n\n";
700 | }
701 |
702 | # skip SYNOPSIS headline
703 | nextline() if (section_title && $is_synopsis);
704 |
705 |
706 | do {{
707 | PARSELINE:
708 |
709 | if ($in_rawblock) {
710 | if (m/^\.(?:fi|SH|cx)/) {
711 | # code block ends
712 | $in_rawblock = 0;
713 | print "
\n" if $code_formatting;
714 | print "\n" if m/^\.cx/;
715 | redo if m/^\.SH/; # .nf sections can be ended with .SH, but we still need to print the new section title too
716 | } elsif ($code_formatting) {
717 | # inside code block with limited html formatting
718 | if ($in_rawblock == 2) {
719 | $in_rawblock = 1;
720 | print "
blocks, backslashes are not special!
726 | print
727 | } else {
728 | # inside code block without formatting
729 | strip_highlighting;
730 | s/\\(.)/$1/g; # in md raw blocks, backslashes are not special!
731 | print " $_"
732 | }
733 |
734 | } elsif ($in_preblock) {
735 | if (m/^\.fi/) {
736 | # preformatted block ends
737 | $in_preblock = 0;
738 | $_ = '';
739 | } else {
740 | # Add two spaces at EOL to force visible linebreak:
741 | add_lineopt('BRK');
742 | }
743 | reformat_syntax;
744 | print
745 |
746 | } elsif (section_title) {
747 | # new section begins
748 | if (defined $paste_after_section{$prev_section}) {
749 | paste_file(%$_) foreach (@{ $paste_after_section{$prev_section} });
750 | undef $paste_after_section{$prev_section};
751 | }
752 | if (defined $paste_before_section{$section}) {
753 | paste_file(%$_) foreach (@{ $paste_before_section{$section} });
754 | undef $paste_before_section{$section};
755 | }
756 | print_section_title titlecase($section)
757 |
758 | } elsif (subsection_title) {
759 | # new subsection begins
760 | print_subsection_title $subsection
761 |
762 | } elsif (m/^\.ds +(\S{1,2}) +"?(.+)$/) {
763 | $strings{ $1 } = $2
764 |
765 | } elsif (m/^\.de\b/) {
766 | # macro definition -- skip completely
767 | 1 while (nextline(1) && ! m/^\.\./);
768 |
769 | } else {
770 | reformat_syntax;
771 | print
772 | }
773 |
774 | }} while (nextline(1));
775 |
776 |
777 | # Paste section which haven't matched anything yet:
778 | # TODO: print warnings -- they probably should have gone somewhere else
779 | foreach (values %paste_before_section)
780 | { paste_file(%$_) foreach (@$_) }
781 | foreach (values %paste_after_section)
782 | { paste_file(%$_) foreach (@$_) }
783 |
784 |
--------------------------------------------------------------------------------
/src/cjit/docs/faq.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions about CJIT
2 |
3 | Here we try to answer the most asked questions.
4 |
5 | ## What's different between `tcc -run` and CJIT?
6 |
7 | The main difference is in usability.
8 |
9 | CJIT improves three main UX aspects for now:
10 |
11 | 1. It works as a single executable file which embeds the TinyCC
12 | compiler, all its headers and its standard library. This way there
13 | is no need to install anything system wide, check paths and setup
14 | build folders.
15 |
16 | 2. It supports adding multiple files into one execution: can accept
17 | wildcards to ingest anything that is a C source, a pre-compiled
18 | object or a shared library. The symbols exported by each file will
19 | be visible to all during the same execution.
20 |
21 | 3. It finds automatically common system libraries for each target
22 | platform, avoiding the need to repeat these settings and look for
23 | the right paths.
24 |
25 | We are happy to further the improve developer experience with CJIT,
26 | and your advice is welcome: [open an issue](https://github.com/dyne/cjit/issues)!
27 |
28 | ## What's different between `libgccjit` and CJIT?
29 |
30 | CJIT is built as an command-line interpreter using the TinyCC backend
31 | for in-memory compilation. In the future it may also offer `libgccjit`
32 | as backend, as long as it will be possible to embed it all inside a
33 | single executable file, which is a core feature of CJIT's vision for
34 | developer experience.
35 |
36 | ## Which parts of CJIT are licensed, under what?
37 |
38 | Detailed licensing information for CJIT is in the [REUSE metadata
39 | file](https://github.com/dyne/cjit/blob/main/REUSE.toml). We check
40 | correctness of these attributions at every single commit.
41 |
42 | All CJIT's original code is licensed using GNU GPL v3 and will be
43 | updated to use future versions of this license published by the Free
44 | Software Foundation. All included licenses are compatible with this.
45 |
46 | We grant to everyone the freedome to use, study, modify, and
47 | redistribute modifications of CJIT as long as such modifications are
48 | licensed with one of the licenses already present: MIT, GPL or LGPL.
49 |
50 | More information about CJIT's licensing is also found in its [manpage section on LICENSING](https://dyne.org/docs/cjit/manpage/#licensing).
51 |
52 | ## Where to I send my corrections to this documentation?
53 |
54 | You are welcome to [open an issue or a PR to the dyne/docs project](https://github.com/dyne/docs).
55 |
56 | The source of the CJIT manual is in the markdown formatted files in `src/cjit/docs` inside the repository.
57 |
58 | ## I have a new question, whom can I ask?
59 |
60 | You are welcome to interact in public with Dyne.org hackers over any
61 | of [our channels and social network acconts](https://dyne.org/contact).
62 |
63 | If you prefer to interact privately, write a mail to
64 | [info@dyne.org](mailto:info@dyne.org).
65 |
--------------------------------------------------------------------------------
/src/cjit/docs/filesystem.md:
--------------------------------------------------------------------------------
1 |
2 | # Filesystem operations
3 |
4 | The [dmon](https://github.com/septag/dmon/) header is designed for
5 | monitoring changes in the filesystem: simplifies the process of
6 | tracking file modifications, deletions, and creations, allowing you to
7 | respond to these events in real time within your C scripts.
8 |
9 | Here is
10 | [examples/dmon.c](https://github.com/dyne/cjit/blob/main/examples/dmon.c)
11 | wich is tested to run on all CJIT platforms:
12 |
13 | ```c
14 | #include
15 | #include
16 |
17 | static void watch_callback(dmon_watch_id watch_id,
18 | dmon_action action,
19 | const char* rootdir,
20 | const char* filepath,
21 | const char* oldfilepath,
22 | void* user) {
23 | (void)(user);
24 | (void)(watch_id);
25 | switch (action) {
26 | case DMON_ACTION_CREATE:
27 | fprintf(stderr,"CREATE: [%s]%s\n", rootdir, filepath);
28 | break;
29 | case DMON_ACTION_DELETE:
30 | fprintf(stderr,"DELETE: [%s]%s\n", rootdir, filepath);
31 | break;
32 | case DMON_ACTION_MODIFY:
33 | fprintf(stderr,"MODIFY: [%s]%s\n", rootdir, filepath);
34 | break;
35 | case DMON_ACTION_MOVE:
36 | fprintf(stderr,"MOVE: [%s]%s -> [%s]%s\n",
37 | rootdir, oldfilepath, rootdir, filepath);
38 | break;
39 | }
40 | }
41 |
42 | int main(int argc, char* argv[]) {
43 | if (argc > 1) {
44 | dmon_init();
45 | puts("waiting for changes ..");
46 | dmon_watch(argv[1], watch_callback,
47 | DMON_WATCHFLAGS_RECURSIVE, NULL);
48 | getchar();
49 | dmon_deinit();
50 | } else {
51 | puts("usage: test dirname");
52 | }
53 | return 0;
54 | }
55 | ```
56 |
57 | # ⏩ [Next: Terminal User Interface](tui.md)
58 |
59 | Go to the next chapter of this tutorial.
60 |
--------------------------------------------------------------------------------
/src/cjit/docs/graphics.md:
--------------------------------------------------------------------------------
1 |
2 | # CJIT for graphical applications
3 |
4 | Be welcome to the exciting world of graphical C applications using SDL
5 | ([Simple DirectMedia Layer](https://sdl.org)). SDL, originally
6 | developed by Sam Lantinga in 1998, is a powerful, cross-platform
7 | library designed to provide low-level access to audio, keyboard,
8 | mouse, and graphics hardware via OpenGL and Direct3D.
9 |
10 | !!! warn
11 | This part of the tutorial may be incomplete for Apple/OSX, please help testing and refining it!
12 |
13 | ## Download the cjit-demo package
14 |
15 | From now on this tutorial will guide you to launch more complex
16 | applications, showing how to use libraries that are installed on your
17 | system and shipped along with the source code.
18 |
19 | To setup the demo environment you can simply run the command below:
20 |
21 | === "MS/Windows"
22 |
23 | ```
24 | iex ((New-Object System.Net.WebClient).DownloadString('https://dyne.org/cjit/demo'))
25 | ```
26 |
27 | === "Apple/OSX"
28 |
29 | ```
30 | curl -sL https://dyne.org/cjit/demo.sh | bash
31 | ```
32 |
33 | === "GNU/Linux"
34 |
35 | ```
36 | curl -sL https://dyne.org/cjit/demo.sh | bash
37 | ```
38 |
39 |
40 | ## The Beauty of Random
41 |
42 | Execute [sdl2_noise.c](https://github.com/dyne/cjit/blob/main/examples/sdl2_noise.c) passing the source file as argument to CJIT, and since we are also using the SDL2 library we also need an extra parameter:
43 |
44 | === "MS/Windows"
45 |
46 | ```
47 | .\cjit.exe examples/sdl2_noise.c SDL2.dll
48 | ```
49 |
50 | === "Apple/OSX"
51 |
52 | ```
53 | ./cjit examples/sdl2_noise.c -lSDL2
54 | ```
55 |
56 | === "GNU/Linux"
57 |
58 | ```
59 | ./cjit examples/sdl2_noise.c -lSDL2
60 | ```
61 |
62 |
63 | 
64 |
65 | !!! info
66 | This preview looks blurred because video compression cannot deal well with randomness.
67 |
68 | Have a look inside [sdl2_noise.c](https://github.com/dyne/cjit/blob/main/examples/sdl2_noise.c), and see the first line of code:
69 |
70 | ### The "hashbang"
71 | ```sh
72 | #!/usr/bin/env cjit
73 | ```
74 |
75 | The source file can be launched as a script, when the CJIT interpreter is found in PATH.
76 |
77 | !!! warning
78 | The hashbang works only on Apple/OSX and GNU/Linux, where scripts can be made executable with `chmod +x`
79 |
80 | ### The pragma lib
81 |
82 | Also see this pre-processor directive:
83 | ```c
84 | #pragma comment(lib, "SDL2")
85 | ```
86 |
87 | This line tells CJIT to link the `SDL2` shared library. It is the equivaled of `SDL2.dll` on the commandline, with the only difference that it can be specified inside the source code.
88 |
89 | !!! info
90 | On Windows the DLL files need to be in the same directory of execution, or installed system-wide.
91 |
92 | ## Three Dimensions
93 |
94 | To draw accelerated graphics and 3D objects we'll use OpenGL libraries, which need to be installed on the system.
95 |
96 | === "MS/Windows"
97 | [Install the Windows SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/) which is distributed gratis by Microsoft.
98 |
99 | === "Apple/OSX"
100 | Not sure (help testing this please!)
101 |
102 | === "GNU/Linux"
103 | ```
104 | sudo apt-get install libopengl-dev
105 | ```
106 |
107 | Then run CJIT passing the file [examples/opengl.c]((https://github.com/dyne/cjit/blob/main/examples/opengl.c) as argument, along with the same parameter to link SDL2.
108 |
109 | 
110 |
111 | For more details on using OpenGL and SDL2 in C with shaders, read the
112 | [multi-platform-modern-opengl-demo-with-sdl2
113 | tutorial](https://shallowbrooksoftware.com/posts/a-multi-platform-modern-opengl-demo-with-sdl2/)
114 | on which our example code is based.
115 |
116 | ## Nuklear widgets
117 |
118 | Nuklear is a minimal, immediate-mode graphical user interface toolkit
119 | written in ANSI C and licensed under public domain. It is designed to
120 | be lightweight and highly customizable, and provides a wide range of
121 | components, including buttons, sliders, text input fields, and more,
122 | all of which can be integrated seamlessly with CJIT.
123 |
124 | This time the code of our example is distributed across multiple files, this is a quick overview of what is found inside the `example` folder:
125 | ```
126 | .
127 | ├── nuklear
128 | │ ├── calculator.c
129 | │ ├── canvas.c
130 | │ ├── node_editor.c
131 | │ ├── overview.c
132 | │ └── style.c
133 | ├── nuklear.c
134 | └── nuklear.h
135 | ```
136 |
137 | The main code of our example
138 | is
139 | [examples/nuklear.c](https://github.com/dyne/cjit/blob/main/examples/nuklear.c) and by default it will just start all modules.
140 |
141 | Fire it up as usual with `./cjit.exe examples/nuklear.c` or equivalent commands on GNU/Linux and Apple/OSX.
142 |
143 | And 💥Boom! enjoy Nuklear!
144 |
145 | 
146 |
147 | # ⏩ [Next: sound with CJIT](sound.md)
148 |
149 | Go to the next chapter of this tutorial.
150 |
--------------------------------------------------------------------------------
/src/cjit/docs/images/cjit_donut_race.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/cjit_donut_race.gif
--------------------------------------------------------------------------------
/src/cjit/docs/images/cjit_life_c.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/cjit_life_c.gif
--------------------------------------------------------------------------------
/src/cjit/docs/images/cjit_nuklear.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/cjit_nuklear.gif
--------------------------------------------------------------------------------
/src/cjit/docs/images/cjit_opengl.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/cjit_opengl.gif
--------------------------------------------------------------------------------
/src/cjit/docs/images/cjit_sdl2_noise.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/cjit_sdl2_noise.gif
--------------------------------------------------------------------------------
/src/cjit/docs/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/cjit/docs/images/favicon.png
--------------------------------------------------------------------------------
/src/cjit/docs/index.md:
--------------------------------------------------------------------------------
1 |
2 | # Welcome to the CJIT Tutorial
3 |
4 | CJIT is a versatile C interpreter based on TinyCC, designed to compile
5 | C code in-memory and execute it live. This manual serves as a guide to
6 | the full potential of CJIT, empowering you to efficiently develop and
7 | test C programs in real-time.
8 |
9 | This tutorial will guide you through practical usage examples, helping
10 | you to swiftly integrate CJIT into your workflow. 📚🔧
11 |
12 | ## Download CJIT
13 |
14 | If you have already downloaded the CJIT executable for your running
15 | system them you can skip this section.
16 |
17 | If you like to download it by hand, go to the [CJIT release page](https://github.com/dyne/cjit/releases).
18 |
19 | If you prefer to cut & paste a terminal script, pick one below for your running system:
20 |
21 | === "MS/Windows"
22 |
23 | ```
24 | Invoke-WebRequest -OutFile "cjit.exe" -Uri "https://github.com/dyne/cjit/releases/latest/download/cjit.exe"
25 | ```
26 |
27 | === "Apple/OSX"
28 |
29 | ```
30 | curl -sLo cjit https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname)-$(uname -m)
31 | chmod +x cjit
32 | ```
33 |
34 | === "GNU/Linux"
35 |
36 | ```
37 | source /etc/os-release
38 | curl -sLo cjit "https://github.com/dyne/cjit/releases/latest/download/cjit-$(uname -m)-${NAME,,}-${VERSION_ID}"
39 | chmod +x cjit
40 | ```
41 |
42 |
43 | !!! info
44 | All Windows examples are made for PowerShell, on WSL then pick GNU/Linux.
45 |
46 | ## Hello World!
47 |
48 | This classic example will make you create a `hello.c` file and execute
49 | it with CJIT to print the string "Hello World!" in the terminal.
50 |
51 | Create hello.c by pasting these lines in the terminal:
52 |
53 | === "MS/Windows"
54 |
55 | ```c
56 | @"
57 | #include
58 | #include
59 | int main(int argc, char **argv) {
60 | fprintf(stderr,"Hello, World!\n");
61 | exit(0);
62 | }
63 | "@| Out-File -FilePath "hello.c" -Encoding ASCII
64 | ```
65 |
66 | === "Apple/OSX"
67 |
68 | ```bash
69 | cat << EOF > hello.c
70 | #!/usr/bin/env cjit
71 | #include
72 | #include
73 | int main(int argc, char **argv) {
74 | fprintf(stderr,"Hello, World!\n");
75 | exit(0);
76 | }
77 | EOF
78 | ```
79 |
80 | === "GNU/Linux"
81 |
82 | ```bash
83 | cat << EOF > hello.c
84 | #!/usr/bin/env cjit
85 | #include
86 | #include
87 | int main(int argc, char **argv) {
88 | fprintf(stderr,"Hello, World!\n");
89 | exit(0);
90 | }
91 | EOF
92 | ```
93 |
94 | Finally execute hello.c with CJIT:
95 |
96 | === "MS/Windows"
97 | ```
98 | .\cjit.exe .\hello.c
99 | ```
100 | === "Apple/OSX"
101 | ```
102 | ./cjit hello.c
103 | ```
104 | === "GNU/Linux"
105 | ```
106 | ./cjit hello.c
107 | ```
108 |
109 |
110 | As a result you will see CJIT starting and printing "Hello World!"
111 |
112 | ```
113 | CJIT v0.16.2 by Dyne.org
114 | Hello World!
115 | ```
116 |
117 | You can play with `hello.c`, change what you want and run it again!
118 |
119 | ## Flying Donuts
120 |
121 | This example will print an animated donut on the terminal!
122 |
123 | Create the `donut.c` file using the artful code below:
124 |
125 | === "MS/Windows"
126 |
127 | ```c
128 | @"
129 | i,j,k,x,y,o,N;
130 | main(){float z[1760],a
131 | #define R(t,x,y) f=x;x-=t*y\
132 | ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;
133 | =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char
134 | b[1760];for(;;){memset(b,32,1760);g=0,
135 | h=1;memset(z,0,7040);for(j=0;j<90;j++){
136 | G=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*
137 | A*a+g*e+5);t=G*A *e-g*a;x=40+30*D
138 | *(H*A*d-t*c);y= 12+15*D*(H*A*c+
139 | t*d);o=x+80*y;N =8*((g*a-G*h*e)
140 | *d-G*h*a-g*e-H*h *c);if(22>y&&y>
141 | 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0
142 | ?N:0)[".,-~:;=!*#$@"];}R(.02,H,G);}R(
143 | .07,h,g);}for(k=0;1761>k;k++)putchar
144 | (k%80?b[k]:10);R(.04,e,a);R(.02,d,
145 | c);usleep(15000);printf('\n'+(
146 | " donut.c! \x1b[23A"));}}
147 | /*no math lib needed
148 | .@a1k0n 2021.*/
149 | "@| Out-File -FilePath "donut.c" -Encoding ASCII
150 | ```
151 |
152 | === "Apple/OSX"
153 |
154 |
155 | ```c
156 | cat << EOF > donut.c
157 | i,j,k,x,y,o,N;
158 | main(){float z[1760],a
159 | #define R(t,x,y) f=x;x-=t*y\
160 | ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;
161 | =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char
162 | b[1760];for(;;){memset(b,32,1760);g=0,
163 | h=1;memset(z,0,7040);for(j=0;j<90;j++){
164 | G=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*
165 | A*a+g*e+5);t=G*A *e-g*a;x=40+30*D
166 | *(H*A*d-t*c);y= 12+15*D*(H*A*c+
167 | t*d);o=x+80*y;N =8*((g*a-G*h*e)
168 | *d-G*h*a-g*e-H*h *c);if(22>y&&y>
169 | 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0
170 | ?N:0)[".,-~:;=!*#$@"];}R(.02,H,G);}R(
171 | .07,h,g);}for(k=0;1761>k;k++)putchar
172 | (k%80?b[k]:10);R(.04,e,a);R(.02,d,
173 | c);usleep(15000);printf('\n'+(
174 | " donut.c! \x1b[23A"));}}
175 | /*no math lib needed
176 | .@a1k0n 2021.*/
177 | EOF
178 | ```
179 |
180 | === "GNU/Linux"
181 |
182 | ```c
183 | cat << EOF > donut.c
184 | i,j,k,x,y,o,N;
185 | main(){float z[1760],a
186 | #define R(t,x,y) f=x;x-=t*y\
187 | ;y+=t*f;f=(3-x*x-y*y)/2;x*=f;y*=f;
188 | =0,e=1,c=1,d=0,f,g,h,G,H,A,t,D;char
189 | b[1760];for(;;){memset(b,32,1760);g=0,
190 | h=1;memset(z,0,7040);for(j=0;j<90;j++){
191 | G=0,H=1;for(i=0;i<314;i++){A=h+2,D=1/(G*
192 | A*a+g*e+5);t=G*A *e-g*a;x=40+30*D
193 | *(H*A*d-t*c);y= 12+15*D*(H*A*c+
194 | t*d);o=x+80*y;N =8*((g*a-G*h*e)
195 | *d-G*h*a-g*e-H*h *c);if(22>y&&y>
196 | 0&&x>0&&80>x&&D>z[o]){z[o]=D;b[o]=(N>0
197 | ?N:0)[".,-~:;=!*#$@"];}R(.02,H,G);}R(
198 | .07,h,g);}for(k=0;1761>k;k++)putchar
199 | (k%80?b[k]:10);R(.04,e,a);R(.02,d,
200 | c);usleep(15000);printf('\n'+(
201 | " donut.c! \x1b[23A"));}}
202 | /*no math lib needed
203 | .@a1k0n 2021.*/
204 | EOF
205 | ```
206 |
207 | Then make the donut fly with CJIT!
208 |
209 | === "MS/Windows"
210 | ```
211 | .\cjit.exe .\donut.c
212 | ```
213 | === "Apple/OSX"
214 | ```
215 | ./cjit donut.c
216 | ```
217 | === "GNU/Linux"
218 | ```
219 | ./cjit donut.c
220 | ```
221 |
222 | !!! warning
223 | With this example and other programs, just hit **CTRL+C** to quit.
224 |
225 | The state of affairs in CJIT is well demonstrated by this example: right now the terminal is much slower on windows (rightmost donut).
226 |
227 | 
228 |
229 | ## Game of Life
230 |
231 | Another fascinating example is the "Game of Life," a cellular
232 | automaton devised by the British mathematician John Horton Conway
233 | in 1970.
234 |
235 | Our `life.c` example is part of the [cjit-demo.tar.gz](https://github.com/dyne/cjit/releases/latest/download/cjit-demo.tar.gz) package you should download to enjoy this and other demos in this tutorial. Download, extract and **copy the cjit executable inside the cjit-demo folder**. Below are quick sequence of commands to do that:
236 |
237 | === "MS/Windows"
238 |
239 | ```
240 | Invoke-WebRequest -OutFile "life.c" -Uri "https://github.com/dyne/cjit/raw/refs/heads/main/examples/life.c"
241 | ```
242 |
243 | === "Apple/OSX"
244 |
245 | ```
246 | curl -sLo life.c https://github.com/dyne/cjit/raw/refs/heads/main/examples/life.c
247 | ```
248 |
249 | === "GNU/Linux"
250 |
251 | ```
252 | curl -sLo life.c https://github.com/dyne/cjit/raw/refs/heads/main/examples/life.c
253 | ```
254 |
255 | Then execute the `life.c` source file passing it as argument to `cjit`, the same way it was done for the flying donut.
256 |
257 | === "MS/Windows"
258 |
259 | ```
260 | .\cjit.exe life.c
261 | ```
262 |
263 | === "Apple/OSX"
264 |
265 | ```
266 | ./cjit life.c
267 | ```
268 |
269 | === "GNU/Linux"
270 |
271 | ```
272 | ./cjit life.c
273 | ```
274 |
275 | Have a look around the `life.c` file with your favorite text editor and
276 | feel free to change things and see what happens.
277 |
278 | 
279 |
280 |
281 | # ⏩ [Next: graphics with CJIT](graphics.md)
282 |
283 | Go to the next chapter of this tutorial.
284 |
--------------------------------------------------------------------------------
/src/cjit/docs/manpage.md:
--------------------------------------------------------------------------------
1 | # cjit(1) - Just-In-Time interpreter for C
2 |
3 | CJIT, January 2025
4 |
5 |
cjit [options] <files> [-- app arguments]
6 |
7 |
8 |
9 | [options] are prefixed by single or double dash and may require an argument
10 |
11 |
12 |
13 | <files> can be one or more paths to any source (.c), object (.o) or libs (dll, dylib, .so)
14 |
15 |
16 |
17 | [-- app args] all arguments following a double dash are passed as-is to the running application
.B .IP/ { next; } /tomb\(1\)/ {print("# Tomb, folder encryption on GNU/Linux"); next;} /^# / {printf("#%s",$$0); next} /^tomb,/ {print("Manpage update: " $0)} { print $0 }' > manpage.md
6 |
--------------------------------------------------------------------------------
/src/tomb/docs/images/awesome-shot.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/awesome-shot.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/cryptounderstaker.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/cryptounderstaker.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/github_tomb.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/github_tomb.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/monmort1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/monmort1.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/nerdonthestreet.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/nerdonthestreet.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/tomb_crew_hkm11.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/tomb_crew_hkm11.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/tomb_n_bats.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/tomb_n_bats.webp
--------------------------------------------------------------------------------
/src/tomb/docs/images/tomb_songs.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dyne/docs/63a6a94f6a693341fd5a46ce6fea9dc816f456e3/src/tomb/docs/images/tomb_songs.webp
--------------------------------------------------------------------------------
/src/tomb/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: ../../layouts/Layout.astro
3 | title: "Tomb :: Folder Encryption on GNU/Linux"
4 | description: "Tomb is a system to make strong encryption easy for everyday use. A tomb is like a locked folder that can be safely transported and hidden in a filesystem."
5 | cover: "https://dyne.org/social/tomb.png"
6 | ---
7 |
8 |
9 |
10 | 
11 | Tombs and Bats
12 |
13 |
14 | Tomb is a **100% Free and Open Source** tool to manage secret files in volumes protected by **strong encryption**.
15 |
16 | Tomb's ambition is to improve safety by way of:
17 |
18 | - A **minimalist** design consisting of small and readable code
19 | - The facilitation of **good practices**, i.e.: key/storage physical separation
20 | - The adoption of a few standards and **battle-tested** components
21 |
22 |
23 | ## How it works
24 |
25 | We design Tomb's hidden file encryption to generate encrypted **storage folders** to be opened and closed using associated **key files**, which are also protected with a **password** chosen by the user.
26 |
27 | A tomb is a file whose **contents are kept secret and indistinguishable**; it can be safely **renamed, transported and hidden in filesystems**; its **keys should be kept separate**, for instance, keeping the tomb file on your computer's hard disk and the key files on a USB stick. **Once open, the tomb looks like a folder**.
28 |
29 | Tomb derives from scripts used in the [dyne:bolic](http://dynebolic.org/) 100% Free GNU/Linux distribution and a shell script (Zsh) using standard filesystem tools (GNU) and the cryptographic API of the Linux kernel (dm-crypt and LUKS via cryptsetup). Tomb's status and error messages are **translated into many human languages** and have **multiple graphical applications** to operate.
30 |
31 |
32 | 
33 | Screenshot of a menu entry in a Desktop Environment
34 |
35 |
36 |
37 | ## Get Started
38 |
39 | **Tomb works only on GNU/Linux systems and WSL2 starting with Windows11**.
40 |
41 | If you are already familiar with using the command line, [download the tar.gz](https://files.dyne.org/tomb) and jump to the [installation instructions](https://github.com/dyne/Tomb/blob/master/INSTALL.md).
42 |
43 | Tomb is also found in [many distributions](https://repology.org/project/tomb/versions), so you can use your package manager to install it.
44 |
45 | However, **Tomb is a single script** and is very easy to install manually. Using `make install` in our source distribution will copy it into `/usr/local/bin` along with its manpage (`man tomb`) and language translations.
46 |
47 | Be in charge of your system, and **may the source be with you**!
48 |
49 |
50 | 
51 | Tomb Songs are the best kept musical secrets in the world
52 |
53 |
54 |
55 | ## Usage
56 |
57 | Tombs are operated from a terminal command line and require **root access** to the machine (or just sudo access to the script).
58 |
59 | To create a 100MB tomb called "secret" do:
60 |
61 | ```
62 | tomb dig -s 100 secret.tomb
63 | tomb forge secret.tomb.key
64 | tomb lock secret.tomb -k secret.tomb.key
65 | ```
66 |
67 | To open it, do
68 | ```
69 | tomb open secret.tomb -k secret.tomb.key
70 | ```
71 | And to close it
72 | ```
73 | tomb close
74 | ```
75 | Or if you are in a hurry
76 | ```
77 | tomb slam all
78 | ```
79 | Will close immediately all open tombs, killing all applications using them.
80 |
81 | Here is a **lovely review made by the Linux Action Show guys** in August 2014, where they recommend Tomb as a replacement for Veracrypt
82 |
83 |
84 |
85 |
86 | ## Advanced usage
87 |
88 | The tomb script takes care of several details to improve a user’s
89 | behaviour and the security of tombs in everyday usage: it protects the
90 | typing of passwords from keyloggers, facilitates hiding keys inside
91 | images, mounts directories in place without copying delicate files around, allows a user to kill all running processes and slam close a tomb in a straightforward command, warns the user about free space and last-time usage, etc.
92 |
93 | 
94 |
95 | One can use **multiple tombs** simultaneously on the same system and list them using `tomb list`.
96 |
97 | 
98 |
99 | Using `tomb resize`, one can **expand tombs** to have more space (but cannot shrink them).
100 |
101 | 
102 |
103 | When it is open, a tomb can **bind contents inside the user’s `$HOME`** folder using `bind-hooks`. For instance, `.gnupg` will only be found inside your `$HOME` when the tomb opens.
104 |
105 | 
106 |
107 | A tomb can be used on a local machine with **keys on a server** and never stored on the same device: `ssh me@dyne.org 'cat my.tomb.key' | tomb open my.tomb -k -` the option `-k -` tells tomb to take the key from stdin.
108 |
109 | 
110 |
111 | It is also possible to **store a tomb on a cloud service and mount it locally**, ensuring remote servers cannot access contents. One can use **sshfs** for this:
112 |
113 | ```
114 | sshfs -o allow_root me@dyne.org:/ /mnt/cloud/
115 | tomb open /mnt/cloud/my.tomb -k my.key
116 | ```
117 |
118 | [This paper](https://www.researchgate.net/publication/262698824_Data_privacy_in_Desktop_as_a_Service) provides a lot of details about using tombs hosted on cloud storage.
119 |
120 | 
121 |
122 | Tomb also supports **deniable key storage** using steganography. One can `tomb bury` and `tomb exhume` keys to and from `JPEG` images when the utility `steghide` is installed. When securing private data, one must never forget where the keys are. It may be easier to remember a picture, as well it may be less suspicious to transport it and exchange it as a file.
123 |
124 | 
125 |
126 | The command `tomb engrave` also allows to backup keys on paper by saving them as printable QR codes, to hide it between the pages of a book. To recover an engraved key, one can scan it with any phone and save the resulting plain text file as the tomb key.
127 |
128 | You can also watch this other video guide by Nerd on the Street.
129 |
130 |
131 |
132 | ## External applications
133 |
134 | The following applications are compatible with Tomb:
135 |
136 | - [pass-tomb](https://github.com/roddhjav/pass-tomb) is a console-based wrapper of the excellent password-keeping program [pass](https://www.passwordstore.org) that helps to keep the whole tree of passwords encrypted inside a tomb.
137 |
138 | - [Secrets](https://secrets.dyne.org) is an online software to split a Tomb key into shares that a quorum of owners can merge to reconstitute.
139 |
140 | - [Mausoleum](https://github.com/mandeep/Mausoleum) is a graphical interface to facilitate the creation and management of tombs, written in Python.
141 |
142 | - [zuluCrypt](https://mhogomchungu.github.io/zuluCrypt/) is a graphical application to manage various types of encrypted volumes on GNU/Linux, among them also Tombs, written in C++.
143 |
144 |
145 | ## Frequently asked questions
146 |
147 | You can find a list of [Frequently Asked Questions (FAQ) on the website](https://dyne.org/tomb)
148 |
149 | ## Development
150 |
151 |
152 | 
153 | A sugarskull octocat
154 |
155 |
156 | Tomb is on [GitHub](https://github.com/dyne/Tomb), where most of the community activity goes.
157 |
158 | Developers can interact with us via a discussion area, issues, or pull requests. The README is also a brief introduction for developers willing to engage.
159 |
160 | The [short tomb tester howto](https://github.com/dyne/Tomb/wiki/TesterHowTo) provides a guide to troubleshooting problems. Anyone planning to write code in Tomb should first look at the [short tomb developer howto](https://github.com/dyne/Tomb/wiki/DeveloperHowto).
161 |
162 | To get in touch with us in person please plan to participate in one of the yearly [italian hackmeeting](http://hackmeeting.org), usually held during summer on the peninsula.
163 |
164 |
165 | 
166 | A cheerful picture of Tomb developers crew at Hackmeeting 2011 in Firenze
167 |
168 |
169 |
170 |
171 |
172 | > All I know is what the words know, and dead things, and that makes a handsome little sum, with a beginning and a middle and an end, as in the well-built phrase and the long sonata of the dead. - Samuel Beckett
173 |
174 |
--------------------------------------------------------------------------------
/src/tomb/docs/manpage.md:
--------------------------------------------------------------------------------
1 | # Tomb, folder encryption on GNU/Linux
2 |
3 | Manpage update:
4 | tomb, Jun 25, 2023
5 |
6 |
7 |
8 |
9 |
10 | ## Description
11 |
12 | Tomb is an application to manage the creation and access of encrypted
13 | storage files: it can be operated from commandline and it can
14 | integrate with a user's graphical desktop.
15 |
16 | Tomb generates encrypted storage files to be opened and closed using
17 | their associated keys, which are also protected with a password chosen
18 | by the user. To create, open and close tombs a user will need super
19 | user rights to execute the tomb commandline utility.
20 |
21 | A tomb is like a locked folder that can be safely transported and
22 | hidden in a filesystem; it encourages users to keep their keys
23 | separate from tombs, for instance keeping a tomb file on your computer
24 | harddisk and its key file on a USB stick.
25 |
26 |
27 |
28 |
29 |
30 | ## Commands
31 |
32 |
33 |
34 | * dig
35 | Generates a file that can be used as a tomb and will occupy as much
36 | space as its desired initial size, the unlocked _.tomb_ file can
37 | then be locked using a _key_. It takes a mandatory _-s_ option
38 | which is the size in megabytes (MiB). Tombs are digged using random
39 | data gathered from a non-blocking source (/dev/urandom). For very
40 | large tombs this may take up too much time and entropy, then it is
41 | possible to use _fallocate(1)_ being aware it does not pre-fill
42 | with random data, decreasing the tomb's security.
43 |
44 |
45 | * forge
46 | Creates a new _key_ and prompts the user for a _password_ to protect
47 | its usage using symmetric encryption. This operation uses random data from a
48 | non-blocking source (/dev/urandom) and it may take long only in some cases; to
49 | switch using a blocking source the _--use-random_ flag can be used. The
50 | _-g_ option switches on the use of a GPG key instead of a password
51 | (asymmetric encryption), then the _-r_ option indicates the recipient key;
52 | more recipient GPG ids can be indicated (comma separated). The default cipher
53 | to protect the key is AES256, a custom one can be specified using the _-o_
54 | option, for a list of supported ciphers use _-v_. For additional protection
55 | against dictionary attacks on keys, the _--kdf_ option can be used when
56 | forging a key, making sure that the binaries in _extras/kdf_ were compiled
57 | and installed on the system.
58 |
59 |
60 | * lock
61 | Initializes and locks an empty tomb (made with _dig_) using a key
62 | (made with _forge_), making it ready for usage. After this
63 | operation, the tomb can only be opened in possession of the key and
64 | knowing its password. As in any other command requiring a key, the
65 | option _-k_ should be used to specify a key file; in case of
66 | encryption to GPG recipients the _-g_ flag should be used followed
67 | by _-r_ and the recipient's secret GPG key id. The _-o_
68 | option can be used to specify the cipher specification: default is
69 | "aes-xts-plain64", old versions of Tomb used "aes-cbc-essiv:sha256".
70 | If you are looking for something exotic, also try
71 | "serpent-xts-plain64". More options may be found in cryptsetup(8) and
72 | Linux documentation. The _--filesystem_ option can be used to
73 | specify an alternative filesystem used to format the tomb,
74 | in place of the default "ext4". This operation requires root
75 | privileges to loopback mount, format the tomb (using LUKS and mkfs),
76 | then set the key in its first LUKS slot.
77 |
78 | Supported filesystems for _--filesystem_:
79 | * ext3
80 | using operating system defaults
81 | * ext4
82 | using operating system defaults
83 | * btrfs
84 | for tombs >= 47MB using operating system defaults
85 | * btrfsmixedmode
86 | for tombs >=18MB btrfs mixed mode (see mkfs.btrfs(8))
87 | * ext3maxinodes
88 | ext3 with a maximum of inodes (for many small files)
89 | * ext4maxinodes
90 | ext4 with a maximum of inodes (for many small files)
91 |
92 |
93 | * open
94 | Opens an existing _tomb file_ (first argument) using a key
95 | (_-k_) which can also be hidden inside a _jpeg image_ (see
96 | _bury_/_exhume_) or a long text file
97 | (see_cloak_/_uncloak_). If a second argument is given it will
98 | indicate the _mountpoint_ where the tomb should be made
99 | accessible, else the tomb is mounted in a directory inside /media (if
100 | not available it uses /run/media/$USER). The option _-o_ can be
101 | used to pass mount(8) options (default: rw,noatime,nodev). The
102 | _-g_ option is needed when using GPG encryption to recipients.
103 |
104 |
105 | * list
106 | List all the tombs found open, including information about the time
107 | they were opened and the hooks that they mounted. If the first
108 | argument is present, then shows only the tomb named that way or
109 | returns an error if it's not found. If the option
110 | _--get-mountpoint_ is used then print a simple list of currently
111 | open tomb mountpoint paths.
112 |
113 |
114 | * ps
115 | List all the processes found running inside the tombs that are open,
116 | printing out their PIDs and owners. This is useful to have an overview
117 | of programs that are keeping the tombs busy and would eventually be
118 | killed by the _slam_ command. The lsof(8) utility is used
119 | internally to enumerate processes running in one or all tombs.
120 |
121 |
122 | * index
123 | Creates or updates the search indexes of all tombs currently open:
124 | enables use of the _search_ command using simple word patterns on
125 | file names. Indexes are created using plocate's updatedb(8) and
126 | recoll(1) if they are found on the system. Indexes allow one to search
127 | very fast for filenames and contents inside a tomb, they are stored
128 | inside it and are not accessible if the Tomb is closed. To avoid
129 | indexing a specific tomb simply touch a _.noindex_ file in it.
130 | Useful tools to have: poppler-utils, aspell, xdg-utils, plocate.
131 |
132 |
133 | * search
134 | Takes any string as argument and searches for them through all tombs
135 | currently open and previously indexed using the _index_ command.
136 | The search matches filenames if plocate is installed and then also
137 | file contents if recoll is installed, all results are listed on the
138 | console.
139 | One can also run recoll's GUI using _recoll -c /media/tomb_
140 |
141 |
142 | * close
143 | Closes a currently open tomb. If more tombs are open, the first
144 | argument should be used to specify the name of the tomb to be closed,
145 | or _all_ to close all currently open tombs. This command fails if
146 | the tomb is in use by running processes (to force close, see
147 | _slam_ below).
148 |
149 |
150 | * slam
151 | Closes a tomb like the command _close_ does, but it doesn't fail
152 | even if the tomb is in use by other application processes: it looks
153 | for and closes each of them (in order: TERM, HUP, KILL). This command may
154 | provoke unsaved data loss, but assists users to face surprise
155 | situations. It requires _lsof_ else it falls back to _close_.
156 |
157 |
158 |
159 | * passwd
160 | Changes the password protecting a key file specified using
161 | _-k_. With keys encrypted for GPG recipients use _-g_ followed
162 | by _-r_ to indicate the new recipient key, or a comma separated
163 | list.. The user will need to know the key's current password, or
164 | possess at least one of the current recipients GPG secret keys,
165 | because the key contents will be decoded and reencoded using the new
166 | passwords or keys. If the key file is broken (missing headers) this
167 | function also attempts its recovery.
168 |
169 |
170 | * setkey
171 | Changes the key file that locks a tomb, substituting the old one with
172 | a new one. Both the old and the new key files are needed for this
173 | operation and their passwords or GPG recipient(s) secret keys must be
174 | available. The new key must be specified using the _-k_ option,
175 | the first argument should be the old key and the second and last
176 | argument the tomb file. Use the _-g_ option to unlock the tomb
177 | with a GPG key, the _-r_ to indicate the recipient or a comma
178 | separated list for more than one recipient.
179 |
180 |
181 | * resize
182 | Increase the size of a tomb file to the amount specified by the
183 | _-s_ option, which is the new size in megabytes (MiB). Full access
184 | to the tomb using a key (_-k_) and its password is required. Tombs
185 | can only grow and can never be made smaller. This command makes use of
186 | the cryptsetup(8) resize feature and the resize2fs command: its much
187 | more practical than creating a new tomb and moving everything into
188 | it. There is no data-loss if a failure occurs during resize: the
189 | command can be re-launched and the resize operation will complete.
190 |
191 |
192 | * engrave
193 | This command transforms a tomb key into an image that can be printed
194 | on paper and physically stored as backup, i.e. hidden in a book. It
195 | Renders a QRCode of the tomb key, still protected by its password: a
196 | PNG image (extension _.qr.png_) will be created in the current
197 | directory and can be later printed (fits an A4 or Letter format). To
198 | recover an engraved key one can use any QRCode reader on a smartphone:
199 | save it into a file and then use that file as a key (_-k_).
200 |
201 |
202 | * bury
203 | Hides a tomb key (_-k_) inside a _jpeg image_ (first argument)
204 | using _steganography_: the image will change in a way that cannot
205 | be noticed by human eye and hardly detected by data analysis. This
206 | option is useful to backup tomb keys in unsuspected places; it depends
207 | from the availability of _steghide_. Use the _-g_ flag and
208 | _-r_ option followed by recipient id to use GPG asymmetric
209 | encryption.
210 |
211 |
212 | * exhume
213 | This command recovers from jpeg images the keys that were previously
214 | hidden into them using _bury_. Exhume requires a key filename
215 | (_-k_) and a _jpeg image_ file (first argument) known to be
216 | containing a key. If the right key password is given, the key will be
217 | exhumed. If the password is not known, it is very hard to verify if a
218 | key is buried in any image or not.
219 |
220 |
221 | * cloak
222 | Cloaks a tomb key (_-k_) disguising it as a text file using a
223 | cipher from _extras/cloak/ciphers_ (second argument) using
224 | _cloakify_. This option is useful to backup tomb keys in
225 | unsuspected places; it needs _extras/cloak_ installed and
226 | _python3_.
227 |
228 |
229 | * uncloak
230 | Recovers a tomb key from a cloaked text file. Uncloak requires a text
231 | file (first argument), a cipher file (second argument) and optionally
232 | an output file (third argument). If the first two parameters are
233 | correct then the output will be a valid tomb key file restored from
234 | cloak.
235 |
236 |
237 |
238 |
239 | ## Options
240 |
241 |
242 |
243 | * -k _<keyfile>_
244 | For all operations requiring a key, this option specifies the location
245 | of the key file to use. Arguments can also be _jpeg image_ files
246 | where keys have been hidden using the _bury_ or _cloak_
247 | commands, or text files retrieved from _engraved_ QR codes. If the
248 | _keyfile_ argument is "-" (dash), Tomb will read the key from
249 | stdin (blocking).
250 |
251 | * -n
252 | Skip processing of exec-hooks and bind-hooks if found inside the tomb.
253 | See the _HOOKS_ section in this manual for more information.
254 |
255 | * -p
256 | When opening a tomb, preserves the ownership of all files and
257 | directories contained in it. Normally the _open_ command changes
258 | the ownership of a tomb's contents to the UID and GID of the user who
259 | has successfully opened it: it is a usability feature in case a tomb is
260 | used by a single user across different systems. This flag deactivates
261 | this behaviour.
262 |
263 | * -o
264 | Manually specify mount options to be used when opening a tomb instead
265 | of the default _rw,noatime,nodev_, i.e. to mount a tomb read-only
266 | (ro) to prevent any modification of its data. Can also be used to
267 | change the symmetric encryption algorithm for keys during _forge_
268 | operations (default _AES256_) or the LUKS encryption method during
269 | _lock_ operations (default _aes-xts-plain64_).
270 |
271 | * -f
272 | Force flag, currently used to override swap checks, might be
273 | overriding more wimpy behaviours in future, but make sure you know
274 | what you are doing if you force an operation.
275 |
276 | * -s _<MBytes>_
277 | When digging or resizing a tomb, this option must be used to specify
278 | the _size_ of the new file to be created. Units are megabytes (MiB).
279 |
280 | * -g
281 | Tell tomb to use an asymmetric GnuPG key encryption instead of a
282 | symmetric passphrase to protect a tomb key. This option can be
283 | followed by _-r_ when the command needs to specify recipient(s).
284 |
285 | * -r _<gpg\_id>[,<gpg\_id2>]_
286 | Provide a new set of recipient(s) to encrypt a tomb key. _gpg\_ids_
287 | can be one or more GPG key ID, comma separated. All GPG keys must be
288 | trusted keys in GPG.
289 |
290 | * --kdf _<itertime>_
291 | Activate the KDF feature against dictionary attacks when creating a key: forces
292 | a delay of _<itertime>_ times every time this key is used. The actual time
293 | to wait depends on the CPU speed (default) or the RAM size (argon2) of the
294 | computer where the key is used. Using 5 or 10 is a sane amount for modern
295 | computers, the value is multiplied by 1 million.
296 |
297 | * --kdftype _argon2 | pbkdf2_
298 | Adopt the _argon2_ algorithm for KDF, stressing the RAM capacity rather
299 | than the CPU speed of the computer decrypting the tomb. Requires the
300 | _argon2_ binary by P-H-C to be installed, as packaged by most distros.
301 | Default is _pbkdf2_.
302 |
303 | * --kdfmem _<memory>_
304 | In case of _argon2_ KDF algorithm, this value specifies the size of RAM
305 | used: it consists of a number which is the elevated power of two in kilobytes.
306 | Default is 18 which is 250 MiB (2^18 = 262,144 kilobytes).
307 |
308 | * --sudo _<executable>_
309 | Select a different tool than sudo for privilege escalation.
310 | Alternatives supported so far are: pkexec, doas, sup, sud. For any
311 | alternative to work the executable must be included in the current
312 | PATH.
313 |
314 |
315 | * -h
316 | Display a help text and quit.
317 |
318 | * -v
319 | Display version and quit.
320 |
321 | * -q
322 | Run more quietly
323 |
324 | * -D
325 | Print more information while running, for debugging purposes
326 |
327 |
328 |
329 |
330 | ## Dev Mode
331 |
332 |
333 | * --no-color
334 | Suppress colors in console output (needed for string parsing by
335 | wrappers).
336 |
337 | * --unsafe
338 | Enable using dev-mode arguments, i.e. to pass passwords from
339 | commandline options. This is mostly used needed for execution by
340 | wrappers and testing suite.
341 |
342 | * --use-random
343 | Use a blocking random source. Tomb uses by default /dev/urandom since
344 | the non-blocking source of Linux kernel doesn't degrades the quality
345 | of random.
346 |
347 | * --tomb-pwd <string>
348 | Use string as password when needed on tomb.
349 |
350 | * --tomb-old-pwd <string>
351 | Use string as old password when needed in tomb commands requiring
352 | multiple keys, like _passwd_ or _setkey_.
353 |
354 | * -U
355 | Switch to this user ID when dropping privileges.
356 |
357 | * -G
358 | Switch to this group ID when dropping privileges.
359 |
360 | * -T
361 | Switch to this TTY terminal when dropping privileges.
362 |
363 |
364 |
365 |
366 | ## Hooks
367 |
368 | Hooks are special files that can be placed inside the tomb and trigger
369 | actions when it is opened and closed; there are two kinds of such
370 | files: _bind-hooks_ and _exec-hooks_ can be placed in the
371 | base root of the tomb.
372 |
373 |
374 |
375 | * bind-hooks
376 | This hook file consists of a simple text file named _bind-hooks_
377 | containing a two column list of paths to files or directories inside
378 | the tomb. The files and directories will be made directly
379 | accessible by the tomb _open_ command inside the current user's
380 | home directory. Tomb uses internally the "mount -o bind" command to
381 | bind locations inside the tomb to locations found in $HOME. In the
382 | first column are indicated paths relative to the tomb and in the
383 | second column are indicated paths relative to $HOME contents, for
384 | example:
385 |
386 | ```
387 |
388 | mail mail
389 | .gnupg .gnupg
390 | .fmrc .fetchmailrc
391 | .mozilla .mozilla
392 |
393 | ```
394 |
395 |
396 |
397 | * exec-hooks
398 | This hook file gets executed as user by tomb with the first argument
399 | determining the step of execution (_open_ or _close_) and the second
400 | being the full path to the mountpoint. The _exec-hooks_ file should be
401 | executable (ELF or shell script) and present inside the Tomb. Tomb
402 | executes this hook as user and adds the name, loopback device and
403 | dev-mapper device paths as additional arguments for the _close_
404 | command.
405 |
406 |
407 |
408 |
409 | ## Privilege Escalation
410 |
411 | The tomb commandline tool needs to acquire super user rights to
412 | execute most of its operations: so it uses sudo(8) or other configured
413 | tools, while pinentry(1) is adopted to collect passwords from the
414 | user. Tomb executes as super user only when required.
415 |
416 | To be made available on multi user systems, the superuser execution of
417 | the tomb script can be authorized for users without jeopardizing the
418 | whole system's security: just add such a line to _/etc/sudoers_:
419 |
420 |
421 | ```
422 |
423 | username ALL=NOPASSWD: /usr/local/bin/tomb
424 |
425 | ```
426 |
427 |
428 | To avoid that tomb execution is logged by _syslog_ also add:
429 |
430 |
431 | ```
432 |
433 | Cmnd_Alias TOMB = /usr/local/bin/tomb
434 | Defaults!TOMB !syslog
435 |
436 | ```
437 |
438 |
439 |
440 |
441 |
442 | ## Password Input
443 |
444 | Password input is handled by the pinentry program: it can be text
445 | based or graphical and is usually configured with a symlink. When
446 | using Tomb in a graphical environment (X11 or Wayland) it is better
447 | to use either pinentry-gtk2 (deprecated), pinentry-gnome or
448 | pinentry-qt because it helps preventing keylogging by other clients.
449 | When using it from a remote ssh connection it might be necessary to
450 | force use of pinentry-tty for instance by unsetting the DISPLAY (X11)
451 | or WAYLAND_DISPLAY (Wayland) environment var.
452 |
453 |
454 |
455 |
456 | ## Swap
457 |
458 | On execution of certain commands Tomb will complain about swap memory
459 | on disk when present and abort if your system has swap
460 | activated. You can disable this behaviour using the
461 | _--force_. Before doing that, however, you may be interested in
462 | knowing the risks of doing so:
463 |
464 | *
465 | During such operations a lack of available memory could cause the swap
466 | to write your secret key on the disk.
467 | *
468 | Even while using an opened tomb, another application could occupy too
469 | much memory so that the swap needs to be used, this way it is possible
470 | that some contents of files contained into the tomb are physically
471 | written on your disk, not encrypted.
472 |
473 |
474 | If you don't need swap, execute _ swapoff -a_. If you really need
475 | it, you could make an encrypted swap partition. Tomb doesn't detect if
476 | your swap is encrypted, and will complain anyway.
477 |
478 |
479 |
480 |
481 | ## Deniability
482 |
483 | The possibility to have an encrypted volume which is invisible and
484 | cannot be detected is called "deniability". The cryptographic layer of
485 | the device mapper in Linux (dm-crypt) does not implement
486 | deniability. Tomb is just a wrapper on top of that and it doesn't add
487 | cryptographic deniability. However a certain way of using tomb can
488 | facilitate a weak sort of deniability outside of the scenario of
489 | seized devices and forensic analysis of files and blocks on disc.
490 |
491 | For instance to eliminate any trace of tomb usage from the shell
492 | history ZSh users can activate the "HISTIGNORESPACE" feature and
493 | prefix all invocations of tomb with a blank space, including two lines
494 | in ".zshrc":
495 |
496 |
497 | ```
498 |
499 | export HISTIGNORESPACE=1
500 | alias tomb=' tomb'
501 |
502 | ```
503 |
504 |
505 |
506 |
507 |
508 | ## Share a Tomb
509 | A tomb key can be encrypted with more than one recipient. Therefore, a
510 | tomb can be shared between different users. The recipients are given
511 | using the _-r_ (or/and _-R_) option and if multiple each GPG
512 | key ID must be separated by a comma (_,_). Sharing a tomb is a
513 | very sensitive action and the user needs to trust that all the GPG
514 | public keys used are kept safe. If one of them its stolen or lost, it
515 | will be always possible to use it to access the tomb key unless all
516 | its copies are destroyed. The _-r_ option can be used in the tomb
517 | commands: _open_, _forge_ _setkey_, _passwd_,
518 | _bury_, _exhume_ and _resize_.
519 |
520 |
521 |
522 |
523 | ## Examples
524 |
525 |
526 | *
527 | Create a 128MB large "secret" tomb and its keys, then open it:
528 |
529 |
530 | ```
531 |
532 | tomb dig -s 128 secret.tomb
533 |
534 | tomb forge secret.tomb.key
535 |
536 | tomb lock secret.tomb -k secret.tomb.key
537 |
538 | tomb open secret.tomb -k secret.tomb.key
539 |
540 | ```
541 |
542 |
543 | *
544 | Open a Tomb using the key from a remote SSH shell, without saving any
545 | local copy of it:
546 |
547 |
548 | ```
549 |
550 | ssh user@my.shell.net 'cat .secrets/tomb.key' | tomb open secret.tomb -k -
551 |
552 | ```
553 |
554 |
555 | *
556 | Open a Tomb on a remote server passing the unencrypted local key on stdin via SSH,
557 | without saving any remote copy of it:
558 |
559 |
560 | ```
561 |
562 | gpg -d .secrets/tomb.key | ssh server tomb open secret.tomb -k cleartext --unsafe
563 |
564 | ```
565 |
566 |
567 | *
568 | Create a bind hook that places your GnuPG folder inside the tomb, but
569 | makes it reachable from the standard $HOME/.gnupg location every time
570 | the tomb will be opened:
571 |
572 |
573 | ```
574 |
575 | tomb open GPG.tomb -k GPG.tomb.key
576 | echo ".gnupg .gnupg" > /media/GPG.tomb/bind-hooks
577 | mv ~/.gnupg /media/GPG.tomb/.gnupg && mkdir ~/.gnupg
578 | tomb close GPG && tomb open GPG.tomb -k GPG.tomb.key
579 |
580 | ```
581 |
582 |
583 | *
584 | Script a tomb to launch the Firefox browser every time is opened,
585 | keeping all its profile data inside it:
586 |
587 |
588 | ```
589 |
590 | tomb open FOX.tomb -k FOX.tomb.key
591 | cat <<EOF > /media/FOX.tomb/exec-hooks
592 | #!/bin/sh
593 | if [ "$1" = "open" ]; then
594 | firefox -no-remote -profile "$2"/firefox-pro &
595 | fi
596 | EOF
597 | chmod +x /media/FOX.tomb/exec-hooks
598 | mkdir /media/FOX.tomb/firefox-pro
599 |
600 | ```
601 |
602 |
603 | *
604 | Script a tomb to archive Pictures using Shotwell, launching it on open:
605 |
606 |
607 | ```
608 |
609 | tomb open Pictures.tomb -k Pictures.tomb.key
610 | cat <<EOF > /media/Pictures.tomb/bind-hooks
611 | Pictures Pictures
612 | EOF
613 | cat <<EOF > /media/Pictures.tomb/exec-hooks
614 | #!/bin/sh
615 | if [ "$1" = "open" ]; then
616 | which shotwell > /dev/null
617 | if [ "$?" = "0" ]; then
618 | shotwell -d "$2"/Pictures/.shotwell &
619 | fi
620 | fi
621 | EOF
622 | chmod +x /media/Pictures.tomb/exec-hooks
623 |
624 | ```
625 |
626 |
627 |
628 |
629 |
630 | ## Bugs
631 | Please report bugs on the Github issue tracker at
632 | [](https://github.com/dyne/Tomb/issues)
633 |
634 | One can also try to get in touch with developers via the #dyne chat
635 | channel on _https://irc.dyne.org_.
636 |
637 |
638 |
639 |
640 | ## Copying
641 |
642 | This manual is Copyright (c) 2011-2021 by Denis Roio <_jaromil@dyne.org_>
643 |
644 | This manual includes contributions by Boyska and Hellekin O. Wolf.
645 |
646 | Permission is granted to copy, distribute and/or modify this manual
647 | under the terms of the GNU Free Documentation License, Version 1.1 or
648 | any later version published by the Free Software Foundation.
649 | Permission is granted to make and distribute verbatim copies of this
650 | manual page provided the above copyright notice and this permission
651 | notice are preserved on all copies.
652 |
653 |
654 |
655 |
656 | ## Availability
657 |
658 | The most recent version of Tomb sourcecode and up to date
659 | documentation is available for download from its website on
660 | _https://tomb.dyne.org_.
661 |
662 |
663 |
664 |
665 | ## See Also
666 |
667 |
668 |
669 | * cryptsetup(8)
670 |
671 | * pinentry(1)
672 |
673 | * gpg-agent(1)
674 |
675 | GnuPG website: https://www.gnupg.org
676 |
677 | DM-Crypt website: https://gitlab.com/cryptsetup/cryptsetup/wikis/DMCrypt
678 |
679 | LUKS website: https://gitlab.com/cryptsetup/cryptsetup/wikis/home
680 |
--------------------------------------------------------------------------------
/src/tomb/docs/stylesheets/extra.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #ECF8F7 !important;
3 | }
4 | .md-header {
5 | background-color: #36968C !important;
6 | }
7 |
--------------------------------------------------------------------------------
/src/tomb/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: Tomb Manual
2 | site_url: https://dyne.org/docs/tomb
3 |
4 | theme:
5 | name: material
6 | logo: images/dyneorg.svg
7 | favicon: images/favicon.png
8 |
9 | extra_css:
10 | - stylesheets/extra.css
11 |
12 | nav:
13 | - Introduction: index.md
14 | - Manpage: manpage.md
15 |
16 | markdown_extensions:
17 | - attr_list
18 | - md_in_html
19 | - admonition
20 | - pymdownx.details
21 | - pymdownx.superfences
22 |
--------------------------------------------------------------------------------