{"id":25198120,"url":"https://github.com/hanfried/tlpigo","last_synced_at":"2025-05-08T22:43:52.088Z","repository":{"id":217790747,"uuid":"268110823","full_name":"hanfried/tlpigo","owner":"hanfried","description":"The Linux Programming Interface with go","archived":false,"fork":false,"pushed_at":"2020-06-30T15:08:55.000Z","size":21,"stargazers_count":9,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T22:43:46.420Z","etag":null,"topics":["c","golang","linux"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hanfried.png","metadata":{"files":{"readme":"README.org","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-30T15:48:18.000Z","updated_at":"2024-12-06T14:30:03.000Z","dependencies_parsed_at":null,"dependency_job_id":"581bcd15-07ad-48e9-8cfa-2719bf505c6c","html_url":"https://github.com/hanfried/tlpigo","commit_stats":null,"previous_names":["hanfried/tlpigo"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanfried%2Ftlpigo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanfried%2Ftlpigo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanfried%2Ftlpigo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hanfried%2Ftlpigo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hanfried","download_url":"https://codeload.github.com/hanfried/tlpigo/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253160727,"owners_count":21863624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","golang","linux"],"created_at":"2025-02-10T02:40:56.940Z","updated_at":"2025-05-08T22:43:52.080Z","avatar_url":"https://github.com/hanfried.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"#+TITLE: The Linux Programming Interface with Golang\n\n\nFollowing the famous [[https://www.man7.org/tlpi/][The Linux Programming Interface]] book from Michael Kerrisk.\nBut now in Golang (instead of C).\n\nI started this project to learn:\n- more details about how Linux works\n- Golang\n- something about System Programming (coming from a scripting language background)\n- understand C idioms and acronyms by working through the book (C has a simple\n  syntax, but many C programs are hard to understand without some practice in\n  reading/writing C code)\n\nI choosed Golang as:\n- it is easier to understand\n- has less gotchas than C (and thus is more practical to program)\n- it is the language of Kubernetes and DevOps (both matter to me in my profession)\n- it probably is also easier to start into system programming than with Rust\n\nIf you prefer videos: I'm putting content about this project on [[https://www.youtube.com/channel/UCN3M_sScbPDAD9G5yOWnFFA][my youtube channel]]\n\n* Structure\n\nI follow the structure of the [[https://www.man7.org/tlpi/code/download/tlpi-200424-dist.tar.gz][Distribution source C source code]].\nAll code examples are formatted with =gofmt= and linted with [[https://github.com/golangci/golangci-lint][golangci-lint --enable-all]].\nI try to organize the Golang code as described in https://github.com/golang-standards/project-layout.\n\n** Chapter 1 - History and Standards\n\nInteresting, but nothing to code.\n\n** Chapter 2 - Fundamental Concepts\n\nImportant, but still nothing to code.\n\n** Chapter 3 - System Programming Concepts\n\nHere, Michael Kerrisk starts coding and writes an own error handling module.\nThe concepts aren't really implementable the same way in Golang (unless we want to use \"unsafe\" constructs).\n\nWe find in the C source code 3 ways how programs could be terminated and several\nerror message functions. None of them really applies to the way Golang handles\ntermination and errors, so I only implemented a [[./internal/errors/functions.go][Terminate]] function that can be\ncalled with =go run ./cmd/errors/terminate.go= but it's not intended to be\nreally used.\n\n*** Aborting and Core Dump\n\nIf an environment variable =EF_DUMPCORE= is set, the C programs are supposed to\nrun C's =abort()= method what in the end raises an =ABORT= signal event what\nresults in abrupt termination of the program by the system and writing a core\ndump.\n\nIn principle we could implement it as well in Golang, but if I understand it\ncorrectly it is highly recommended *not* to abort a running Golang program. If\nwe want a core dump for what ever reason of a Go program, we only need to set\n=ulimit -c unlimited= (or set a number for how big the core dump should be max)\nand set environment variable =GOTRACEBACK=trash= to get a core dump when\nexiting.\n\n*** Immediate exiting without cleaning up\n\nThe C function =_exit()= stops the program without any flushing of file handlers\nor running =atexit()= methods. Even in C world, usually that's not the way to\nstop a program. It is intended to be used with for example forks where we don't\nwant to flush or close handlers shared.\n\nWe can implement this functionality in Golang with calling =os.Exit(EXIT_CODE)=.\nBut we should not need it in Golang as we don't need forks for parallelity as\nGolang has goroutines instead.\n\nWhat we might need from (e.g. when argument parsing fails) is writing a message\nand stop right there. We can use =log.Fatal(msg)= to achieve it, but even this\nis discussed whether it is code smell or not in Golang.\n\n*** Exit on error with cleaning up\n\nIn C we'd call =exit()= (now without the underscore) to achieve it. Michael\nKerrisk implements several functions to also dump a human readable error message\nalong for the =errno= or to write an own error message or to write a usage\nmessage if argument parsing fails.\n\nFirst of all, we have a different error approach in Golang. Instead of one\nglobal =errno= variable that can be affected everywhere in the program (that's\nwhy it's copied in the C sources), Golang returns an error variable for every\ncall that could fail. In case, this error variable knows already its human\nreadable error message by =err.Error()=. Indeed, there is no way and no need in\nGolang to lookup the corresponding error message for an =errno=. (Unless we want\nto import =\u003cerrno.h\u003e= from C). So, the usual way in Golang we communicate an\nerror to the program user is to call =panic(fmt.Sprintf(\"Something failed: %s\",\nerr.Error()))= and in addition to what C makes we also get a minimal stack trace.\n\nFor argument parsing, I'll use most of the time argument parsing modules, so no\nneed to implement =errUsage= methods here. This is debatable as there is some\noverhead with them (e.g. they might =malloc= memory), so in some system\nprogramming situations, this might not be the preferred way (e.g. to write a\ntool to inspect out of memory situations).\n\n** Chapter 4 - File I/O: The Universal I/O Model\n\nHere, first some basic fileio is implemented (opening, closing, writing, reading) in [[./pkg/fileio/fileio.go]]\n\nImplemented:\n- [[./pkg/fileio/copy.go][copy]] functionality that can be called with =go run cmd/fileio/copy/copy.go \u003cSRC\u003e \u003cDEST\u003e=\n- [[./cmd/fileio/seek/seek.go][seek]] program to write, read text and hex from a file and seek to a random position\n- [[./pkg/fileio/tee.go][tee]] functionality that can be called with =go run cmd/fileio/tee/tee.go --append \u003cDEST\u003e=\n- [[./pkg/fileio/sparse_copy.go][sparse copy]] functionality to copy files with holes that is active if set a\n  =--hole-size \u003cLENGTH\u003e= option to the [[./cmd/fileio/copy/copy.go][copy program]]\n\nYou can find a video about my implementation and discussion of[[https://www.youtube.com/watch?v=c0Z9vb9hzC0\u0026][ Chapter 3 and 4]].\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhanfried%2Ftlpigo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhanfried%2Ftlpigo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhanfried%2Ftlpigo/lists"}