From fa3426b5d9ac9eeccaea3aa7e4eb44e1fa2eab65 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Mon, 26 Aug 2024 23:07:44 +0300 Subject: Update content for gemtext --- gemfeed/2008-06-26-perl-poetry.gmi | 15 +- gemfeed/2008-06-26-perl-poetry.gmi.tpl | 14 +- gemfeed/2010-04-09-standard-ml-and-haskell.gmi | 10 + gemfeed/2010-04-09-standard-ml-and-haskell.gmi.tpl | 176 ++++ .../2010-05-09-the-fype-programming-language.gmi | 38 +- ...010-05-09-the-fype-programming-language.gmi.tpl | 512 ++++++++++ .../2011-05-07-perl-daemon-service-framework.gmi | 7 +- ...011-05-07-perl-daemon-service-framework.gmi.tpl | 6 +- ...12-05-run-debian-on-your-phone-with-debroid.gmi | 21 +- ...5-run-debian-on-your-phone-with-debroid.gmi.tpl | 180 ++++ ...-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi | 7 +- ...09-jails-and-zfs-on-freebsd-with-puppet.gmi.tpl | 6 +- ...pinning-up-my-own-authoritative-dns-servers.gmi | 12 +- ...ing-up-my-own-authoritative-dns-servers.gmi.tpl | 239 +++++ ...ealistic-load-testing-with-ioriot-for-linux.gmi | 36 +- ...stic-load-testing-with-ioriot-for-linux.gmi.tpl | 191 ++++ ...4-22-dtail-the-distributed-log-tail-program.gmi | 27 +- ...-dtail-the-distributed-log-tail-program.gmi.tpl | 10 +- ...2021-05-16-personal-bash-coding-style-guide.gmi | 11 +- ...-05-16-personal-bash-coding-style-guide.gmi.tpl | 10 +- ...05-gemtexter-one-bash-script-to-rule-it-all.gmi | 15 +- ...emtexter-one-bash-script-to-rule-it-all.gmi.tpl | 12 +- gemfeed/2021-07-04-the-well-grounded-rubyist.gmi | 14 + .../2021-07-04-the-well-grounded-rubyist.gmi.tpl | 109 +++ ...1-08-01-on-being-pedantic-about-open-source.gmi | 20 +- ...-01-on-being-pedantic-about-open-source.gmi.tpl | 121 +++ gemfeed/2021-09-12-keep-it-simple-and-stupid.gmi | 7 +- .../2021-09-12-keep-it-simple-and-stupid.gmi.tpl | 6 +- gemfeed/2021-10-22-defensive-devops.gmi | 30 +- gemfeed/2021-10-22-defensive-devops.gmi.tpl | 106 ++ gemfeed/2021-11-29-bash-golf-part-1.gmi | 15 +- gemfeed/2021-11-29-bash-golf-part-1.gmi.tpl | 10 +- ...1-12-26-how-to-stay-sane-as-a-devops-person.gmi | 32 +- ...-26-how-to-stay-sane-as-a-devops-person.gmi.tpl | 130 +++ gemfeed/2022-01-01-bash-golf-part-2.gmi | 15 +- gemfeed/2022-01-01-bash-golf-part-2.gmi.tpl | 10 +- ...2022-02-04-computer-operating-systems-i-use.gmi | 7 +- ...-02-04-computer-operating-systems-i-use.gmi.tpl | 6 +- gemfeed/2022-03-06-the-release-of-dtail-4.0.0.gmi | 11 +- .../2022-03-06-the-release-of-dtail-4.0.0.gmi.tpl | 10 +- gemfeed/2022-04-10-creative-universe.gmi | 45 +- gemfeed/2022-04-10-creative-universe.gmi.tpl | 142 +++ .../2022-05-27-perl-is-still-a-great-choice.gmi | 25 +- ...2022-05-27-perl-is-still-a-great-choice.gmi.tpl | 10 +- gemfeed/2022-06-15-sweating-the-small-stuff.gmi | 41 +- .../2022-06-15-sweating-the-small-stuff.gmi.tpl | 330 +++++++ ...022-07-30-lets-encrypt-with-openbsd-and-rex.gmi | 7 +- ...07-30-lets-encrypt-with-openbsd-and-rex.gmi.tpl | 6 +- ...22-08-27-gemtexter-1.1.0-lets-gemtext-again.gmi | 15 +- ...8-27-gemtexter-1.1.0-lets-gemtext-again.gmi.tpl | 14 +- gemfeed/2022-09-30-after-a-bad-nights-sleep.gmi | 21 +- .../2022-09-30-after-a-bad-nights-sleep.gmi.tpl | 100 ++ gemfeed/2022-10-30-installing-dtail-on-openbsd.gmi | 27 +- .../2022-10-30-installing-dtail-on-openbsd.gmi.tpl | 26 +- ...i-tried-emacs-but-i-switched-back-to-neovim.gmi | 31 +- ...ied-emacs-but-i-switched-back-to-neovim.gmi.tpl | 117 +++ ...022-12-24-ultrarelearning-java-my-takeaways.gmi | 19 +- ...12-24-ultrarelearning-java-my-takeaways.gmi.tpl | 109 +++ gemfeed/2023-01-23-why-grapheneos-rox.gmi | 36 +- gemfeed/2023-01-23-why-grapheneos-rox.gmi.tpl | 143 +++ gemfeed/2023-02-26-how-to-shut-down-after-work.gmi | 13 +- .../2023-02-26-how-to-shut-down-after-work.gmi.tpl | 80 ++ ...-03-25-gemtexter-2.0.0-lets-gemtext-again-2.gmi | 19 +- ...25-gemtexter-2.0.0-lets-gemtext-again-2.gmi.tpl | 18 +- ...04-01-never-split-the-difference-book-notes.gmi | 15 + ...1-never-split-the-difference-book-notes.gmi.tpl | 2 + ...rithms-and-data-structures-in-golang-part-1.gmi | 15 +- ...ms-and-data-structures-in-golang-part-1.gmi.tpl | 14 +- gemfeed/2023-05-01-unveiling-guprecords | 1 + ...23-05-06-the-obstacle-is-the-way-book-notes.gmi | 32 +- ...5-06-the-obstacle-is-the-way-book-notes.gmi.tpl | 7 +- ...23-06-01-kiss-server-monitoring-with-gogios.gmi | 15 +- ...6-01-kiss-server-monitoring-with-gogios.gmi.tpl | 10 +- ...-17-career-guide-and-soft-skills-book-notes.gmi | 55 +- ...career-guide-and-soft-skills-book-notes.gmi.tpl | 18 +- ...-07-21-gemtexter-2.1.0-lets-gemtext-again-3.gmi | 11 +- ...21-gemtexter-2.1.0-lets-gemtext-again-3.gmi.tpl | 10 +- gemfeed/2023-09-25-dtail-usage-examples.gmi | 32 +- gemfeed/2023-09-25-dtail-usage-examples.gmi.tpl | 8 +- ...-static-web-photo-albums-with-photoalbum.sh.gmi | 15 +- ...tic-web-photo-albums-with-photoalbum.sh.gmi.tpl | 14 +- gemfeed/2023-11-11-mind-management-book-notes.gmi | 30 +- .../2023-11-11-mind-management-book-notes.gmi.tpl | 8 +- gemfeed/2023-12-10-bash-golf-part-3.gmi | 15 +- gemfeed/2023-12-10-bash-golf-part-3.gmi.tpl | 10 +- ...24-02-04-from-babylon5.buetow.org-to-.cloud.gmi | 17 + ...2-04-from-babylon5.buetow.org-to-.cloud.gmi.tpl | 165 ++++ ...-quickly-logging-ideas-programmed-in-golang.gmi | 16 +- ...ckly-logging-ideas-programmed-in-golang.gmi.tpl | 8 +- ...4-04-01-KISS-high-availability-with-OpenBSD.gmi | 19 +- ...-01-KISS-high-availability-with-OpenBSD.gmi.tpl | 18 +- .../2024-05-01-slow-productivity-book-notes.gmi | 24 +- ...2024-05-01-slow-productivity-book-notes.gmi.tpl | 8 +- ...-03-projects-i-currently-dont-have-time-for.gmi | 7 +- ...projects-i-currently-dont-have-time-for.gmi.tpl | 6 +- .../2024-06-23-terminal-multiplexing-with-tmux.gmi | 22 +- ...4-06-23-terminal-multiplexing-with-tmux.gmi.tpl | 20 +- gemfeed/2024-07-05-random-weird-things.gmi | 25 +- gemfeed/2024-07-05-random-weird-things.gmi.tpl | 6 +- .../2024-07-07-the-stoic-challenge-book-notes.gmi | 18 +- ...24-07-07-the-stoic-challenge-book-notes.gmi.tpl | 8 +- .../2024-08-05-typing-127.1-words-per-minute.gmi | 19 +- ...024-08-05-typing-127.1-words-per-minute.gmi.tpl | 18 +- gemfeed/DRAFT-site-reliability-engineering.gmi.tpl | 152 +++ gemfeed/atom.xml | 1010 +++++++++++--------- index.gmi | 2 +- notes/a-monks-guide-to-happiness.gmi | 11 + notes/a-monks-guide-to-happiness.gmi.tpl | 69 ++ notes/career-guide-and-soft-skills.gmi | 55 +- notes/influence-wihout-authority.gmi | 10 + notes/influence-wihout-authority.gmi.tpl | 2 + notes/mind-management.gmi | 30 +- notes/never-split-the-difference.gmi | 15 + notes/slow-productivity.gmi | 24 +- notes/the-obstacle-is-the-way.gmi | 32 +- notes/the-power-of-neuroplasticity.gmi | 13 + notes/the-power-of-neuroplasticity.gmi.tpl | 2 + notes/the-stoic-challenge.gmi | 18 +- uptime-stats.gmi | 2 +- 119 files changed, 4636 insertions(+), 1180 deletions(-) create mode 100644 gemfeed/2010-04-09-standard-ml-and-haskell.gmi.tpl create mode 100644 gemfeed/2010-05-09-the-fype-programming-language.gmi.tpl create mode 100644 gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi.tpl create mode 100644 gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi.tpl create mode 100644 gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi.tpl create mode 100644 gemfeed/2021-07-04-the-well-grounded-rubyist.gmi.tpl create mode 100644 gemfeed/2021-08-01-on-being-pedantic-about-open-source.gmi.tpl create mode 100644 gemfeed/2021-10-22-defensive-devops.gmi.tpl create mode 100644 gemfeed/2021-12-26-how-to-stay-sane-as-a-devops-person.gmi.tpl create mode 100644 gemfeed/2022-04-10-creative-universe.gmi.tpl create mode 100644 gemfeed/2022-06-15-sweating-the-small-stuff.gmi.tpl create mode 100644 gemfeed/2022-09-30-after-a-bad-nights-sleep.gmi.tpl create mode 100644 gemfeed/2022-11-24-i-tried-emacs-but-i-switched-back-to-neovim.gmi.tpl create mode 100644 gemfeed/2022-12-24-ultrarelearning-java-my-takeaways.gmi.tpl create mode 100644 gemfeed/2023-01-23-why-grapheneos-rox.gmi.tpl create mode 100644 gemfeed/2023-02-26-how-to-shut-down-after-work.gmi.tpl create mode 100644 gemfeed/2024-02-04-from-babylon5.buetow.org-to-.cloud.gmi.tpl create mode 100644 gemfeed/DRAFT-site-reliability-engineering.gmi.tpl create mode 100644 notes/a-monks-guide-to-happiness.gmi.tpl diff --git a/gemfeed/2008-06-26-perl-poetry.gmi b/gemfeed/2008-06-26-perl-poetry.gmi index 536c9c50..a8345a71 100644 --- a/gemfeed/2008-06-26-perl-poetry.gmi +++ b/gemfeed/2008-06-26-perl-poetry.gmi @@ -2,6 +2,12 @@ > Published at 2008-06-26T21:43:51+01:00; Updated at 2021-05-04 +Here are some Perl Poems I wrote. They don't do anything useful when you run them, but they don't produce a compiler error either. They only exist for fun and demonstrate what you can do with Perl syntax. + +Wikipedia: "Perl poetry is the practice of writing poems that can be compiled as legal Perl code, for example the piece known as Black Perl. Perl poetry is made possible by the large number of English words that are used in the Perl language. New poems are regularly submitted to the community at PerlMonks." + +=> https://en.wikipedia.org/wiki/Perl + ``` '\|/' * -- * ----- @@ -28,20 +34,11 @@ _~~|~/_|_|__/|~~~~~~~ | / ~~~~~ | | ~~~~~~~~ ## Table of Contents * ⇢ Perl Poetry -* ⇢ ⇢ Introduction * ⇢ ⇢ math.pl * ⇢ ⇢ christmas.pl * ⇢ ⇢ shopping.pl * ⇢ ⇢ More... -## Introduction - -Here are some Perl Poems I wrote. They don't do anything useful when you run them, but they don't produce a compiler error either. They only exist for fun and demonstrate what you can do with Perl syntax. - -Wikipedia: "Perl poetry is the practice of writing poems that can be compiled as legal Perl code, for example the piece known as Black Perl. Perl poetry is made possible by the large number of English words that are used in the Perl language. New poems are regularly submitted to the community at PerlMonks." - -=> https://en.wikipedia.org/wiki/Perl - ## math.pl ```perl diff --git a/gemfeed/2008-06-26-perl-poetry.gmi.tpl b/gemfeed/2008-06-26-perl-poetry.gmi.tpl index 01636b3d..903c5c6e 100644 --- a/gemfeed/2008-06-26-perl-poetry.gmi.tpl +++ b/gemfeed/2008-06-26-perl-poetry.gmi.tpl @@ -2,6 +2,12 @@ > Published at 2008-06-26T21:43:51+01:00; Updated at 2021-05-04 +Here are some Perl Poems I wrote. They don't do anything useful when you run them, but they don't produce a compiler error either. They only exist for fun and demonstrate what you can do with Perl syntax. + +Wikipedia: "Perl poetry is the practice of writing poems that can be compiled as legal Perl code, for example the piece known as Black Perl. Perl poetry is made possible by the large number of English words that are used in the Perl language. New poems are regularly submitted to the community at PerlMonks." + +=> https://en.wikipedia.org/wiki/Perl + ``` '\|/' * -- * ----- @@ -27,14 +33,6 @@ _~~|~/_|_|__/|~~~~~~~ | / ~~~~~ | | ~~~~~~~~ << template::inline::toc -## Introduction - -Here are some Perl Poems I wrote. They don't do anything useful when you run them, but they don't produce a compiler error either. They only exist for fun and demonstrate what you can do with Perl syntax. - -Wikipedia: "Perl poetry is the practice of writing poems that can be compiled as legal Perl code, for example the piece known as Black Perl. Perl poetry is made possible by the large number of English words that are used in the Perl language. New poems are regularly submitted to the community at PerlMonks." - -=> https://en.wikipedia.org/wiki/Perl - ## math.pl ```perl diff --git a/gemfeed/2010-04-09-standard-ml-and-haskell.gmi b/gemfeed/2010-04-09-standard-ml-and-haskell.gmi index 844fd595..17bd4651 100644 --- a/gemfeed/2010-04-09-standard-ml-and-haskell.gmi +++ b/gemfeed/2010-04-09-standard-ml-and-haskell.gmi @@ -8,6 +8,16 @@ As you will see, SML and Haskell are very similar (at least when it comes to the Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages, but here are a few functions implemented in both SML and Haskell: +## Table of Contents + +* ⇢ Standard ML and Haskell +* ⇢ ⇢ Defining a multi-data type +* ⇢ ⇢ Processing a multi +* ⇢ ⇢ Simplify function +* ⇢ ⇢ Delete all +* ⇢ ⇢ Delete one +* ⇢ ⇢ Higher-order functions + ## Defining a multi-data type Standard ML: diff --git a/gemfeed/2010-04-09-standard-ml-and-haskell.gmi.tpl b/gemfeed/2010-04-09-standard-ml-and-haskell.gmi.tpl new file mode 100644 index 00000000..a3d3ed79 --- /dev/null +++ b/gemfeed/2010-04-09-standard-ml-and-haskell.gmi.tpl @@ -0,0 +1,176 @@ +# Standard ML and Haskell + +> Published at 2010-04-09T22:57:36+01:00 + +I am currently looking into the functional programming language Standard ML (aka SML). The purpose is to refresh my functional programming skills and to learn something new too. Since I already knew a little Haskell, I could not help myself, and I also implemented the same exercises in Haskell. + +As you will see, SML and Haskell are very similar (at least when it comes to the basics). However, the syntax of Haskell is a bit more "advanced". Haskell utilizes fewer keywords (e.g. no val, end, fun, fn ...). Haskell also allows to write down the function types explicitly. What I have been missing in SML so far is the so-called pattern guards. Although this is a very superficial comparison for now, so far, I like Haskell more than SML. Nevertheless, I thought it would be fun to demonstrate a few simple functions of both languages to show off the similarities. + +Haskell is also a "pure functional" programming language, whereas SML also makes explicit use of imperative concepts. I am by far not a specialist in either of these languages, but here are a few functions implemented in both SML and Haskell: + +<< template::inline::toc + +## Defining a multi-data type + +Standard ML: + +```sml +datatype ’a multi + = EMPTY + | ELEM of ’a + | UNION of ’a multi * ’a multi +``` + +Haskell: + +```haskell +data (Eq a) => Multi a + = Empty + | Elem a + | Union (Multi a) (Multi a) + deriving Show +``` + +## Processing a multi + +Standard ML: + +```sml +fun number (EMPTY) _ = 0 + | number (ELEM x) w = if x = w then 1 else 0 + | number (UNION (x,y)) w = (number x w) + (number y w) +fun test_number w = number (UNION (EMPTY, \ + UNION (ELEM 4, UNION (ELEM 6, \ + UNION (UNION (ELEM 4, ELEM 4), EMPTY))))) w +``` + +Haskell: + +```haskell +number Empty _ = 0 +number (Elem x) w = if x == w then 1 else 0 +test_number w = number (Union Empty \ + (Union (Elem 4) (Union (Elem 6) \ + (Union (Union (Elem 4) (Elem 4)) Empty)))) w +``` + +## Simplify function + +Standard ML: + +```sml +fun simplify (UNION (x,y)) = + let fun is_empty (EMPTY) = true | is_empty _ = false + val x’ = simplify x + val y’ = simplify y + in if (is_empty x’) andalso (is_empty y’) + then EMPTY + else if (is_empty x’) + then y’ + else if (is_empty y’) + then x’ + else UNION (x’, y’) + end + | simplify x = x +``` + +Haskell: + +```haskell +simplify (Union x y) + | (isEmpty x’) && (isEmpty y’) = Empty + | isEmpty x’ = y’ + | isEmpty y’ = x’ + | otherwise = Union x’ y’ + where + isEmpty Empty = True + isEmpty _ = False + x’ = simplify x + y’ = simplify y +simplify x = x +``` + +## Delete all + +Standard ML: + +```sml +fun delete_all m w = + let fun delete_all’ (ELEM x) = if x = w then EMPTY else ELEM x + | delete_all’ (UNION (x,y)) = UNION (delete_all’ x, delete_all’ y) + | delete_all’ x = x + in simplify (delete_all’ m) + end +``` + +Haskell: + +```haskell +delete_all m w = simplify (delete_all’ m) + where + delete_all’ (Elem x) = if x == w then Empty else Elem x + delete_all’ (Union x y) = Union (delete_all’ x) (delete_all’ y) + delete_all’ x = x +``` + +## Delete one + +Standard ML: + +```sml +fun delete_one m w = + let fun delete_one’ (UNION (x,y)) = + let val (x’, deleted) = delete_one’ x + in if deleted + then (UNION (x’, y), deleted) + else let val (y’, deleted) = delete_one’ y + in (UNION (x, y’), deleted) + end + end + | delete_one’ (ELEM x) = + if x = w then (EMPTY, true) else (ELEM x, false) + | delete_one’ x = (x, false) + val (m’, _) = delete_one’ m + in simplify m’ + end +``` + +Haskell: + +```haskell +delete_one m w = do + let (m’, _) = delete_one’ m + simplify m’ + where + delete_one’ (Union x y) = + let (x’, deleted) = delete_one’ x + in if deleted + then (Union x’ y, deleted) + else let (y’, deleted) = delete_one’ y + in (Union x y’, deleted) + delete_one’ (Elem x) = + if x == w then (Empty, True) else (Elem x, False) + delete_one’ x = (x, False) +``` + +## Higher-order functions + +The first line is always the SML code, the second line the Haskell variant: + +``` +fun make_map_fn f1 = fn (x,y) => f1 x :: y +make_map_fn f1 = \x y -> f1 x : y + +fun make_filter_fn f1 = fn (x,y) => if f1 x then x :: y else y +make_filter_fn f1 = \x y -> if f1 then x : y else y + +fun my_map f l = foldr (make_map_fn f) [] l +my_map f l = foldr (make_map_fn f) [] l + +fun my_filter f l = foldr (make_filter_fn f) [] l +my_filter f l = foldr (make_filter_fn f) [] l +``` + +E-Mail your comments to `paul@nospam.buetow.org` :-) + +=> ../ Back to the main site diff --git a/gemfeed/2010-05-09-the-fype-programming-language.gmi b/gemfeed/2010-05-09-the-fype-programming-language.gmi index 5f847c35..b77d49fa 100644 --- a/gemfeed/2010-05-09-the-fype-programming-language.gmi +++ b/gemfeed/2010-05-09-the-fype-programming-language.gmi @@ -2,6 +2,12 @@ > Published at 2010-05-09T12:48:29+01:00; Updated at 2021-05-05 +Fype is an interpreted programming language created by me for learning and fun. The interpreter is written in C. It has been tested on FreeBSD and NetBSD and may also work on other Unix like operating systems such as Linux based ones. Besides learning and fun, there is no other use case of why Fype exists as many other programming languages are much faster and more powerful. + +The Fype syntax is straightforward and uses a maximum look ahead of 1 and an effortless top-down parsing mechanism. Fype is parsing and interpreting its code simultaneously. This means that syntax errors are only detected during program runtime. + +Fype is a recursive acronym and means "Fype is For Your Program Execution" or "Fype is Free Yak Programmed for ELF". You could also say, "It's not a hype - it's Fype!". + ``` ____ _ __ / / _|_ _ _ __ ___ _ _ ___ __ _| |__ / _|_ _ @@ -11,11 +17,33 @@ |___/|_| |___/ |___/ ``` -Fype is an interpreted programming language created by me for learning and fun. The interpreter is written in C. It has been tested on FreeBSD and NetBSD and may also work on other Unix like operating systems such as Linux based ones. Besides learning and fun, there is no other use case of why Fype exists as many other programming languages are much faster and more powerful. - -The Fype syntax is straightforward and uses a maximum look ahead of 1 and an effortless top-down parsing mechanism. Fype is parsing and interpreting its code simultaneously. This means that syntax errors are only detected during program runtime. - -Fype is a recursive acronym and means "Fype is For Your Program Execution" or "Fype is Free Yak Programmed for ELF". You could also say, "It's not a hype - it's Fype!". +## Table of Contents + +* ⇢ The Fype Programming Language +* ⇢ ⇢ Object-oriented C style +* ⇢ ⇢ Data types +* ⇢ ⇢ Syntax +* ⇢ ⇢ ⇢ Comments +* ⇢ ⇢ ⇢ Variables +* ⇢ ⇢ ⇢ Synonyms +* ⇢ ⇢ Statements and expressions +* ⇢ ⇢ ⇢ Parenthesis +* ⇢ ⇢ ⇢ Basic expressions +* ⇢ ⇢ ⇢ Bitwise expressions +* ⇢ ⇢ ⇢ Numeric expressions +* ⇢ ⇢ Control statements +* ⇢ ⇢ Scopes +* ⇢ ⇢ Definedness +* ⇢ ⇢ System +* ⇢ ⇢ ⇢ I/O +* ⇢ ⇢ Procedures and functions +* ⇢ ⇢ ⇢ Procedures +* ⇢ ⇢ ⇢ Nested procedures +* ⇢ ⇢ ⇢ Functions +* ⇢ ⇢ ⇢ Nested functions +* ⇢ ⇢ Arrays +* ⇢ ⇢ Fancy stuff +* ⇢ ⇢ May the source be with you ## Object-oriented C style diff --git a/gemfeed/2010-05-09-the-fype-programming-language.gmi.tpl b/gemfeed/2010-05-09-the-fype-programming-language.gmi.tpl new file mode 100644 index 00000000..d4dac222 --- /dev/null +++ b/gemfeed/2010-05-09-the-fype-programming-language.gmi.tpl @@ -0,0 +1,512 @@ +# The Fype Programming Language + +> Published at 2010-05-09T12:48:29+01:00; Updated at 2021-05-05 + +Fype is an interpreted programming language created by me for learning and fun. The interpreter is written in C. It has been tested on FreeBSD and NetBSD and may also work on other Unix like operating systems such as Linux based ones. Besides learning and fun, there is no other use case of why Fype exists as many other programming languages are much faster and more powerful. + +The Fype syntax is straightforward and uses a maximum look ahead of 1 and an effortless top-down parsing mechanism. Fype is parsing and interpreting its code simultaneously. This means that syntax errors are only detected during program runtime. + +Fype is a recursive acronym and means "Fype is For Your Program Execution" or "Fype is Free Yak Programmed for ELF". You could also say, "It's not a hype - it's Fype!". + +``` + ____ _ __ + / / _|_ _ _ __ ___ _ _ ___ __ _| |__ / _|_ _ + / / |_| | | | '_ \ / _ \ | | | |/ _ \/ _` | '_ \ | |_| | | | + _ / /| _| |_| | |_) | __/ | |_| | __/ (_| | | | |_| _| |_| | +(_)_/ |_| \__, | .__/ \___| \__, |\___|\__,_|_| |_(_)_| \__, | + |___/|_| |___/ |___/ +``` + +<< template::inline::toc + +## Object-oriented C style + +The Fype interpreter is written in an object-oriented style of C. Each "main component" has its own .h and .c file. There is a struct type for each (most components at least) component, which can be initialized using a "COMPONENT_new" function and destroyed using a "COMPONENT_delete" function. Method calls follow the same schema, e.g. "COMPONENT_METHODNAME". There is no such as class inheritance and polymorphism involved. + +To give you an idea of how it works here as an example is a snippet from the main Fype "class header": + +```c +typedef struct { + Tupel *p_tupel_argv; // Contains command line options + List *p_list_token; // Initial list of token + Hash *p_hash_syms; // Symbol table + char *c_basename; +} Fype; +``` + +And here is a snippet from the primary Fype "class implementation": + +```c +Fype* +fype_new() { + Fype *p_fype = malloc(sizeof(Fype)); + + p_fype->p_hash_syms = hash_new(512); + p_fype->p_list_token = list_new(); + p_fype->p_tupel_argv = tupel_new(); + p_fype->c_basename = NULL; + + garbage_init(); + + return (p_fype); +} + +void +fype_delete(Fype *p_fype) { + argv_tupel_delete(p_fype->p_tupel_argv); + + hash_iterate(p_fype->p_hash_syms, symbol_cleanup_hash_syms_cb); + hash_delete(p_fype->p_hash_syms); + + list_iterate(p_fype->p_list_token, token_ref_down_cb); + list_delete(p_fype->p_list_token); + + if (p_fype->c_basename) + free(p_fype->c_basename); + + garbage_destroy(); +} + +int +fype_run(int i_argc, char **pc_argv) { + Fype *p_fype = fype_new(); + + // argv: Maintains command line options + argv_run(p_fype, i_argc, pc_argv); + + // scanner: Creates a list of token + scanner_run(p_fype); + + // interpret: Interpret the list of token + interpret_run(p_fype); + + fype_delete(p_fype); + + return (0); +} +``` + +## Data types + +Fype uses auto type conversion. However, if you want to know what's going on, you may take a look at the following basic data types: +* integer - Specifies a number +* double - Specifies a double-precision number +* string - Specifies a string +* number - May be an integer or a double number +* any- May be any type above +* void - No type +* identifier - It's a variable name or a procedure name, or a function name + +There is no boolean type, but we can use the integer values 0 for false and 1 for true. There is support for explicit type casting too. + +## Syntax + +### Comments + +Text from a # character until the end of the current line is considered being a comment. Multi-line comments may start with an #* and with a *# anywhere. Exceptions are if those signs are inside of strings. + +### Variables + +Variables are defined with the "my" keyword (inspired by Perl :-). If you don't assign a value during declaration, it uses the default integer value 0. Variables may be changed during program runtime. Variables may be deleted using the "undef" keyword! Example: + +``` +my foo = 1 + 2; +say foo; + +my bar = 12, baz = foo; +say 1 + bar; +say bar; + +my baz; +say baz; # Will print out 0 +``` + +You may use the "defined" keyword to check if an identifier has been defined or not: + +``` +ifnot defined foo { + say "No foo yet defined"; +} + +my foo = 1; + +if defined foo { + put "foo is defined and has the value "; + say foo; +} +``` + +### Synonyms + +Each variable can have as many synonyms as wished. A synonym is another name to access the content of a specific variable. Here is an example of how to use it: + +``` +my foo = "foo"; +my bar = \foo; +foo = "bar"; + +# The synonym variable should now also set to "bar" +assert "bar" == bar; +``` + +Synonyms can be used for all kind of identifiers. It's not limited to standard variables but can also be used for function and procedure names (more about functions and procedures later). + +``` +# Create a new procedure baz +proc baz { say "I am baz"; } + +# Make a synonym baz, and undefine baz +my bay = \baz; + +undef baz; + +# bay still has a reference of the original procedure baz +bay; # this prints aut "I am baz" +``` + +The "syms" keyword gives you the total number of synonyms pointing to a specific value: + +``` +my foo = 1; +say syms foo; # Prints 1 + +my baz = \foo; +say syms foo; # Prints 2 +say syms baz; # Prints 2 + +undef baz; +say syms foo; # Prints 1 +``` + +## Statements and expressions + +A Fype program is a list of statements. Each keyword, expression or function call is part of a statement. Each statement is ended with a semicolon. Example: + +``` +my bar = 3, foo = 1 + 2; +say foo; +exit foo - bar; +``` + +### Parenthesis + +All parenthesis for function arguments is optional. They help to make the code better readable. They also help to force the precedence of expressions. + +### Basic expressions + +Any "any" value holding a string will be automatically converted to an integer value. + +``` +(any) + +(any) - +(any) * +(any) / +(integer) == +(integer) != +(integer) <= +(integer) gt +(integer) <> +(integer) gt +(integer) not +``` + +### Bitwise expressions + +``` +(integer) :< +(integer) :> +(integer) and +(integer) or +(integer) xor +``` + +### Numeric expressions + +``` +(number) neg +``` + +... returns the negative value of "number": + +``` +(integer) no +``` + +... returns 1 if the argument is 0; otherwise, it will return 0! If no argument is given, then 0 is returned! + +``` +(integer) yes +``` + +... always returns 1. The parameter is optional. Example: + +``` +# Prints out 1, because foo is not defined +if yes { say no defined foo; } +``` + +## Control statements + +Control statements available in Fype: + +``` +if { } +``` + +... runs the statements if the expression evaluates to a true value. + +``` +ifnot { } +``` + +... runs the statements if the expression evaluates to a false value. + +``` +while { } +``` + +... runs the statements as long as the expression evaluates to a true value. + +``` +until { } +``` + +... runs the statements as long as the expression evaluates to a false value. + +## Scopes + +A new scope starts with an { and ends with an }. An exception is a procedure, which does not use its own scope (see later in this manual). Control statements and functions support scopes. The "scope" function prints out all available symbols at the current scope. Here is a small example: + +``` +my foo = 1; + +{ + # Prints out 1 + put defined foo; + { + my bar = 2; + + # Prints out 1 + put defined bar; + + # Prints out all available symbols at this + # point to stdout. Those are: bar and foo + scope; + } + + # Prints out 0 + put defined bar; + + my baz = 3; +} + +# Prints out 0 +say defined bar; +``` + +Another example including an actual output: + +``` +./fype -e ’my global; func foo { my var4; func bar { my var2, var3; func baz { my var1; scope; } baz; } bar; } foo;’ +Scopes: +Scope stack size: 3 +Global symbols: +SYM_VARIABLE: global (id=00034, line=-0001, pos=-001, type=TT_INTEGER, dval=0.000000, refs=-1) +SYM_FUNCTION: foo +Local symbols: +SYM_VARIABLE: var1 (id=00038, line=-0001, pos=-001, type=TT_INTEGER, dval=0.000000, refs=-1) +1 level(s) up: +SYM_VARIABLE: var2 (id=00036, line=-0001, pos=-001, type=TT_INTEGER, dval=0.000000, refs=-1) +SYM_VARIABLE: var3 (id=00037, line=-0001, pos=-001, type=TT_INTEGER, dval=0.000000, refs=-1) +SYM_FUNCTION: baz +2 level(s) up: +SYM_VARIABLE: var4 (id=00035, line=-0001, pos=-001, type=TT_INTEGER, dval=0.000000, refs=-1) +SYM_FUNCTION: bar +``` + +## Definedness + +``` +(integer) defined +``` + +... returns 1 if "identifier" has been defined. Returns 0 otherwise. + +``` +(integer) undef +``` + +... tries to undefine/delete the "identifier". Returns 1 if it succeeded, otherwise 0 is returned. + +## System + +These are some system and interpreter specific built-in functions supported: + +``` +(void) end +``` + +... exits the program with the exit status of 0. + +``` +(void) exit +``` + +... exits the program with the specified exit status. + +``` +(integer) fork +``` + +... forks a subprocess. It returns 0 for the child process and the PID of the child process otherwise! Example: + +``` +my pid = fork; + +if pid { + put "I am the parent process; child has the pid "; + say pid; + +} ifnot pid { + say "I am the child process"; +} +``` + +To execute the garbage collector do: + +``` +(integer) GC +``` + +It returns the number of items freed! You may wonder why most of the time, it will produce a value of 0! Fype tries to free not needed memory ASAP. This may change in future versions to gain faster execution speed! + +### I/O + +``` +(any) put +``` + +... prints out the argument + +``` +(any) say +``` + +is the same as put, but also includes an ending newline. + +``` +(void) ln +``` + +... just prints a new line. + +## Procedures and functions + +### Procedures + +A procedure can be defined with the "proc" keyword and deleted with the "undef" keyword. A procedure does not return any value and does not support parameter passing. It's using already defined variables (e.g. global variables). A procedure does not have its own namespace. It's using the calling namespace. It is possible to define new variables inside of a procedure in the current namespace. + +``` +proc foo { + say 1 + a * 3 + b; + my c = 6; +} + +my a = 2, b = 4; + +foo; # Run the procedure. Print out "11\n" +say c; # Print out "6\n"; +``` + +### Nested procedures + +It's possible to define procedures inside of procedures. Since procedures don't have their own scope, nested procedures will be available to the current scope as soon as the main procedure has run the first time. You may use the "defined" keyword to check if a procedure has been defined or not. + +``` +proc foo { + say "I am foo"; + + undef bar; + proc bar { + say "I am bar"; + } +} + +# Here bar would produce an error because +# the proc is not yet defined! +# bar; + +foo; # Here the procedure foo will define the procedure bar! +bar; # Now the procedure bar is defined! +foo; # Here the procedure foo will redefine bar again! +``` + +### Functions + +A function can be defined with the "func" keyword and deleted with the "undef" keyword. Function do not yet return values and do not yet supports parameter passing. It's using local (lexical scoped) variables. If a certain variable does not exist, when It's using already defined variables (e.g. one scope above). + +``` +func foo { + say 1 + a * 3 + b; + my c = 6; +} + +my a = 2, b = 4; + +foo; # Run the procedure. Print out "11\n" +say c; # Will produce an error because c is out of scope! +``` + +### Nested functions + +Nested functions work the same way the nested procedures work, except that nested functions will not be available anymore after the function has been left! + +``` +func foo { + func bar { + say "Hello i am nested"; + } + + bar; # Calling nested +} + +foo; +bar; # Will produce an error because bar is out of scope! +``` + +## Arrays + +Some progress on arrays has been made too. The following example creates a multidimensional array "foo". Its first element is the return value of the func which is "bar". The fourth value is a string" 3" converted to a double number. The last element is an anonymous array which itself contains another anonymous array as its final element: + +``` +func bar { say ”bar” } +my foo = [bar, 1, 4/2, double ”3”, [”A”, [”BA”, ”BB”]]]; +say foo; +``` + +It produces the following output: + +``` +% ./fype arrays.fy +bar +01 +2 +3.000000 +A +BA +BB +``` + +## Fancy stuff + +Fancy stuff like OOP or Unicode or threading is not planed. But fancy stuff like function pointers and closures may be considered.:) + +## May the source be with you + +You can find all of this on the GitHub page. There is also an "examples" folders containing some Fype scripts! + +=> https://codeberg.org/snonux/fype + +E-Mail your comments to `paul@nospam.buetow.org` :-) + +=> ../ Back to the main site diff --git a/gemfeed/2011-05-07-perl-daemon-service-framework.gmi b/gemfeed/2011-05-07-perl-daemon-service-framework.gmi index 78c79a9e..0891101c 100644 --- a/gemfeed/2011-05-07-perl-daemon-service-framework.gmi +++ b/gemfeed/2011-05-07-perl-daemon-service-framework.gmi @@ -2,6 +2,8 @@ > Published at 2011-05-07T22:26:02+01:00; Updated at 2021-05-07 +PerlDaemon is a minimal daemon for Linux and other Unix like operating systems programmed in Perl. It is a minimal but pretty functional and fairly generic service framework. This means that it does not do anything useful other than providing a framework for starting, stopping, configuring and logging. To do something useful, a module (written in Perl) must be provided. + ``` a'! _,,_ a'! _,,_ a'! _,,_ \\_/ \ \\_/ \ \\_/ \.-, @@ -12,7 +14,6 @@ ## Table of Contents * ⇢ Perl Daemon (Service Framework) -* ⇢ ⇢ Introduction * ⇢ ⇢ Features * ⇢ ⇢ Quick Guide * ⇢ ⇢ How to configure @@ -23,10 +24,6 @@ * ⇢ ⇢ ⇢ Your own module * ⇢ ⇢ May the source be with you -## Introduction - -PerlDaemon is a minimal daemon for Linux and other Unix like operating systems programmed in Perl. It is a minimal but pretty functional and fairly generic service framework. This means that it does not do anything useful other than providing a framework for starting, stopping, configuring and logging. To do something useful, a module (written in Perl) must be provided. - ## Features PerlDaemon supports: diff --git a/gemfeed/2011-05-07-perl-daemon-service-framework.gmi.tpl b/gemfeed/2011-05-07-perl-daemon-service-framework.gmi.tpl index f7baa258..eba46212 100644 --- a/gemfeed/2011-05-07-perl-daemon-service-framework.gmi.tpl +++ b/gemfeed/2011-05-07-perl-daemon-service-framework.gmi.tpl @@ -2,6 +2,8 @@ > Published at 2011-05-07T22:26:02+01:00; Updated at 2021-05-07 +PerlDaemon is a minimal daemon for Linux and other Unix like operating systems programmed in Perl. It is a minimal but pretty functional and fairly generic service framework. This means that it does not do anything useful other than providing a framework for starting, stopping, configuring and logging. To do something useful, a module (written in Perl) must be provided. + ``` a'! _,,_ a'! _,,_ a'! _,,_ \\_/ \ \\_/ \ \\_/ \.-, @@ -11,10 +13,6 @@ << template::inline::toc -## Introduction - -PerlDaemon is a minimal daemon for Linux and other Unix like operating systems programmed in Perl. It is a minimal but pretty functional and fairly generic service framework. This means that it does not do anything useful other than providing a framework for starting, stopping, configuring and logging. To do something useful, a module (written in Perl) must be provided. - ## Features PerlDaemon supports: diff --git a/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi index f31ba96b..9328b1bf 100644 --- a/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi +++ b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi @@ -2,6 +2,12 @@ > Published at 2015-12-05T16:12:57+00:00; Updated at 2021-05-16 +You can use the following tutorial to install a full-blown Debian GNU/Linux Chroot on an LG G3 D855 CyanogenMod 13 (Android 6). First of all, you need to have root permissions on your phone, and you also need to have the developer mode activated. The following steps have been tested on Linux (Fedora 23). + +=> ./run-debian-on-your-phone-with-debroid/Deboroid.png + +A couple of years have passed since I last worked on Debroid. Currently, I am using the Termux app on Android, which is less sophisticated than a fully blown Debian installation but sufficient for my current requirements. The content of this site may be still relevant, and it would also work with more recent versions of Debian and Android. I would expect that some minor modifications need to be made, though. + ``` ____ _ _ _ | _ \ ___| |__ _ __ ___ (_) __| | @@ -11,13 +17,16 @@ ``` -You can use the following tutorial to install a full-blown Debian GNU/Linux Chroot on an LG G3 D855 CyanogenMod 13 (Android 6). First of all, you need to have root permissions on your phone, and you also need to have the developer mode activated. The following steps have been tested on Linux (Fedora 23). - -=> ./run-debian-on-your-phone-with-debroid/Deboroid.png +## Table of Contents -## Foreword - -A couple of years have passed since I last worked on Debroid. Currently, I am using the Termux app on Android, which is less sophisticated than a fully blown Debian installation but sufficient for my current requirements. The content of this site may be still relevant, and it would also work with more recent versions of Debian and Android. I would expect that some minor modifications need to be made, though. +* ⇢ Run Debian on your phone with Debroid +* ⇢ ⇢ Step by step guide +* ⇢ ⇢ ⇢ First debootstrap stage +* ⇢ ⇢ ⇢ Copy Debian image to the phone +* ⇢ ⇢ ⇢ Second debootstrap stage +* ⇢ ⇢ ⇢ Setup of various scripts +* ⇢ ⇢ ⇢ Entering Debroid and enable a service +* ⇢ ⇢ ⇢ Include to Android startup: ## Step by step guide diff --git a/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi.tpl b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi.tpl new file mode 100644 index 00000000..40539e7f --- /dev/null +++ b/gemfeed/2015-12-05-run-debian-on-your-phone-with-debroid.gmi.tpl @@ -0,0 +1,180 @@ +# Run Debian on your phone with Debroid + +> Published at 2015-12-05T16:12:57+00:00; Updated at 2021-05-16 + +You can use the following tutorial to install a full-blown Debian GNU/Linux Chroot on an LG G3 D855 CyanogenMod 13 (Android 6). First of all, you need to have root permissions on your phone, and you also need to have the developer mode activated. The following steps have been tested on Linux (Fedora 23). + +=> ./run-debian-on-your-phone-with-debroid/Deboroid.png + +A couple of years have passed since I last worked on Debroid. Currently, I am using the Termux app on Android, which is less sophisticated than a fully blown Debian installation but sufficient for my current requirements. The content of this site may be still relevant, and it would also work with more recent versions of Debian and Android. I would expect that some minor modifications need to be made, though. + +``` + ____ _ _ _ +| _ \ ___| |__ _ __ ___ (_) __| | +| | | |/ _ \ '_ \| '__/ _ \| |/ _` | +| |_| | __/ |_) | | | (_) | | (_| | +|____/ \___|_.__/|_| \___/|_|\__,_| + +``` + +<< template::inline::toc + +## Step by step guide + +All scripts mentioned here can be found on GitHub at: + +=> https://codeberg.org/snonux/debroid + +### First debootstrap stage + +This is to be performed on a Fedora Linux machine (could work on a Debian too, but Fedora is just what I use on my Laptop). The following steps prepare an initial Debian base image, which can then be transferred to the phone. + +```sh +sudo dnf install debootstrap +# 5g +dd if=/dev/zero of=jessie.img bs=$[ 1024 * 1024 ] \ + count=$[ 1024 * 5 ] + +# Show used loop devices +sudo losetup -f +# Store the next free one to $loop +loop=loopN +sudo losetup /dev/$loop jessie.img + +mkdir jessie +sudo mkfs.ext4 /dev/$loop +sudo mount /dev/$loop jessie +sudo debootstrap --foreign --variant=minbase \ + --arch armel jessie jessie/ \ + http://http.debian.net/debian +sudo umount jessie +``` + +### Copy Debian image to the phone + +Now setup the Debian image on an external SD card on the Phone via Android Debugger as follows: + +```sh +adb root && adb wait-for-device && adb shell +mkdir -p /storage/sdcard1/Linux/jessie +exit + +# Sparse image problem, may be too big for copying otherwise +gzip jessie.img +# Copy over +adb push jessie.img.gz /storage/sdcard1/Linux/jessie.img.gz +adb shell +cd /storage/sdcard1/Linux +gunzip jessie.img.gz + +# Show used loop devices +losetup -f +# Store the next free one to $loop +loop=loopN + +# Use the next free one (replace the loop number) +losetup /dev/block/$loop $(pwd)/jessie.img +mount -t ext4 /dev/block/$loop $(pwd)/jessie + +# Bind-Mound proc, dev, sys` +busybox mount --bind /proc $(pwd)/jessie/proc +busybox mount --bind /dev $(pwd)/jessie/dev +busybox mount --bind /dev/pts $(pwd)/jessie/dev/pts +busybox mount --bind /sys $(pwd)/jessie/sys + +# Bind-Mound the rest of Android +mkdir -p $(pwd)/jessie/storage/sdcard{0,1} +busybox mount --bind /storage/emulated \ + $(pwd)/jessie/storage/sdcard0 +busybox mount --bind /storage/sdcard1 \ + $(pwd)/jessie/storage/sdcard1 + +# Check mounts +mount | grep jessie +``` + +### Second debootstrap stage + +This is to be performed on the Android phone itself (inside a Debian chroot): + +```sh +chroot $(pwd)/jessie /bin/bash -l +export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin:/usr/local/sbin +/debootstrap/debootstrap --second-stage +exit # Leave chroot +exit # Leave adb shell +``` + +### Setup of various scripts + +jessie.sh deals with all the loopback mount magic and so on. It will be run later every time you start Debroid on your phone. + +```sh +# Install script jessie.sh +adb push storage/sdcard1/Linux/jessie.sh /storage/sdcard/Linux/jessie.sh +adb shell +cd /storage/sdcard1/Linux +sh jessie.sh enter + +# Bashrc +cat <~/.bashrc +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH +export EDITOR=vim +hostname $(cat /etc/hostname) +END + +# Fixing an error message while loading the profile +sed -i s#id#/usr/bin/id# /etc/profile + +# Setting the hostname +echo phobos > /etc/hostname +echo 127.0.0.1 phobos > /etc/hosts +hostname phobos + +# Apt-sources +cat < sources.list +deb http://ftp.uk.debian.org/debian/ jessie main contrib non-free +deb-src http://ftp.uk.debian.org/debian/ jessie main contrib non-free +END +apt-get update +apt-get upgrade +apt-get dist-upgrade +exit # Exit chroot +``` + +### Entering Debroid and enable a service + +This enters Debroid on your phone and starts the example service uptimed: + +```sh +sh jessie.sh enter + +# Setup example serice uptimed +apt-get install uptimed +cat < /etc/rc.debroid +export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH +service uptimed status &>/dev/null || service uptimed start +exit 0 +END + +chmod 0755 /etc/rc.debroid +exit # Exit chroot +exit # Exit adb shell +``` + +### Include to Android startup: + +If you want to start Debroid automatically whenever your phone starts, then do the following: + +```sh +adb push data/local/userinit.sh /data/local/userinit.sh +adb shell +chmod +x /data/local/userinit.sh +exit +``` + +Reboot & test! Enjoy! + +E-Mail your comments to `paul@nospam.buetow.org` :-) + +=> ../ Back to the main site diff --git a/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi b/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi index ee830eb5..dc28d940 100644 --- a/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi +++ b/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi @@ -2,6 +2,8 @@ > Published at 2016-04-09T18:29:47+01:00 +Over the last couple of years I wrote quite a few Puppet modules in order to manage my personal server infrastructure. One of them manages FreeBSD Jails and another one ZFS file systems. I thought I would give a brief overview in how it looks and feels. + ``` __ __ (( \---/ )) @@ -25,16 +27,11 @@ ## Table of Contents * ⇢ Jails and ZFS with Puppet on FreeBSD -* ⇢ ⇢ Introduction * ⇢ ⇢ ZFS * ⇢ ⇢ Jails * ⇢ ⇢ Inside-Jail Puppet * ⇢ ⇢ Managing multiple Jails -## Introduction - -Over the last couple of years I wrote quite a few Puppet modules in order to manage my personal server infrastructure. One of them manages FreeBSD Jails and another one ZFS file systems. I thought I would give a brief overview in how it looks and feels. - ## ZFS The ZFS module is a pretty basic one. It does not manage ZFS pools yet as I am not creating them often enough which would justify implementing an automation. But let's see how we can create a ZFS file system (on an already given ZFS pool named ztank): diff --git a/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi.tpl b/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi.tpl index a7a311d8..f99f2c18 100644 --- a/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi.tpl +++ b/gemfeed/2016-04-09-jails-and-zfs-on-freebsd-with-puppet.gmi.tpl @@ -2,6 +2,8 @@ > Published at 2016-04-09T18:29:47+01:00 +Over the last couple of years I wrote quite a few Puppet modules in order to manage my personal server infrastructure. One of them manages FreeBSD Jails and another one ZFS file systems. I thought I would give a brief overview in how it looks and feels. + ``` __ __ (( \---/ )) @@ -24,10 +26,6 @@ << template::inline::toc -## Introduction - -Over the last couple of years I wrote quite a few Puppet modules in order to manage my personal server infrastructure. One of them manages FreeBSD Jails and another one ZFS file systems. I thought I would give a brief overview in how it looks and feels. - ## ZFS The ZFS module is a pretty basic one. It does not manage ZFS pools yet as I am not creating them often enough which would justify implementing an automation. But let's see how we can create a ZFS file system (on an already given ZFS pool named ztank): diff --git a/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi b/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi index 41ae6512..6bcd8948 100644 --- a/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi +++ b/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi @@ -2,12 +2,20 @@ > Published at 2016-05-22T18:59:01+01:00 -## Background - Finally, I had time to deploy my authoritative DNS servers (master and slave) for my domains "buetow.org" and "buetow.zone". My domain name provider is Schlund Technologies. They allow their customers to edit the DNS records (BIND files) manually. And they also allow you to set your authoritative DNS servers for your domains. From now, I am making use of that option. => http://www.schlundtech.de Schlund Technologies +## Table of Contents + +* ⇢ Spinning up my own authoritative DNS servers +* ⇢ ⇢ All FreeBSD Jails +* ⇢ ⇢ PF firewall +* ⇢ ⇢ Puppet managed BIND zone files +* ⇢ ⇢ The result +* ⇢ ⇢ Monitoring +* ⇢ ⇢ DNS update workflow + ## All FreeBSD Jails To set up my authoritative DNS servers, I installed a FreeBSD Jail dedicated for DNS with Puppet on my root machine as follows: diff --git a/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi.tpl b/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi.tpl new file mode 100644 index 00000000..39415e69 --- /dev/null +++ b/gemfeed/2016-05-22-spinning-up-my-own-authoritative-dns-servers.gmi.tpl @@ -0,0 +1,239 @@ +# Spinning up my own authoritative DNS servers + +> Published at 2016-05-22T18:59:01+01:00 + +Finally, I had time to deploy my authoritative DNS servers (master and slave) for my domains "buetow.org" and "buetow.zone". My domain name provider is Schlund Technologies. They allow their customers to edit the DNS records (BIND files) manually. And they also allow you to set your authoritative DNS servers for your domains. From now, I am making use of that option. + +=> http://www.schlundtech.de Schlund Technologies + +<< template::inline::toc + +## All FreeBSD Jails + +To set up my authoritative DNS servers, I installed a FreeBSD Jail dedicated for DNS with Puppet on my root machine as follows: + +``` +include freebsd + +freebsd::ipalias { '2a01:4f8:120:30e8::14': + ensure => up, + proto => 'inet6', + preflen => '64', + interface => 're0', + aliasnum => '5', +} + +include jail::freebsd + +class { 'jail': + ensure => present, + jails_config => { + dns => { + '_ensure' => present, + '_type' => 'freebsd', + '_mirror' => 'ftp://ftp.de.freebsd.org', + '_remote_path' => 'FreeBSD/releases/amd64/10.1-RELEASE', + '_dists' => [ 'base.txz', 'doc.txz', ], + '_ensure_directories' => [ '/opt', '/opt/enc' ], + 'host.hostname' => "'dns.ian.buetow.org'", + 'ip4.addr' => '192.168.0.15', + 'ip6.addr' => '2a01:4f8:120:30e8::15', + }, + . + . + } +} +``` + +## PF firewall + +Please note that "dns.ian.buetow.org" is just the Jail name of the master DNS server (and "caprica.ian.buetow.org" the name of the Jail for the slave DNS server) and that I am using the DNS names "dns1.buetow.org" (master) and "dns2.buetow.org" (slave) for the actual service names (these are the DNS servers visible to the public). Please also note that the IPv4 address is an internal one. I have a PF to use NAT and PAT. The DNS ports are being forwarded (TCP and UDP) to that Jail. By default, all ports are blocked, so I am adding an exception rule for the IPv6 address. These are the PF rules in use: + +``` +% cat /etc/pf.conf +. +. +# dns.ian.buetow.org +rdr pass on re0 proto tcp from any to $pub_ip port {53} -> 192.168.0.15 +rdr pass on re0 proto udp from any to $pub_ip port {53} -> 192.168.0.15 +pass in on re0 inet6 proto tcp from any to 2a01:4f8:120:30e8::15 port {53} flags S/SA keep state +pass in on re0 inet6 proto udp from any to 2a01:4f8:120:30e8::15 port {53} flags S/SA keep state +. +. +``` + +## Puppet managed BIND zone files + +In "manifests/dns.pp" (the Puppet manifest for the Master DNS Jail itself), I configured the BIND DNS server this way: + +``` +class { 'bind_freebsd': + config => "puppet:///files/bind/named.${::hostname}.conf", + dynamic_config => "puppet:///files/bind/dynamic.${::hostname}", +} +``` + +The Puppet module is a pretty simple one. It installs the file "/usr/local/etc/named/named.conf" and it populates the "/usr/local/etc/named/dynamicdb" directory with all my zone files. + +Once (Puppet-) applied inside of the Jail, I get this: + +``` +paul uranus:~/git/blog/source [4268]% ssh admin@dns1.buetow.org.buetow.org pgrep -lf named +60748 /usr/local/sbin/named -u bind -c /usr/local/etc/namedb/named.conf +paul uranus:~/git/blog/source [4269]% ssh admin@dns1.buetow.org.buetow.org tail -n 13 /usr/local/etc/namedb/named.conf +zone "buetow.org" { + type master; + notify yes; + allow-update { key "buetoworgkey"; }; + file "/usr/local/etc/namedb/dynamic/buetow.org"; +}; + +zone "buetow.zone" { + type master; + notify yes; + allow-update { key "buetoworgkey"; }; + file "/usr/local/etc/namedb/dynamic/buetow.zone"; +}; +paul uranus:~/git/blog/source [4277]% ssh admin@dns1.buetow.org.buetow.org cat /usr/local/etc/namedb/dynamic/buetow.org +$TTL 3600 +@ IN SOA dns1.buetow.org. domains.buetow.org. ( + 25 ; Serial + 604800 ; Refresh + 86400 ; Retry + 2419200 ; Expire + 604800 ) ; Negative Cache TTL +; Infrastructure domains +@ IN NS dns1 +@ IN NS dns2 +* 300 IN CNAME web.ian +buetow.org. 86400 IN A 78.46.80.70 +buetow.org. 86400 IN AAAA 2a01:4f8:120:30e8:0:0:0:11 +buetow.org. 86400 IN MX 10 mail.ian +dns1 86400 IN A 78.46.80.70 +dns1 86400 IN AAAA 2a01:4f8:120:30e8:0:0:0:15 +dns2 86400 IN A 164.177.171.32 +dns2 86400 IN AAAA 2a03:2500:1:6:20:: +. +. +. +. +``` + +That is my master DNS server. My slave DNS server runs in another Jail on another bare-metal machine. Everything is set up similar to the master DNS server. However, that server is located in a different DC and different IP subnets. The only difference is the "named.conf". It's configured to be a slave, and that means that the "dynamicdb" gets populated by BIND itself while doing zone transfers from the master. + +``` +paul uranus:~/git/blog/source [4279]% ssh admin@dns2.buetow.org tail -n 11 /usr/local/etc/namedb/named.conf +zone "buetow.org" { + type slave; + masters { 78.46.80.70; }; + file "/usr/local/etc/namedb/dynamic/buetow.org"; +}; + +zone "buetow.zone" { + type slave; + masters { 78.46.80.70; }; + file "/usr/local/etc/namedb/dynamic/buetow.zone"; +}; +``` + +## The result + +The result looks like this now: + +``` +% dig -t ns buetow.org +; <<>> DiG 9.10.3-P4-RedHat-9.10.3-12.P4.fc23 <<>> -t ns buetow.org +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 37883 +;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1 + +;; OPT PSEUDOSECTION: +; EDNS: version: 0, flags:; udp: 512 +;; QUESTION SECTION: +;buetow.org. IN NS + +;; ANSWER SECTION: +buetow.org. 600 IN NS dns2.buetow.org. +buetow.org. 600 IN NS dns1.buetow.org. + +;; Query time: 41 msec +;; SERVER: 192.168.1.254#53(192.168.1.254) +;; WHEN: Sun May 22 11:34:11 BST 2016 +;; MSG SIZE rcvd: 77 + +% dig -t any buetow.org @dns1.buetow.org +; <<>> DiG 9.10.3-P4-RedHat-9.10.3-12.P4.fc23 <<>> -t any buetow.org @dns1.buetow.org +;; global options: +cmd +;; Got answer: +;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 49876 +;; flags: qr aa rd ra; QUERY: 1, ANSWER: 6, AUTHORITY: 0, ADDITIONAL: 7 + +;; OPT PSEUDOSECTION: +; EDNS: version: 0, flags:; udp: 4096 +;; QUESTION SECTION: +;buetow.org. IN ANY + +;; ANSWER SECTION: +buetow.org. 86400 IN A 78.46.80.70 +buetow.org. 86400 IN AAAA 2a01:4f8:120:30e8::11 +buetow.org. 86400 IN MX 10 mail.ian.buetow.org. +buetow.org. 3600 IN SOA dns1.buetow.org. domains.buetow.org. 25 604800 86400 2419200 604800 +buetow.org. 3600 IN NS dns2.buetow.org. +buetow.org. 3600 IN NS dns1.buetow.org. + +;; ADDITIONAL SECTION: +mail.ian.buetow.org. 86400 IN A 78.46.80.70 +dns1.buetow.org. 86400 IN A 78.46.80.70 +dns2.buetow.org. 86400 IN A 164.177.171.32 +mail.ian.buetow.org. 86400 IN AAAA 2a01:4f8:120:30e8::12 +dns1.buetow.org. 86400 IN AAAA 2a01:4f8:120:30e8::15 +dns2.buetow.org. 86400 IN AAAA 2a03:2500:1:6:20:: + +;; Query time: 42 msec +;; SERVER: 78.46.80.70#53(78.46.80.70) +;; WHEN: Sun May 22 11:34:41 BST 2016 +;; MSG SIZE rcvd: 322 +``` + +## Monitoring + +For monitoring, I am using Icinga2 (I am operating two Icinga2 instances in two different DCs). I may have to post another blog article about Icinga2, but to get the idea, these were the snippets added to my Icinga2 configuration: + +``` +apply Service "dig" { + import "generic-service" + + check_command = "dig" + vars.dig_lookup = "buetow.org" + vars.timeout = 30 + + assign where host.name == "dns.ian.buetow.org" || host.name == "caprica.ian.buetow.org" +} + +apply Service "dig6" { + import "generic-service" + + check_command = "dig" + vars.dig_lookup = "buetow.org" + vars.timeout = 30 + vars.check_ipv6 = true + + assign where host.name == "dns.ian.buetow.org" || host.name == "caprica.ian.buetow.org" +} +``` + +## DNS update workflow + +Whenever I have to change a DNS entry, all I have to do is: + +* Git clone or update the Puppet repository +* Update/commit and push the zone file (e.g. "buetow.org") +* Wait for Puppet. Puppet will deploy that updated zone file. And it will reload the BIND server. +* The BIND server will notify all slave DNS servers (at the moment, only one). And it will transfer the new version of the zone. + +That's much more comfortable now than manually clicking at some web UIs at Schlund Technologies. + +E-Mail your comments to `paul@nospam.buetow.org` :-) + +=> ../ Back to the main site diff --git a/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi b/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi index 4aeae0c6..0d7fcc6c 100644 --- a/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi +++ b/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi @@ -2,6 +2,16 @@ > Published at 2018-06-01T14:50:29+01:00; Updated at 2021-05-08 +This text first was published in the german IT-Administrator computer Magazine. 3 years have passed since and I decided to publish it on my blog too. + +=> https://www.admin-magazin.de/Das-Heft/2018/06/Realistische-Lasttests-mit-I-O-Riot + +I havn't worked on I/O Riot for some time now, but all what is written here is still valid. I am still using I/O Riot to debug I/O issues and pattern once in a while, so by all means the tool is not obsolete yet. The tool even helped to resolve a major production incident at work caused by disk I/O. + +I am eagerly looking forward to revamp I/O Riot so that it uses the new BPF Linux capabilities instead of plain old Systemtap (or alternatively: Newer versions of Systemtap can also use BPF as the backend I have learned). Also, when I wrote I/O Riot initially, I didn't have any experience with the Go programming language yet and therefore I wrote it in C. Once it gets revamped I might consider using Go instead of C as it would spare me from many segmentation faults and headaches during development ;-). I might also just stick to C for plain performance reasons and just refactor the code dealing with concurrency. + +Pleace notice that some of the screenshots show the command "ioreplay" instead of "ioriot". That's because the name has changed after taking those. + ``` .---. / \ @@ -13,17 +23,21 @@ jgs\__/'---'\__/ ``` -## Foreword - -This text first was published in the german IT-Administrator computer Magazine. 3 years have passed since and I decided to publish it on my blog too. - -=> https://www.admin-magazin.de/Das-Heft/2018/06/Realistische-Lasttests-mit-I-O-Riot - -I havn't worked on I/O Riot for some time now, but all what is written here is still valid. I am still using I/O Riot to debug I/O issues and pattern once in a while, so by all means the tool is not obsolete yet. The tool even helped to resolve a major production incident at work caused by disk I/O. - -I am eagerly looking forward to revamp I/O Riot so that it uses the new BPF Linux capabilities instead of plain old Systemtap (or alternatively: Newer versions of Systemtap can also use BPF as the backend I have learned). Also, when I wrote I/O Riot initially, I didn't have any experience with the Go programming language yet and therefore I wrote it in C. Once it gets revamped I might consider using Go instead of C as it would spare me from many segmentation faults and headaches during development ;-). I might also just stick to C for plain performance reasons and just refactor the code dealing with concurrency. - -Pleace notice that some of the screenshots show the command "ioreplay" instead of "ioriot". That's because the name has changed after taking those. +## Table of Contents + +* ⇢ Realistic load testing with I/O Riot for Linux +* ⇢ The article +* ⇢ ⇢ Background: Existing Techniques +* ⇢ ⇢ Benchmarking the Email Cloud at Mimecast +* ⇢ ⇢ Using I/O Riot +* ⇢ ⇢ ⇢ Installation +* ⇢ ⇢ ⇢ Recording of I/O events +* ⇢ ⇢ ⇢ Test preparation +* ⇢ ⇢ ⇢ Test Initialization +* ⇢ ⇢ ⇢ Replay +* ⇢ ⇢ I/O Riot is Open Source +* ⇢ ⇢ Systemtap +* ⇢ ⇢ More refereces # The article diff --git a/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi.tpl b/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi.tpl new file mode 100644 index 00000000..2fdea893 --- /dev/null +++ b/gemfeed/2018-06-01-realistic-load-testing-with-ioriot-for-linux.gmi.tpl @@ -0,0 +1,191 @@ +# Realistic load testing with I/O Riot for Linux + +> Published at 2018-06-01T14:50:29+01:00; Updated at 2021-05-08 + +This text first was published in the german IT-Administrator computer Magazine. 3 years have passed since and I decided to publish it on my blog too. + +=> https://www.admin-magazin.de/Das-Heft/2018/06/Realistische-Lasttests-mit-I-O-Riot + +I havn't worked on I/O Riot for some time now, but all what is written here is still valid. I am still using I/O Riot to debug I/O issues and pattern once in a while, so by all means the tool is not obsolete yet. The tool even helped to resolve a major production incident at work caused by disk I/O. + +I am eagerly looking forward to revamp I/O Riot so that it uses the new BPF Linux capabilities instead of plain old Systemtap (or alternatively: Newer versions of Systemtap can also use BPF as the backend I have learned). Also, when I wrote I/O Riot initially, I didn't have any experience with the Go programming language yet and therefore I wrote it in C. Once it gets revamped I might consider using Go instead of C as it would spare me from many segmentation faults and headaches during development ;-). I might also just stick to C for plain performance reasons and just refactor the code dealing with concurrency. + +Pleace notice that some of the screenshots show the command "ioreplay" instead of "ioriot". That's because the name has changed after taking those. + +``` + .---. + / \ + \.@-@./ + /`\_/`\ + // _ \\ + | \ )|_ + /`\_`> <_/ \ +jgs\__/'---'\__/ +``` + +<< template::inline::toc + +# The article + +With I/O Riot IT administrators can load test and optimize the I/O subsystem of Linux-based operating systems. The tool makes it possible to record I/O patterns and replay them at a later time as often as desired. This means bottlenecks can be reproduced and eradicated. + +When storing huge amounts of data, such as more than 200 billion archived emails at Mimecast, it's not only the a