Musings from the mountains himwant.org

Add publish.el

akshitgaur2005.tngl.sh ef8777a8 ec79e548

Waiting for spindle ...
+82 -1356
+13 -2
.tangled/workflows/deploy.yaml
··· 7 7 nixpkgs: 8 8 - nodejs 9 9 - bash 10 + - emacs # <--- The Magic: Pulls Emacs into the container 10 11 11 12 steps: 12 13 - name: install dependencies 13 14 command: npm install 14 15 16 + # --- NEW STEP: Headless Emacs Conversion --- 17 + - name: convert org to markdown 18 + command: emacs --batch -l publish.el 19 + # ------------------------------------------- 20 + 15 21 - name: build site 16 - # Use 'npm run build' which runs 'astro build' 17 22 command: npm run build 18 23 19 24 - name: deploy 25 + # Ensure these secrets are set in your Codeberg/Woodpecker Repo Settings! 26 + environment: 27 + CLOUDFLARE_API_TOKEN: 28 + from_secret: CLOUDFLARE_API_TOKEN 29 + CLOUDFLARE_ACCOUNT_ID: 30 + from_secret: CLOUDFLARE_ACCOUNT_ID 20 31 command: | 21 - npx --yes wrangler pages deploy dist --project-name himwant --branch main 32 + npx --yes wrangler pages deploy dist --project-name himwant --branch main
+69
publish.el
··· 1 + ;; publish.el - The Himwant Converter 2 + 3 + (require 'ox-md) 4 + (require 'json) 5 + 6 + (org-export-define-derived-backend 'md-fenced 'md 7 + :translate-alist 8 + '((src-block . my/org-md-src-block-fenced) 9 + (example-block . my/org-md-example-block-fenced))) 10 + 11 + (defun my/org-md-src-block-fenced (src-block _contents info) 12 + "Transcode SRC-BLOCK to GitHub Flavored Markdown fenced block." 13 + (let* ((lang-raw (org-element-property :language src-block)) 14 + ;; Fix C mapping if needed, otherwise pass through 15 + (lang (cond ((string= lang-raw "C") "c") (t lang-raw))) 16 + (value (org-element-property :value src-block)) 17 + (params-str (org-element-property :parameters src-block)) 18 + ;; Handle potential nil parameters safely 19 + (header-args (if params-str (org-babel-parse-header-arguments params-str) nil)) 20 + (title-val (cdr (assoc :title header-args)))) 21 + (format "```%s%s\n%s```\n\n" 22 + (or lang "") 23 + (if title-val (format " title=\"%s\"" title-val) "") 24 + value))) 25 + 26 + (defun my/org-md-example-block-fenced (example-block _contents info) 27 + (let ((value (org-element-property :value example-block))) 28 + (format "```\n%s```\n\n" value))) 29 + 30 + (defun my/process-org-file (file-path) 31 + "Open FILE-PATH and export it to Markdown with frontmatter." 32 + (with-current-buffer (find-file-noselect file-path) 33 + (let* ((title (or (cadar (org-collect-keywords '("TITLE"))) "Untitled")) 34 + ;; Collect other keywords 35 + (keywords (org-collect-keywords '("DESCRIPTION" "DRAFT" "SERIES" "TAGS"))) 36 + (description (car (cdr (assoc "DESCRIPTION" keywords)))) 37 + (series (car (cdr (assoc "SERIES" keywords)))) 38 + (draft-kw (car (cdr (assoc "DRAFT" keywords)))) 39 + (tags (let ((t1 (org-get-tags))) 40 + (if t1 t1 41 + (split-string (or (car (cdr (assoc "TAGS" keywords))) "") "[ ,:]+" t)))) 42 + (published (format-time-string "%Y-%m-%d")) 43 + (output-file (concat (file-name-sans-extension file-path) ".md")) 44 + frontmatter) 45 + 46 + ;; Build Frontmatter 47 + (setq frontmatter 48 + (concat 49 + "---\n" 50 + (format "title: \"%s\"\n" title) 51 + (format "pubDate: %s\n" published) ;; Astro usually prefers pubDate 52 + (format "draft: %s\n" (if (string-equal (downcase (or draft-kw "")) "true") "true" "false")) 53 + (when description (format "description: '%s'\n" description)) 54 + (when series (format "series: '%s'\n" series)) 55 + (when tags (format "tags: %s\n" (json-encode tags))) 56 + "---\n\n")) 57 + 58 + ;; Export 59 + (let ((md-content (org-export-as 'md-fenced nil nil t))) 60 + (with-temp-file output-file 61 + (insert frontmatter) 62 + (insert md-content)) 63 + (message "Converted: %s -> %s" file-path output-file))))) 64 + 65 + 66 + ;; Change this path to match where your Org files live 67 + (let ((content-dir "./src/content/")) 68 + (dolist (file (directory-files-recursively content-dir "\\.org$")) 69 + (my/process-org-file file)))
-194
src/content/aoc/2025/01.md
··· 1 - --- 2 - title: "Secret Entrance" 3 - published: 2025-12-16 4 - draft: false 5 - --- 6 - 7 - 8 - 9 - # Part 1 10 - 11 - We are given line seperated operations that happen on a 100 pin circular dial. The dial starts at 50 and we are to output, how many times the dial stops at 0! 12 - 13 - We first, as expected, just take in the input and initialise variables to store current dial position and total number of times the dial has stopped at 0. 14 - 15 - ```rust title="setup" 16 - use std::fs::read_to_string; 17 - fn main() { 18 - let contents = read_to_string("./input.txt").unwrap(); 19 - let mut curr: i32 = 50; 20 - let mut tot = 0; 21 - 22 - <<logic_loop>> 23 - 24 - println!("Password: {tot}"); 25 - } 26 - ``` 27 - 28 - We go through each line of input, and parse it. Our input is in the form -"L50" where the first character is the direction in which the dial is to be rotated and the rest is the amplitude. 29 - 30 - ```rust title="logic_loop" 31 - for line in contents.lines() { 32 - let words: Vec<char> = line.chars().collect(); 33 - let dir = words[0]; 34 - let amp: String = words[1..].iter().collect(); 35 - let amp: i32 = amp.parse().unwrap(); 36 - 37 - <<rotate_dial>> 38 - } 39 - ``` 40 - 41 - Now that we have both the dir and the amp, we can modify the dial position. 42 - 43 - ```rust title="rotate_dial" 44 - if dir == 'L' { 45 - curr -= amp; 46 - } else { 47 - curr += amp; 48 - } 49 - 50 - <<loopback>> 51 - ``` 52 - 53 - The value of curr could have gone above 99 or below 0, which we need to rectify. 54 - 55 - ```rust title="loopback" 56 - if curr < 0 { 57 - curr = 100 + curr; 58 - } 59 - 60 - curr = curr % 100; 61 - 62 - <<count_zeros>> 63 - ``` 64 - 65 - Now that we have the current position of the dial, we only need to check if it currently points at 0, and increment `tot`, if it does. 66 - 67 - ```rust title="count_zeros" 68 - if curr == 0 { 69 - tot += 1; 70 - } 71 - ``` 72 - 73 - We have the final program- 74 - 75 - ```rust title="Full Program" 76 - use std::fs::read_to_string; 77 - fn main() { 78 - let contents = read_to_string("./input.txt").unwrap(); 79 - let mut curr: i32 = 50; 80 - let mut tot = 0; 81 - 82 - for line in contents.lines() { 83 - let words: Vec<char> = line.chars().collect(); 84 - let dir = words[0]; 85 - let amp: String = words[1..].iter().collect(); 86 - let amp: i32 = amp.parse().unwrap(); 87 - 88 - if dir == 'L' { 89 - curr -= amp; 90 - } else { 91 - curr += amp; 92 - } 93 - 94 - if curr < 0 { 95 - curr = 100 + curr; 96 - } 97 - 98 - curr = curr % 100; 99 - 100 - if curr == 0 { 101 - tot += 1; 102 - } 103 - } 104 - 105 - println!("Password: {tot}"); 106 - } 107 - ``` 108 - 109 - 110 - # Part 2 111 - 112 - Another complication has been added to our little problem! Now we not only need to say how many times the dial stopped at 0, but also how many times it crossed it! 113 - 114 - We add two new variables that are going to help us! `prev` and `cross`. We are going to keep `tot` and its related logic and add onto it! 115 - 116 - ```rust 117 - // In setup 118 - let mut prev: i32 = 50; 119 - let mut cross = 0; 120 - ``` 121 - 122 - If the amplitude is >100, that means atleast one full rotation, therefore, atleast oe crossing of 0! We can figure out the number of crossing here using division. We also bring the value of amp to the range [0, 99]. 123 - 124 - ```rust 125 - cross += amp / 100; 126 - let amp = amp % 100; 127 - ``` 128 - 129 - An easy way to detect a crossing is to check if the difference in `curr` and `prev` is opposite to what we expected. 130 - 131 - For example, let's say dial position is at `5` and we get input `L10`, as the `dir` is `L`, the dial position should decrease, that is, `curr` < `prev`, but as the `amp` was 10, the new dial position becomes `95`. Now, `curr` (95) > `prev` (5). 132 - 133 - Detecting for this, and similarly `curr` < `prev` for `R`, we can check if there was a crossing on this move! 134 - 135 - One thing we need to keep in mind is to ignore those where either `curr` or `prev` were 0, as they would have been already counted by `tot`! 136 - 137 - :::duck 138 - Also, do remember to set `prev = curr` at the end, you don't want to know how much time I spent debugging this! 139 - ::: 140 - 141 - ```rust 142 - if ((dir == 'L' && prev < curr) || (dir == 'R' && prev > curr)) && curr != 0 && prev != 0 { 143 - cross += 1; 144 - } 145 - 146 - prev = curr; 147 - ``` 148 - 149 - Our final program- 150 - 151 - ```rust title="main.rs" 152 - use std::fs::read_to_string; 153 - 154 - fn main() { 155 - let contents = read_to_string("./input.txt").unwrap(); 156 - 157 - let mut curr: i32 = 50; 158 - let mut prev: i32 = 50; 159 - let mut tot = 0; 160 - let mut cross = 0; 161 - 162 - for line in contents.lines() { 163 - let words: Vec<char> = line.chars().collect(); 164 - let dir = words[0]; 165 - let amp: String = words[1..].iter().collect(); 166 - let amp: i32 = amp.parse().unwrap(); 167 - 168 - cross += amp / 100; 169 - let amp = amp % 100; 170 - 171 - if dir == 'L' { 172 - curr -= amp; 173 - } else { 174 - curr += amp; 175 - } 176 - 177 - if curr < 0 { 178 - curr = 100 + curr; 179 - } 180 - curr = curr % 100; 181 - 182 - if curr == 0 { 183 - tot += 1; 184 - } 185 - if ((dir == 'L' && prev < curr) || (dir == 'R' && prev > curr)) && curr != 0 && prev != 0 { 186 - cross += 1; 187 - } 188 - 189 - prev = curr; 190 - } 191 - println!("Password: {}", cross + tot); 192 - } 193 - ``` 194 -
-188
src/content/aoc/2025/02.md
··· 1 - --- 2 - title: "Gift Shop" 3 - published: 2025-12-18 4 - draft: false 5 - --- 6 - 7 - We are given comma-separated ranges of numbers that we have to check, we sum all the numbers which are n repeating blocks, for example, 123123 has n = 2, and block = 123, similarly, 111, has n = 3, and block = 1! Part 1 has n = 2, and Part 2 can have any value as n! So we can just directly solve Part 2 (although I did solve Part 1 as a standalone problem first). Let's get started&#x2026; 8 - 9 - 10 - # Boilerplate 11 - 12 - ```rust 13 - use std::fs; 14 - 15 - fn main() { 16 - let input = fs::read_to_string("./input.txt").unwrap(); 17 - let ranges = input.split(","); 18 - let mut sum = 0; 19 - for range in ranges { 20 - let mut nums = range.split("-"); 21 - 22 - let start: u64 = nums.next().unwrap().trim().parse().unwrap(); 23 - let end: u64 = nums.next().unwrap().trim().parse().unwrap(); 24 - 25 - for i in start..=end { 26 - let i_str = i.to_string(); 27 - 28 - if check(i_str) { 29 - sum += i; 30 - } 31 - } 32 - } 33 - println!("Sum: {sum}"); 34 - } 35 - ``` 36 - 37 - We parse the input, and send the number (as a string) to `check` function for the actual logic. 38 - 39 - 40 - # check 41 - 42 - ```rust title="check" 43 - fn check(i_str: String) -> bool { 44 - for check_len in 1..i_str.len() { 45 - if check_n(&i_str, check_len) { 46 - return true; 47 - } 48 - } 49 - return false; 50 - } 51 - ``` 52 - 53 - We start with n=1 and go up to the length of the string checking if it has 'n' repeating blocks! 54 - 55 - 56 - # check<sub>n</sub> 57 - 58 - check<sub>n</sub> actually performs the logic- 59 - 60 - 1. It is obviously not going to be 'n' repeating blocks if the length of the string is not even divisible by n! 61 - 62 - ```rust 63 - if i_str.len() % check_len != 0 { 64 - return false; 65 - } 66 - ``` 67 - 68 - 2. Setup block content 69 - 70 - ```rust 71 - let nums = i_str.char_indices(); 72 - 73 - let mut curr = String::new(); 74 - let comp = &i_str[0..check_len]; 75 - ``` 76 - 77 - 3. Now we append each character to `curr`, and on every 'n'th character, we compare `curr` and `comp`, if it is different, we return false, otherwise we clear `curr` and continue. 78 - 79 - ```rust 80 - for (id, c) in nums { 81 - if id % check_len == 0 && id != 0 { 82 - if comp != curr { 83 - return false; 84 - } 85 - curr = String::new(); 86 - } 87 - curr.push(c); 88 - } 89 - ``` 90 - 91 - 4. We also need to check the last block 92 - 93 - ```rust 94 - if comp != curr { 95 - return false; 96 - } 97 - ``` 98 - 99 - 5. We return true, if all blocks are same 100 - 101 - ```rust 102 - true 103 - ``` 104 - 105 - Our Final check<sub>n</sub> function- 106 - 107 - ```rust title="check_n" 108 - fn check_n(i_str: &str, check_len: usize) -> bool { 109 - if i_str.len() % check_len != 0 { 110 - return false; 111 - } 112 - let nums = i_str.char_indices(); 113 - 114 - let mut curr = String::new(); 115 - let comp = &i_str[0..check_len]; 116 - for (id, c) in nums { 117 - if id % check_len == 0 && id != 0 { 118 - if comp != curr { 119 - return false; 120 - } 121 - curr = String::new(); 122 - } 123 - curr.push(c); 124 - } 125 - if comp != curr { 126 - return false; 127 - } 128 - true 129 - } 130 - ``` 131 - 132 - Which gives us our final program- 133 - 134 - ```rust title="main.rs" 135 - use std::fs; 136 - 137 - fn main() { 138 - let input = fs::read_to_string("./input.txt").unwrap(); 139 - let ranges = input.split(","); 140 - let mut sum = 0; 141 - for range in ranges { 142 - let mut nums = range.split("-"); 143 - 144 - let start: u64 = nums.next().unwrap().trim().parse().unwrap(); 145 - let end: u64 = nums.next().unwrap().trim().parse().unwrap(); 146 - 147 - for i in start..=end { 148 - let i_str = i.to_string(); 149 - 150 - if check(i_str) { 151 - sum += i; 152 - } 153 - } 154 - } 155 - println!("Sum: {sum}"); 156 - } 157 - fn check(i_str: String) -> bool { 158 - for check_len in 1..i_str.len() { 159 - if check_n(&i_str, check_len) { 160 - return true; 161 - } 162 - } 163 - return false; 164 - } 165 - fn check_n(i_str: &str, check_len: usize) -> bool { 166 - if i_str.len() % check_len != 0 { 167 - return false; 168 - } 169 - let nums = i_str.char_indices(); 170 - 171 - let mut curr = String::new(); 172 - let comp = &i_str[0..check_len]; 173 - for (id, c) in nums { 174 - if id % check_len == 0 && id != 0 { 175 - if comp != curr { 176 - return false; 177 - } 178 - curr = String::new(); 179 - } 180 - curr.push(c); 181 - } 182 - if comp != curr { 183 - return false; 184 - } 185 - true 186 - } 187 - ``` 188 -
-145
src/content/aoc/2025/03.md
··· 1 - --- 2 - title: "Lobby" 3 - published: 2025-12-24 4 - draft: false 5 - --- 6 - 7 - Entire question [here](https://adventofcode.com/2025/day/3). 8 - 9 - We are given several line separated strings of numbers (0-9) and a number `n`, for each string, we have two select two characters, appending which, in order, produces the largest number; and return their sum. 10 - 11 - For example, in the string "97856483" and n = 2, our answer is 98. In "811111111111119", we have 89! 12 - 13 - The only differentiating part in part 1 and part 2 is n. Part 1 has n = 2, and part 2 has it equal to 12. 14 - 15 - Let's get started then, and get done with the boilerplate first. 16 - 17 - ```rust 18 - use std::fs; 19 - 20 - fn main() { 21 - let input = fs::read_to_string("./sample.txt").unwrap(); 22 - let mut sum = 0; 23 - 24 - for line in input.lines() { 25 - let num = parse(&line, 12); 26 - sum += num; 27 - } 28 - println!("Final number: {sum}"); 29 - } 30 - ``` 31 - 32 - The real meat is in the parse function! 33 - 34 - Let us go through the logic. 35 - 36 - 1. We store three variables, sum, last<sub>index</sub>, and placeholder. 37 - 38 - 1. `sum` is the running sum for the current line. 39 - 2. `last_index`- We only search after last<sub>index</sub>. 40 - 3. `placeholder`- To store the place value we are currently searching for. For example, 10s, 100s, etc. 41 - 42 - ```rust 43 - fn parse(line: &str, pl: u32) -> u64 { 44 - let mut sum: u64 = 0; 45 - let mut last_index: isize = -1; 46 - let mut placeholder: i32 = pl as i32 - 1; 47 - 48 - <<logic>> 49 - } 50 - ``` 51 - 52 - 2. Now onto the loop!! We go through each character in the line, starting after the last<sub>index</sub> and check if the current char is equal to curr<sub>num</sub> (curr<sub>num</sub> starts from 9 and ticks down each time we can't find that number in the line). One thing to note is the range in which we check the chars, starting from `last_index + 1` to length of the line - placeholder! 53 - 54 - ```rust 55 - while placeholder >= 0 { 56 - let mut found = false; 57 - 58 - for curr_num in (0u64..=9).rev() { 59 - for (i, c) in line.chars().enumerate() { 60 - if i as isize <= last_index { 61 - continue; 62 - } 63 - 64 - if let Some(num) = c.to_digit(10) { 65 - if num as u64 == curr_num 66 - && i < line.len() - placeholder as usize 67 - { 68 - last_index = i as isize; 69 - sum += curr_num * 10_u64.pow(placeholder as u32); 70 - placeholder -= 1; 71 - found = true; 72 - break; 73 - } 74 - } 75 - } 76 - 77 - if found { 78 - break; 79 - } 80 - } 81 - 82 - if !found { 83 - break; 84 - } 85 - } 86 - 87 - sum 88 - ``` 89 - 90 - We have our final program 91 - 92 - ```rust title="main.rs" 93 - use std::fs; 94 - 95 - fn main() { 96 - let input = fs::read_to_string("./sample.txt").unwrap(); 97 - let mut sum = 0; 98 - 99 - for line in input.lines() { 100 - let num = parse(&line, 12); 101 - sum += num; 102 - } 103 - println!("Final number: {sum}"); 104 - } 105 - fn parse(line: &str, pl: u32) -> u64 { 106 - let mut sum: u64 = 0; 107 - let mut last_index: isize = -1; 108 - let mut placeholder: i32 = pl as i32 - 1; 109 - 110 - while placeholder >= 0 { 111 - let mut found = false; 112 - 113 - for curr_num in (0u64..=9).rev() { 114 - for (i, c) in line.chars().enumerate() { 115 - if i as isize <= last_index { 116 - continue; 117 - } 118 - 119 - if let Some(num) = c.to_digit(10) { 120 - if num as u64 == curr_num 121 - && i < line.len() - placeholder as usize 122 - { 123 - last_index = i as isize; 124 - sum += curr_num * 10_u64.pow(placeholder as u32); 125 - placeholder -= 1; 126 - found = true; 127 - break; 128 - } 129 - } 130 - } 131 - 132 - if found { 133 - break; 134 - } 135 - } 136 - 137 - if !found { 138 - break; 139 - } 140 - } 141 - 142 - sum 143 - } 144 - ``` 145 -
-128
src/content/posts/perpetual.md
··· 1 - --- 2 - title: "Musings" 3 - published: 2025-12-07 4 - draft: true 5 - description: '...' 6 - tags: ["musings"] 7 - --- 8 - 9 - Am I alone? 10 - 11 - I think so 12 - 13 - But who am I? 14 - 15 - You are me 16 - 17 - And who is speaking? 18 - 19 - I am you 20 - 21 - Well that doesn't make any sense 22 - 23 - It doesn't have to 24 - 25 - But it has to! What am I supposed to do if nothing makes sense? 26 - 27 - You are not supposed to do anything 28 - 29 - How am I even supposed to live then? If I am supposed to do nothing, what am I even here for? 30 - 31 - You use the word "supposed" a lot, don't you? 32 - 33 - &#x2026; 34 - 35 - One of the quieter ones huh 36 - 37 - I am not quiet! 38 - 39 - Well, to answer your question, again you are not supposed to do anything but tha- 40 - 41 - So I am not even supposed to live then? 42 - 43 - Let me complete first, yes you are not supposed to do anything but that is different than "supposed to do nothing" you know 44 - 45 - You are just confusing me, if I am not supposed to do anything, what is the point of doing ***ANYTHING***? 46 - 47 - Again, there is no point 48 - 49 - So it doesn't matter if I die? 50 - 51 - Death is the only certainty in life as you people say, why do you think yours will be any different this time 52 - 53 - Even my parents won't remember me? 54 - 55 - They will, but they too will move on 56 - 57 - No they won't! They love me! 58 - 59 - Yes they love you, but they WILL move on, the same way you moved on from that doll you loved as a kid 60 - 61 - I just grew up&#x2026; 62 - 63 - So will they. The same way you continue to live on, they will too 64 - 65 - If there is no point to anything then why even bother doing anything? Why should I eat? Why should I sleep? Why should I love? Why should I care? 66 - 67 - The fact that there is no point, is THE entire point. Nothing needs to make sense because sense is not needed for you to function. You fear things out of your control, that is your bane 68 - 69 - Of course I do! I am a human you know, of course I am going to fear things that can hurt me 70 - 71 - But you fear things that have no impact on you. You dress up just so people on the street don't mock you, you fear being yourself just so others will like you. Just consider that girl you have a crush on, you analyse every move, both yours and hers, trying to find a signal that may or may not even be there! 72 - 73 - So what! Should I just stop caring about others? If nothing matters, should I just go around punching random kids on the street! 74 - 75 - You are still doing the same, just dumping the responsibilty of that answer on me 76 - 77 - I can't even ask you a question?! 78 - 79 - What do you think you have been doing till now :) The problem isn't you asking me a question, the problem is you asking an answer. You refuse to think about it, you refuse to take on that burden because you are afraid of what your answer could be 80 - 81 - But if others hate me, what will I do? How will I live completely alone? 82 - 83 - Why do you live? 84 - 85 - What do you mean why do I live? 86 - 87 - I mean why are you still alive, if you don't have any hope, why haven't you killed yourself? 88 - 89 - Because people I care about, my parents, my friends, would be sad if I died 90 - 91 - So you live for others? 92 - 93 - Isn't that good enough? 94 - 95 - You are making excuses, just like you always do. Pretending to be the forever victim, the one who couldn't have done any wrong, the one who fate has robbed at every turn. 96 - 97 - &#x2026; 98 - 99 - You like having othes depend upon you, even if for the very smallest of the things, it satisfies that twisted little mind of yours, it makes you feel worth something. 100 - 101 - That could be&#x2026; 102 - 103 - If you want real happiness, you have got to find it for yourself, not wait for somebody to give it to you! Isn't that what you have been doing? 104 - 105 - I am worthless, nobody needs me. 106 - 107 - You seek your value in the perce 108 - 109 - AHHH SHUT UP!!! 110 - 111 - ption of others. Do you fear being alone? You're afraid that you will lose your identity if others leave you 112 - 113 - JUST LEAVE ME ALONE!! HOW CAN A FLOATING VOICE EVEN DARE TELL ME THAT!! 114 - 115 - You're afraid that you will disappear from the mind of others. Each conversation they have that doesn't involve you, each inside joke that you are not part of, each knowing glance that you can't decipher scares you. Isn't that right? 116 - 117 - No it is not, I want to be alone, I don't feel emotions since a long time, I have not cried in 5 years, I have always been alone and I like being alone. That is the reason I left my home and came to a new city for school. I want to be alone. 118 - 119 - Was it really that or did you just want the attention to yourself? Tired of the fact that your brother was the one your mother has always liked more? What about when your entire family had that car crash and your mother kept looking for him, not even bothering to look at you? Or how your father was so focused on getting your mother in the hospital that he just left you with a stranger, with a broken and bleeding foot and a detached ear? How old were you then, 13? 120 - 121 - I did not do it for attention. And anyways, nowadays they DO focus more on me! 122 - 123 - Yes, after your brother disappointed them for 5 years straight. Huh, the same amount of years that took you to regain their trust after exactly two lies!! Do you think things will remain the same once he regains it too, as he is currently doing, or will they revert back to how things actually were? A 3 year old boy getting beaten up because he wanted his favourite song to play, a 8 year old getting beaten because his hand writing is not that good, a 15 year old getting beaten up because somebody stole the handle grips from his bicycle? 124 - 125 - Even if they do, I don't care, things have always been like that and I have made my peace with it 126 - 127 - Have you really? 128 -
-50
src/content/posts/why-guix-is-just-better/index.md
··· 1 - --- 2 - title: "Guix is just better" 3 - published: 2025-11-18 4 - draft: true 5 - description: 'A signature look of superiority' 6 - tags: ["guix","linux"] 7 - --- 8 - 9 - 10 - 11 - # Déjà vu? 12 - 13 - The three people that may have read a previous iteration of this blog on the previous iteration of this website, that I accidentaly nuked while changing the framework from hugo to astro, are requested to pretend this is some fresh piece of writing. 14 - 15 - :::caution 16 - Yes, I am THAT stupid 17 - ::: 18 - 19 - Regardless, if you want to hear me ramble more about a topic I don't fully understand, continue on!! 20 - 21 - 22 - # What is Guix? 23 - 24 - In its own [words](https://guix.gnu.org/en/about/), 25 - 26 - > The GNU Guix package and system manager is a free software project developed by volunteers around the world under the umbrella of the GNU Project. 27 - 28 - > Guix System is a distribution of the GNU operating system. It uses the Linux-libre kernel, and support for the Hurd is being worked on. As a GNU distribution, it is committed to respecting and enhancing the freedom of its users. As such, it adheres to the GNU Free System Distribution Guidelines. 29 - 30 - > GNU Guix provides state-of-the-art package management features such as transactional upgrades and roll-backs, reproducible build environments, unprivileged package management, and per-user profiles. It uses low-level mechanisms from the Nix package manager, but packages are defined as native Guile modules, using extensions to the Scheme language—which makes it nicely hackable. 31 - 32 - > Guix takes that a step further by additionally supporting stateless, reproducible operating system configurations. This time the whole system is hackable in Scheme, from the initial RAM disk to the initialization system, and to the system services. 33 - 34 - Guix is a distro intended for geeks, incidentally pronounced that way too. There is no way to sugarcoat it, there is an inherent difficulty to these things, if you find Arch difficult to use, you shouldn't use Nix, if you can't use Nix, you should probably stay away from Guix, and if you can master Guix&#x2026; you still won't be able to use Windows without borking it! 35 - 36 - 37 - ## Story Time 38 - 39 - I have been on linux since I was 13 (2018) and in my 7 years of using it, it has been exactly 3 times when I was hugely excited about linux itself, not some tooling related to it or any work I did using it, linux itself. 40 - 41 - 42 - ### The Beginnings 43 - 44 - First was when I discovered Linux, in the form of Ubuntu which at that time had not gone down the drain. My laptop was a brand-new Dell laptop with i3 6th gen CPU, 4 gigabytes of RAM and a whopping 1 TB of Hard Disk capacity, I had worked with PC's before this (I learned how to play *Surma Sarela* and *Bhalu Lagdu Bhanuli* on my father's computer when I was 3) but it had been mostly superficial with only a little dabbling in the Front-End development space due to the encouragement from my *Chachu* (Uncle). But I digress, as you would expect this did not lead to me being an expert in all things computer and I borked that laptop many times on Windows. Eventually I read a little about Ubuntu on the internet and figured well why not?! What do I have to lose! The process was not very difficult and I managed to install it. Suprisingly, the transition was very smooth (it speaks to its quality that even a 13 year old ME was able to install and use it) and I would wait for every update, and this would lead to me becoming addicted to this excitement, becoming the ill-fated **Distro-Hopper**. 45 - 46 - 47 - ### Mid-Life Crisis 48 - 49 - When 2020 with its Covid Craziness<sup>TM</sup> hit, I found myself with a lot of free time on my hand 50 -
-152
src/content/posts/xv6-intro/index.md
··· 1 - --- 2 - title: "xv6 - Introduction" 3 - published: 2026-01-02 4 - draft: false 5 - description: 'Introducing the xv6 kernel' 6 - series: 'xv6' 7 - tags: ["xv6","os"] 8 - --- 9 - 10 - 11 - 12 - # Why?? 13 - 14 - I am currently going through the book ***Operating Systems: Three Easy Pieces***, and the next step after completing the first piece, Virtualisation, is to go through the xv6 kernel. The xv6 kernel had two implementations, the x86 one and RISC-V one. As the x86 one is now unmaintained and on recommendation of a mentor, I am using [xv6-riscv](https://github.com/mit-pdos/xv6-riscv)! So without further ado, let's get started. 15 - 16 - 17 - # The xv6 Kernel 18 - 19 - - Based on Unix kernel 20 - - Created by MIT for educational purposes 21 - - Implemented for RISC-V 22 - - Multicore 23 - - ~6000 lines of code (C and Assembly) 24 - 25 - 26 - ## Features 27 - 28 - - Processes 29 - - Virtual Address Spaces 30 - - Page Tables 31 - - Files and Directories 32 - - Pipes 33 - - Multitasking 34 - - Time-Slicing 35 - - 21 system calls 36 - 37 - 38 - ## User Programs 39 - 40 - - sh 41 - - cat 42 - - echo 43 - - grep 44 - - kill 45 - - ln 46 - - ls 47 - - mkdir 48 - - rm 49 - - wc 50 - 51 - 52 - ## What is missing? 53 - 54 - All the complexity of a "real" operating system is missing. For example, UserID, file protections, IPC, "mount"able filesystem, etc. 55 - 56 - 57 - ## SMP: Shared Memory Multiprocesser 58 - 59 - CPU = core = HART 60 - 61 - Main memory (RAM) is shared and is of size 128 Mbytes 62 - 63 - 64 - ## Supported Devices 65 - 66 - - UART (Serial Comm. Tx <=> Rx) 67 - - Disk 68 - - Timer Interrupts 69 - - PLIC: Platform Level Interrupt Controller 70 - - CLINT: Core Local Interrupt Controller 71 - 72 - 73 - ## Memory Management 74 - 75 - - Page Size = 4096 bytes (`#define PGSIZE`) 76 - - Single Free List 77 - - No variable sized allocation 78 - - No "malloc" 79 - - Page Tables- 80 - - Three Levels 81 - - One table per process + One table for Kernel 82 - - Pages marked - R/W/X/U/V 83 - 84 - 85 - ## Scheduler 86 - 87 - - Round Robin 88 - - Size of TimeSlice is fixed (1,000,000 cycles) 89 - - All cores share one "Ready Queue" 90 - - Next TimeSlice may be on a different core 91 - 92 - 93 - ## Boot Sequence 94 - 95 - - QEMU 96 - - Loads kernel code at a fixed address (0x8000-0000) 97 - - Starts all cores running 98 - - No bootloader/boot-block/BIOS 99 - 100 - 101 - ## Locking 102 - 103 - - Spin Locks 104 - - `sleep()` & `wakeup()` 105 - 106 - 107 - ## "Param.h" 108 - 109 - - Fixed Limits (like no. of processes, no. of open files, etc) 110 - - Several Arrays ("`kill(pid)`" => Linear search of Processes array) 111 - 112 - 113 - ## User Address Space 114 - 115 - ![img](./ua-space.jpeg "Sorry for the bad handwriting!") 116 - 117 - Arguments (argc, argv) will be placed on the stack before the program begins execution. 118 - 119 - 120 - ## RISC-V Virtual Addresses 121 - 122 - - Multiple Schemes are available 123 - - Sv32 -> Used for 2-level Page Tables 124 - - Sv39 -> For 3-levels 125 - - Sv48 -> For 4-levels! 126 - - xv6 uses Sv39 127 - - VA Size- 128 - 129 - ``` 130 - 39 bits 131 - 2^39 = 512 GB 132 - = 0x80-0000-0000 133 - ``` 134 - - But xv6 uses only 38 bits for its VAs 135 - 136 - ``` 137 - 38 bits 138 - 2^38 = 256 GB 139 - = 0x40-0000-0000 140 - ``` 141 - - Therefore the allowed range is - 0&#x2026;0x3F-FFFF-FFFF 142 - 143 - 144 - ## Startup 145 - 146 - We go from 147 - 148 - ``` 149 - entry.S -> start.c -> main.c 150 - (Setup Stack) (Machine Mode) (Supervisor Mode) 151 - ``` 152 -
-274
src/content/posts/xv6-mem-management/index.md
··· 1 - --- 2 - title: "xv6 - Memory Management" 3 - published: 2026-01-03 4 - draft: false 5 - description: 'How does xv6 manage memory?' 6 - series: 'xv6' 7 - tags: ["xv6","os"] 8 - --- 9 - 10 - We know that xv6 uses a simple freelist, keeping that in mind, let's take a look at [kalloc.c](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/kalloc.c)! 11 - 12 - - ```c 13 - extern char end[]; 14 - ``` 15 - 16 - First memory address after kernel. 17 - Defined by `kernel.ld` 18 - - ```c 19 - struct run { 20 - struct run *next; 21 - }; 22 - ``` 23 - 24 - This is the freelist. 25 - - ```c 26 - struct { 27 - struct spinlock lock; 28 - struct run *freelist; 29 - } kmem; 30 - ``` 31 - 32 - Protects the freelist with a lock. 33 - - ```c 34 - void 35 - kinit() 36 - { 37 - initlock(&kmem.lock, "kmem"); 38 - freerange(end, (void*)PHYSTOP); 39 - } 40 - ``` 41 - 42 - Initialises the lock and frees the entire memory space above the kernel. 43 - - ```c 44 - void 45 - freerange(void *pa_start, void *pa_end) 46 - { 47 - char *p; 48 - p = (char*)PGROUNDUP((uint64)pa_start); 49 - for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE) 50 - kfree(p); 51 - } 52 - ``` 53 - 54 - We go from `pa_start` to `pa_end` and free each page! 55 - 56 - The next two functions do require a closer look- 57 - 58 - 59 - # kfree 60 - 61 - ```c 62 - void 63 - kfree(void *pa) 64 - { 65 - struct run *r; 66 - 67 - if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) 68 - panic("kfree"); 69 - 70 - // Fill with junk to catch dangling refs. 71 - memset(pa, 1, PGSIZE); 72 - 73 - r = (struct run*)pa; 74 - 75 - acquire(&kmem.lock); 76 - r->next = kmem.freelist; 77 - kmem.freelist = r; 78 - release(&kmem.lock); 79 - } 80 - ``` 81 - 82 - Let's go line by line here. 83 - 84 - 1. ```c 85 - void 86 - kfree(void *pa) 87 - { 88 - struct run *r; 89 - 90 - ... 91 - } 92 - ``` 93 - 94 - - We take in physical address (`pa`) as input, which is a pointer that points to the page we want to free. 95 - - We also create `struct run` to actually manipulate memory. 96 - 2. ```c 97 - if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) 98 - panic("kfree"); 99 - ``` 100 - 101 - Here, we define the conditions in which `kfree` is invalid to run and should panic- 102 - 103 - - `(uint64)pa % PGSIZE != 0` -> The pointer `pa` is not page-aligned! 104 - 105 - - `(char*)pa < end` -> `pa` points to a kernel page! 106 - 107 - - `(uint64)pa >= PHYSTOP` -> `pa` points to a memory address larger than the physical memory! 108 - 109 - 3. ```c 110 - memset(pa, 1, PGSIZE); 111 - ``` 112 - 113 - As is quite obvious here, we fill the entire page with junk value so a snooping program cannot see the residual data. It also helps in debugging and catching dangling refs. 114 - 115 - 4. ```c 116 - r = (struct run*)pa; 117 - 118 - acquire(&kmem.lock); 119 - r->next = kmem.freelist; 120 - kmem.freelist = r; 121 - release(&kmem.lock); 122 - ``` 123 - 124 - Step-by-step execution of this block- 125 - 126 - - We assign the page to `r`. 127 - 128 - - We acquire the lock to memory. 129 - 130 - - We prepend this page to the start of the freelist. 131 - 132 - - We point the freelist pointer to `r`. 133 - 134 - - We release the lock on memory we are currently holding. 135 - 136 - And that concludes the `kfree` function! 137 - 138 - 139 - # kalloc 140 - 141 - ```c 142 - void * 143 - kalloc(void) 144 - { 145 - struct run *r; 146 - 147 - acquire(&kmem.lock); 148 - r = kmem.freelist; 149 - if(r) 150 - kmem.freelist = r->next; 151 - release(&kmem.lock); 152 - 153 - if(r) 154 - memset((char*)r, 5, PGSIZE); // fill with junk 155 - return (void*)r; 156 - } 157 - ``` 158 - 159 - Let's again analyse each line (only unique ones)- 160 - 161 - 1. ```c 162 - struct run *r; 163 - 164 - acquire(&kmem.lock); 165 - r = kmem.freelist; 166 - ``` 167 - 168 - We acquire the memory lock and point a variable `r` to it. 169 - 170 - 2. ```c 171 - if(r) 172 - kmem.freelist = r->next; 173 - release(&kmem.lock); 174 - ``` 175 - 176 - If r exists, we move freelist pointer to the 2nd node and release the lock. 177 - 178 - 3. ```c 179 - if(r) 180 - memset((char*)r, 5, PGSIZE); // fill with junk 181 - return (void*)r; 182 - ``` 183 - 184 - Again, if r exists, we fill it with junk to foil any would be snooper's plan! 185 - 186 - And that concludes the `kalloc.c` file in xv6 kernel! You are finally ready to conquer your memory!! 187 - 188 - Our final `kalloc.c` 189 - 190 - ```c 191 - // Physical memory allocator, for user processes, 192 - // kernel stacks, page-table pages, 193 - // and pipe buffers. Allocates whole 4096-byte pages. 194 - 195 - #include "types.h" 196 - #include "param.h" 197 - #include "memlayout.h" 198 - #include "spinlock.h" 199 - #include "riscv.h" 200 - #include "defs.h" 201 - 202 - void freerange(void *pa_start, void *pa_end); 203 - 204 - extern char end[]; // first address after kernel. 205 - // defined by kernel.ld. 206 - 207 - struct run { 208 - struct run *next; 209 - }; 210 - 211 - struct { 212 - struct spinlock lock; 213 - struct run *freelist; 214 - } kmem; 215 - 216 - void 217 - kinit() 218 - { 219 - initlock(&kmem.lock, "kmem"); 220 - freerange(end, (void*)PHYSTOP); 221 - } 222 - 223 - void 224 - freerange(void *pa_start, void *pa_end) 225 - { 226 - char *p; 227 - p = (char*)PGROUNDUP((uint64)pa_start); 228 - for(; p + PGSIZE <= (char*)pa_end; p += PGSIZE) 229 - kfree(p); 230 - } 231 - 232 - // Free the page of physical memory pointed at by pa, 233 - // which normally should have been returned by a 234 - // call to kalloc(). (The exception is when 235 - // initializing the allocator; see kinit above.) 236 - void 237 - kfree(void *pa) 238 - { 239 - struct run *r; 240 - 241 - if(((uint64)pa % PGSIZE) != 0 || (char*)pa < end || (uint64)pa >= PHYSTOP) 242 - panic("kfree"); 243 - 244 - // Fill with junk to catch dangling refs. 245 - memset(pa, 1, PGSIZE); 246 - 247 - r = (struct run*)pa; 248 - 249 - acquire(&kmem.lock); 250 - r->next = kmem.freelist; 251 - kmem.freelist = r; 252 - release(&kmem.lock); 253 - } 254 - 255 - // Allocate one 4096-byte page of physical memory. 256 - // Returns a pointer that the kernel can use. 257 - // Returns 0 if the memory cannot be allocated. 258 - void * 259 - kalloc(void) 260 - { 261 - struct run *r; 262 - 263 - acquire(&kmem.lock); 264 - r = kmem.freelist; 265 - if(r) 266 - kmem.freelist = r->next; 267 - release(&kmem.lock); 268 - 269 - if(r) 270 - memset((char*)r, 5, PGSIZE); // fill with junk 271 - return (void*)r; 272 - } 273 - ``` 274 -
-223
src/content/posts/xv6-spinlocking/index.md
··· 1 - --- 2 - title: "xv6 - SpinLocks" 3 - published: 2026-01-02 4 - draft: false 5 - description: 'Should I spin or should I lock?' 6 - series: 'xv6' 7 - tags: ["xv6","os"] 8 - --- 9 - 10 - 11 - 12 - # Spin Locking 13 - 14 - We know that xv6 uses SpinLocks, sleep and wakeup for its locking. In this post, let us discuss SpinLocks. 15 - 16 - SpinLocks are defined in [spinlock.c](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/spinlock.c). 17 - 18 - 19 - ## Basics 20 - 21 - There are primarily **two** functions related to locks, acquire and release 22 - 23 - :::warning 24 - Spin Locks should not be held for a long time as spinning wastes cycles! 25 - ::: 26 - 27 - :::tip 28 - In such cases, consider using `sleep()` and `wakeup()`! 29 - ::: 30 - 31 - 32 - ### acquire 33 - 34 - Acquiring the lock seems simple enough on the surface. 35 - 36 - ```c 37 - while (locked == 1); 38 - locked = 1; 39 - cpu = mycpu(); 40 - ``` 41 - 42 - But two processors can simultaniously execute this! Therefore we need an atomic operation to read and write to `locked` in one instruction. Fortunately RISC-V has one such instrcution - `AMOSWAP`, which we will use. 43 - 44 - Another thing to note is that we need to disable preemption or interrupts while we are in the critical section! 45 - 46 - Therefore, we have- 47 - 48 - ``` 49 - 1 -> [ Locked ] -> y 50 - if (y != 0) try again 51 - ``` 52 - 53 - 54 - ### release 55 - 56 - release is quite simple, just put value 0 in the locked field! 57 - 58 - 59 - ## Theory 60 - 61 - Now, `acquire()` disables the interrupts and `release()` re-enables them. But now, situations with multiple locks becomes problematic. 62 - 63 - ```c 64 - acquire(&lk1); 65 - acquire(&lk2); 66 - 67 - // Critical Section 68 - 69 - release(&lk2); // Interrupts re-enabled prematurely!! 70 - 71 - // Some more operations 72 - 73 - release(&lk1); 74 - ``` 75 - 76 - So, we store a counter `noff` and a status int `intena` (interrupts enabled) for each hart. 77 - 78 - If this is the first acquire (`noff =​= 0`), we set `intena` to current interrupt status (0 if disables, 1 otherwise). We then increment the counter regardless. 79 - 80 - During release, we decrement the counter and if it becomes 0, we restore the interrupts to their saved state in `intena`! 81 - 82 - 83 - ## Code 84 - 85 - 86 - ### Structure 87 - 88 - The struct spinlock itself, is defined in [spinlock.h](https://github.com/mit-pdos/xv6-riscv/blob/riscv/kernel/spinlock.h). 89 - 90 - ```c title="spinlock.h" 91 - struct spinlock { 92 - uint locked; // Is the lock held? 93 - 94 - // For debugging: 95 - char *name; // Name of lock. 96 - struct cpu *cpu; // The cpu holding the lock. 97 - }; 98 - ``` 99 - 100 - It contains an int `locked`, which indicates that the lock is free/unacquired when `locked = 0` and otherwise for `locked = 1` 101 - 102 - 103 - ### Imports 104 - 105 - We first import the necessary files. Nothing too exciting here. 106 - 107 - ```c title="imports" 108 - #include "types.h" 109 - #include "param.h" 110 - #include "memlayout.h" 111 - #include "spinlock.h" 112 - #include "riscv.h" 113 - #include "proc.h" 114 - #include "defs.h" 115 - ``` 116 - 117 - 118 - ### Initalising the lock 119 - 120 - Before we can even acquire the lock, we need to actually initialise it! Its steps are easy enough to be obvious. 121 - 122 - ```c title="initlock" 123 - void 124 - initlock(struct spinlock *lk, char *name) 125 - { 126 - lk->name = name; 127 - lk->locked = 0; 128 - lk->cpu = 0; 129 - } 130 - ``` 131 - 132 - 133 - ### Acquiring the Lock 134 - 135 - Let' start writing the acquire function! 136 - 137 - ```c 138 - void acquire(struct spinlock *lk) { 139 - <<aq_disable_interrupt>> 140 - <<aq_atomic_swap>> 141 - <<aq_misc>> 142 - } 143 - ``` 144 - 145 - 1. As discussed earlier we first disable the interrupts. `push_off()` takes care of that. We also ensure we already aren't holding the lock. 146 - 147 - ```c title="Disable Interrupts" 148 - push_off(); 149 - if(holding(lk)) 150 - panic("acquire"); 151 - ``` 152 - 153 - 2. ```c title="Atomic Swap and Loop" 154 - while(__sync_lock_test_and_set(&lk->locked, 1) != 0); 155 - ``` 156 - 157 - 3. We need to ensure that compiler optimisations do not mess with the order, also store the cpu's information in the struct. 158 - 159 - ```c title="Misc" 160 - __sync_synchronize(); 161 - lk->cpu = mycpu(); 162 - ``` 163 - 164 - Our final acquire function- 165 - 166 - ```c title="acquire" 167 - void acquire(struct spinlock *lk) { 168 - push_off(); 169 - if(holding(lk)) 170 - panic("acquire"); 171 - while(__sync_lock_test_and_set(&lk->locked, 1) != 0); 172 - __sync_synchronize(); 173 - lk->cpu = mycpu(); 174 - } 175 - ``` 176 - 177 - 178 - ### Releasing the lock 179 - 180 - Releasing is a lot simpler. 181 - 182 - ```c 183 - void release(struct spinlock *lk) { 184 - <<rl_misc>> 185 - <<rl_en_int>> 186 - } 187 - ``` 188 - 189 - 1. Ensure we are holding the lock, scrub cpu information, synchronise, and release the lock 190 - 191 - ```c title="Misc" 192 - if(!holding(lk)) 193 - panic("release"); 194 - 195 - lk->cpu = 0; 196 - 197 - __sync_synchronize(); 198 - 199 - __sync_lock_release(&lk->locked); 200 - ``` 201 - 202 - 2. Re-enable Interrupts 203 - 204 - ```c title="Interrupts" 205 - pop_off(); 206 - ``` 207 - 208 - Release function- 209 - 210 - ```c title="release" 211 - void release(struct spinlock *lk) { 212 - if(!holding(lk)) 213 - panic("release"); 214 - 215 - lk->cpu = 0; 216 - 217 - __sync_synchronize(); 218 - 219 - __sync_lock_release(&lk->locked); 220 - pop_off(); 221 - } 222 - ``` 223 -