4 पॉइंट द्वारा GN⁺ 2023-09-10 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • GNU coreutils 8.3 source structure को utility-दर-utility पढ़ते हुए समझाने वाला एक दीर्घकालिक व्याख्या प्रोजेक्ट, जो command-line tool design सीख रहे शुरुआती programmers के लिए बनाया गया है
  • यह उपयोग-निर्देश documentation नहीं, बल्कि source code पढ़ने में मदद करने वाला material है; इसमें हर command के namespace, execution flow, design decisions, algorithms, UNIX और शुरुआती Coreutils lineage को साथ में कवर किया गया है
  • coreutils में छोटे और single-purpose C programs बहुत हैं, इसलिए global variables, macros, goto, लंबी functions जैसे आधुनिक नज़रिए से rough code patterns को भी ऐतिहासिक context में पढ़ना चाहिए
  • common flow initialization, option parsing, input handling, system calls चलाने और failure handling से होकर जाता है; getopt_long(), fts, gnulib helpers बार-बार दिखाई देते हैं
  • contribution या बदलाव से पहले यह जांचना चाहिए कि क्या existing tools से उसे reproduce किया जा सकता है, क्या वह backward compatibility तोड़ता है, और POSIX से कितना अलग है

GNU coreutils व्याख्या प्रोजेक्ट का दायरा

  • यह GNU coreutils 8.3 की सभी utilities को समझाने वाला दीर्घकालिक project है
  • target readers command-line utilities के design को देख रहे शुरुआती programmers हैं
  • जिस utility में आपकी रुचि हो, उसका source code पढ़ते समय इसे background explanation के तौर पर साथ देखने के लिए यह सबसे उपयुक्त है
  • यह material user manual नहीं है; असल usage के लिए man pages देखें
  • project कई phases से बना है
    • Phase 1: हर utility के namespace और execution overview pages पूरे
    • Phase 2: प्रमुख design decisions और algorithms, UNIX और शुरुआती Coreutils lineage, ज्यादा उपयोगी source walkthroughs, source code evolution visualization पूरे
    • Phase indefinite: हर utility के line-by-line code walkthroughs लंबे समय तक जारी रहने वाले काम के रूप में बचे हैं
    • line-by-line notes इकट्ठा करने के लिए GitHub repo उपलब्ध है

utility-wise explanation pages

  • हर command name उस utility को decode करने वाले detailed page से जुड़ा है
  • हर page में discussion, source code और walkthrough शामिल हैं
  • bold में दिखी utilities Phase 2 में expanded items हैं
  • list में arch, base64, cat, chmod, cp, date, dd, df, ls, rm, sort, tail, tr, wc, yes आदि GNU coreutils commands शामिल हैं

code पढ़ने से पहले जानने योग्य assumptions

  • coreutils की कई utilities का इतिहास लगभग 30 साल पुराना है, और कई लोगों ने लंबे समय में इस code को modify किया है
  • ज्यादातर छोटी और single-purpose के लिए बनी छोटी programs हैं
    • आम तौर पर single source file programs हैं
    • यह ऐसा code नहीं है जिसे बहुत लंबे समय तक टिकने या अपने role से ज्यादा expand होने के लिए design किया गया हो
    • global variables, macros, goto, nested switch/loops वाली लंबी functions जैसे patterns दिखते हैं
  • POSIX की जानकारी code समझने में अहम है
    • Utility Syntax Guidelines से शुरू करना बेहतर है
    • POSIX input और output की interoperability define करता है, लेकिन असल काम करने का तरीका implementation पर छोड़ता है
    • GNU coreutils POSIX का सख्ती से पालन न करे, फिर भी permission bits, uid/gid, environment variables, exit status जैसे concepts गहराई से बसे हैं
  • portability issues की वजह से coreutils gnulib पर काफी निर्भर है
    • लगभग हर utility में ऐसे gnulib functions शामिल हैं जो कई systems पर common issues handle करने के लिए design किए गए हैं
  • coreutils को bash, zsh, ksh जैसे shells के support के साथ चलना माना जाता है
    • shell fork/clone से utility चलाता है, arguments pass करता है, environment set करता है, pipes के जरिए input/output redirect करता है, और exit value preserve करता है
  • GNU coreutils मूल रूप से shell, text और file utilities नाम के तीन packages से शुरू हुआ था, और same type की utilities कई design patterns share करती हैं

basic design patterns

  • ज्यादातर CLI utilities में आम तौर पर तीन stages होते हैं
    • flags, options, localization आदि तैयार करने वाला setup stage
    • input पढ़कर execution parameters तय करने वाला argument parsing stage
    • input तैयार करके उसे एक या अधिक system calls को देने वाला processing/execution stage
  • execution के दौरान कई points पर constraints check किए जा सकते हैं और failure हो सकता है
    • अलग-अलग exit statuses problem की जगह का hint दे सकते हैं
    • EXIT_FAILURE अक्सर generic failure status के रूप में इस्तेमाल होता है
  • failure के बाद user को feedback दिया जाता है
  • utility variants तीन groups में बंटते हैं
    • Trivial utilities: कुछ lines के macros define करने के बाद किसी दूसरी utility का source include करती हैं, और macros से specific flow control force करती हैं। उदाहरण: arch, dir, vdir
    • Wrapper utilities: setup और option parsing के बाद command-line options को सीधे system call arguments में pass करती हैं। system call का result ही utility का result बनता है, और अपनी processing कम होती है। उदाहरण: link, whoami, hostid, logname
    • Full utilities: setup, option/argument parsing, input data processing और कई system calls चलाने तक सब कुछ रखती हैं; ज्यादातर utilities इसी category में आती हैं

common initialization और option parsing

  • सभी utilities में main() की शुरुआत में छोटा initialization procedure होता है
    • initialize_main (&argc, &argv);
    • set_program_name (argv[0]);
    • setlocale (LC_ALL, "");
    • bindtextdomain (PACKAGE, LOCALEDIR);
    • textdomain (PACKAGE);
    • atexit (close_stdout);
  • यह preprocessing code internationalization और exit-time behavior registration जैसे administrative tasks handle करता है, और individual utility के core behavior को प्रभावित नहीं करता
  • command-line option parsing में Getopt tools की मुख्य भूमिका है
    • short options -, long options -- prefix का उपयोग करते हैं
    • short options string से define होते हैं, और long options struct का उपयोग करते हैं
    • short option string में अगर argument नहीं है तो सिर्फ character लिखा जाता है, required argument के लिए :, optional argument के लिए :: लगाया जाता है
    • kill की short option string Lln:s:t का मतलब है कि L, l, t में arguments नहीं हैं और n, s में arguments चाहिए
    • सभी utilities में getopt_long() next option return करने के लिए इस्तेमाल होता है
    • optind, argv[] array में next argument की position दिखाता है
    • optarg option argument value की ओर इशारा करने वाला character pointer है

file system traversal और system call helpers

  • Unix-like systems में file system traversal को आसानी से handle करने के लिए अक्सर fts library का support होता है
    • fts_open() या xfts_open() से path से FTS structure बनाया जाता है
    • tree की file या directory nodes FTSENT structure से represent होती हैं
    • fts_read() call करने पर FTSENT generate होता है, और यही process tree traversal है
    • FTSENT->fts_info field अक्सर item description में इस्तेमाल होता है, और item को कैसे process करना है यह तय करने में उपयोग किया जाता है
  • coreutils, libc द्वारा दिए गए functions के अलावा भी कई system call wrappers और helpers इस्तेमाल करता है
  • write handling में write() system call wrapper और fwrite() जैसे libc functions के अलावा full_write() जैसे non-standard functions दिखते हैं
    • full_write() hard failure न हो तो writing retry करता रहता है
    • safe_write() interrupt होने पर भी write() system call retry करता है
    • dd का iwrite(), split का cwrite() जैसे write helpers भी हैं जो केवल single utility में इस्तेमाल होते हैं

common functions और code idioms

  • सभी utilities कम से कम main(), usage(), _() तीन functions इस्तेमाल करती हैं
  • usage() input parameters, meaning और सही syntax सहित help दिखाता है
  • _() system.h में defined macro है, और plain strings को GNU gettext.h की Native Language Support functionality से जोड़ता है
    • user को दिखाई जाने वाली string हो तो आम तौर पर इस macro से wrap की जाती है
  • ज्यादातर non-trivial utilities में common code lines repeat होती हैं
    • #include "system.h" system-dependent macros, variables और non-standard utility functions define करता है
    • PROGRAM_NAME utility का official name define करता है और version checking में इस्तेमाल होता है
    • AUTHORS utility authors define करता है और version checking में इस्तेमाल होता है
    • emit_try_help() failed output के बाद help suggestion print करता है
    • emit_ancillary_info (PROGRAM_NAME) command-specific output के बाद common extra help info print करता है
    • initialize_main(&argc, &argv) VMS की built-in wildcard expansion handle करता है, और अधिकांश दूसरे operating systems में remove हो जाता है
    • atexit(close_stdout) program exit पर buffered streams को flush और close करने वाला function register करता है
  • C idioms भी आते हैं जो beginners के लिए अपरिचित हो सकते हैं
    • !! double unary NOT operation है, जिसका उपयोग value को boolean में force-convert करने के लिए होता है
    • do { ... } while (0) multiple-statement macro को wrap करके preprocessor substitution के बाद tokenization सुरक्षित बनाने वाला non-loop pattern है

maintenance approach और contribution से पहले checks

  • coreutils जैसे active projects आम तौर पर तीन maintenance flows से evolve होते हैं
  • project-wide changes सभी utilities की structure और dependencies में फैले बड़े changes होते हैं
    • 1995 में GNU gettext project के जरिए Native Language Support जोड़ा गया, जिससे text output की अधिकांश lines में _() macro आया
    • 1996 में internationalization support बढ़ा और main() में कई initialization code जोड़े गए
    • 1995 में usage output में utility purpose का छोटा description जोड़ा गया
    • 2003 में VMS wildcard support जोड़ा गया, जो initialize_main() function में दिखता है
    • 2016 में failure paths में compiler warnings से बचने के लिए die() macro ने अधिकांश exit() और error() functions की जगह ली
  • utility-specific changes bug fixes, new features और optimizations में बंटते हैं
    • join, sort, uniq 2016 के patch से पहले overflow attacks के लिए vulnerable थे
    • df में 2013 में --output option जोड़ा गया
    • yes की performance बेहतर buffering से improve हुई
  • annual maintenance में कम से कम सभी utilities के copyright years update करना शामिल होता है
    • FSF address update जैसे administrative changes भी होते हैं और execution पर असर नहीं डालते
  • contributors को पहले GNU project page, contribution guidelines, rejected features, mailing list archives देख लेना बेहतर है
  • code लिखने से पहले जांचने के लिए तीन सवाल हैं
    • क्या existing tools से वही function reproduce किया जा सकता है
    • क्या contribution backward compatibility तोड़ता है
    • क्या proposed behavior POSIX से काफी अलग है
  • अगर भरोसा न हो तो mailing list पर community से पूछने की प्रक्रिया recommend की जाती है

दिलचस्प details

  • सबसे छोटी utility false है और 2 lines की है; arch, dir, vdir भी बराबर हैं
  • सबसे छोटी standalone utility true है, 80 lines की; इसका first version लगभग minimal C program जैसा है
  • सबसे लंबी utility ls है, 5308 lines की
  • कई utilities 1970s के Research UNIX तक जाती हैं, और कुछ Multics तक
  • सबसे पुराना conceptual ancestor लगभग 1963 का CTSS LISTF command है, जो बाद में छोटा होकर ls बना
    • LISTF, 1962 design paper की original 18 utilities में से एक है
  • dd का अनोखा syntax 1960s की शुरुआत के OS/360 job control language की याद दिलाता है
  • sort multithreading का उपयोग करने वाली इकलौती utility है
  • fmt feature cost का उपयोग करके line और paragraph optimization दिखाता है
  • yes high-performance output के लिए page-aligned memory buffer का उपयोग करता है
  • df device metadata का उपयोग करता है, और du हर file check करता है, इसलिए df तेज है
  • cksum में normal execution और CRC-32 table generation के लिए दो entry points हैं
  • echo में कोई failure condition नहीं है
  • test और expr का design common utility structure से काफी अलग है
  • su को originally coreutils/shellutils में maintain किया जाता था

देखने लायक implementations

  • shuf और shred random numbers के लिए ISAAC cipher) का उपयोग करते हैं
  • shuf Reservoir sampling का उपयोग करता है
  • sum legacy System V और BSD checksums का उपयोग करता है
  • expr left-associative expression evaluation का उपयोग करता है
  • shred Secure overwrite का उपयोग करता है
  • cksum CRC-32 checksum calculate करता है
  • sort Merge sort का modified रूप इस्तेमाल करता है
  • factor mathematical implementation elements देखने लायक utility है

sponsorship notice

  • personal sponsorship लेने की setup नहीं है
  • अगर आप समय या पैसे share करना चाहते हैं, तो Free Software Foundation में contribute कर सकते हैं

1 टिप्पणियां

 
GN⁺ 2023-09-10
Hacker News की राय
  • अगर यह कहा जा रहा है कि “इन utilities में से कई लगभग 30 साल पुरानी हैं, और इस दौरान कई लोगों ने उन्हें modify किया है”, लेकिन साथ ही “इन्हें लंबी उम्र या अपनी भूमिका से आगे expand होने के लिए design नहीं किया गया था”, तो मैं देखना चाहूंगा कि लेखक के हिसाब से लंबी उम्र को ध्यान में रखकर बना program कैसा होता है
    जिज्ञासा है कि क्या कोई ऐसा program है जो 30 साल तक टिक चुका हो, या ऐसा जिसे वे मानते हों कि अगले 30 साल चलेगा

    • सवाल यह है कि उसकी भूमिका आखिर ठीक-ठीक क्या है. मुझे लगता है कि इन tools से जो किया जा सकता है, उसकी कोई सीमा है भी या नहीं
      मैंने अपनी छोटी-सी programming language को test करने के लिए bash और coreutils से test framework बनाया था. शुरुआत में “proper” language न इस्तेमाल करने पर थोड़ा अजीब लगा, लेकिन असल में यह बहुत अच्छी तरह चला और parallel execution भी हुआ
      सिर्फ एक चीज test नहीं कर पाया: program का argv[0]. कितने भी combinations करके देखे, मनचाहा behavior ठीक से नहीं बन पाया, इसलिए मैंने coreutils को env feature request और patch भेजा: https://lists.gnu.org/archive/html/coreutils/2023-08/msg0006...
      लगता है यह शामिल हो जाएगा, यानी एक पुराने program में नया feature जुड़ने जैसा होगा
    • यहां कही बात को शायद “लंबे समय तक actively developed रहने के लिए बनाया गया” के अर्थ में समझना चाहिए
      लेखक ने जिन practices की सूची दी है, उन्हें बड़े programs में आम तौर पर scale बढ़ने के साथ maintainability को नुकसान पहुंचाने वाली चीजों के रूप में criticize किया जाता है
    • शायद मतलब “लंबी development life” था. यानी लगभग एक बार लिखो और लंबे समय तक इस्तेमाल करो वाली utility, और यह “एक काम अच्छी तरह करो” वाले तरीके का फायदा भी है
    • अजीब बात है कि मैंने “long life” को लगातार चलते रहने वाले program के रूप में समझा. इसे साफ input, short run और साफ output वाले tool के contrast में देखा
    • Emacs?
  • संदर्भ के लिए उपयोगी सामग्री:
    GNU coreutils testing का तरीका: https://www.pixelbeat.org/docs/coreutils-testing.html
    coreutils के हर command की पड़ताल: https://ratfactor.com/slackware/pkgblog/coreutils
    GNU Coreutils के साथ command-line text processing: https://learnbyexample.github.io/cli_text_processing_coreuti... — मेरी ebook, जिसमें 20 से ज्यादा text processing tools cover हैं

  • संबंधित लेख:
    Decoded: GNU Coreutils (2018) - https://news.ycombinator.com/item?id=29871037 - जनवरी 2022, 7 comments
    Decoded: GNU coreutils (2019) - https://news.ycombinator.com/item?id=26411908 - मार्च 2021, 38 comments
    Decoded: GNU Coreutils - https://news.ycombinator.com/item?id=20328650 - जुलाई 2019, 55 comments

  • एक दिलचस्प बात: macOS पर Homebrew से coreutils install करने पर, क्योंकि macOS में पहले से od(1) मौजूद है, coreutils का od god(1) के रूप में install होता है

  • अगर लेखक यह देख रहे हों, तो कम से कम एक गलती है. shred page का short description[0] असल में csplit का description[1] है, और यह कुछ ऐसा होना चाहिए: “file contents को छिपाने के लिए overwrite करता है और optionally delete करता है”
    [0]: https://maizure.org/projects/decoded-gnu-coreutils/shred.htm...
    [1]: https://maizure.org/projects/decoded-gnu-coreutils/csplit.ht...

  • मुझे पता नहीं था कि ऐसा कुछ है, बढ़िया है. yes जैसा simple tool भी यह देखने के लिए काफी रोचक है कि standard output पर लिखने वाली utility का basic code कैसे लिखा जाता है
    https://maizure.org/projects/decoded-gnu-coreutils/yes.html

    • मेरा point यह है कि simple utility भी अच्छी तरह लिखे और optimize किए जाने लायक होती है
      उदाहरण के लिए, output को बहुत तेजी से लिखने का तरीका सीखने के लिए एक minimal example होना अच्छा है. program इतना छोटा है कि lines की संख्या ज्यादा मायने नहीं रखती, और अगर author तरीका जानता है तो उसे जितना हो सके उतना fast बनाना बेहतर है, ताकि वह bottleneck न बने
    • मजे के लिए बनाया गया Go implementation यह है:
      package main
      
      import "flag"
      
      func main() {  
      yes := flag.String("m", "y", "message")  
      flag.Parse()  
      for {  
      println(*yes)  
      }  
      }  
      
  • बेसिक utilities की सूची के तौर पर काफ़ी दिलचस्प। UNIX बहुत लंबे समय से इस्तेमाल किया है, फिर भी shred, shuf, factor जैसी चीज़ों के बारे में कभी सुना नहीं था
    एक बार

    sudo find / -type f -exec shred {} \;  
    

    चलाकर देखने का मन होता है कि यह खुद को मारने से पहले कितनी दूर तक जाता है। बेशक virtual machine या ऐसे डिवाइस पर जिसे आसानी से दोबारा flash किया जा सके

    • ऐसा ही कुछ dd से करके देखा था, लेकिन वह अंत तक पूरा हो गया और काफ़ी एंटी-क्लाइमैक्स लगा
      उम्मीद थी कि crash होगा या कम से कम connection टूट जाएगा, लेकिन kernel और sshd, bash अब भी memory में थे, इसलिए एक ऐसे prompt पर वापस आ गया जिससे कुछ भी ठीक से नहीं किया जा सकता था
    • Linux पर शायद इसके अंत तक जाने की संभावना ज़्यादा है। मौजूदा चल रही executables और libraries पर लिखा नहीं जा सकता (ETXTBUSY), इसलिए shred खुद को या find को खराब नहीं कर पाएगा
  • मुझे यह बात पसंद है कि /bin/true असल में fail होकर false return कर सकता है। तकनीकी तौर पर “Not /bin/false” call ज़्यादा robust हो जाता है: https://github.com/coreutils/coreutils/blob/master/src/true....
    पता है कि ऐसा लगभग कभी नहीं होगा, लेकिन बस मज़ेदार है

    • true command में एक और दिलचस्प बात यह है कि यह ज़रूरत से कहीं ज़्यादा complex हो गया है
      पहले एक exercise:
      touch mytrue  
      chmod u+x mytrue  
      ./mytrue  
      echo "error code for mytrue is $?"  
      
      true सचमुच इसी तरह शुरू हुआ था। काफ़ी Zen जैसा
      पहला बदलाव legal वजहों से था। हर code में copyright notice होना चाहिए था, और खाली file में भी चाहिए था। इसलिए कुछ न होने वाली file, सिर्फ copyright notice वाली file बन गई, और सवाल उठा कि “क्या कुछ भी नहीं पर copyright लगाया जा सकता है?” AT&T ने कोशिश की थी
      फिर किसी ने कहा कि program well-defined होना चाहिए और Unix के accidental behavior पर निर्भर नहीं रहना चाहिए, और उस समय यह काफ़ी reasonable था। इसलिए true में आखिरकार code आया, और वह code exit 0 था
      फिर किसी ने कहा कि system utilities को shell के बजाय C में लिखना चाहिए ताकि वे तेज़ हों, और OpenBSD में उसका एक अच्छा उदाहरण अब भी है: http://cvsweb.openbsd.org/cgi-bin/cvsweb/~checkout~/src/usr....
      किसी समय GNU bureaucracy बीच में आई और कहा कि हर program को -h flag support करना चाहिए, फिर कहा कि हर program को locale support करना चाहिए, इसलिए आज का GNU true हैरानी की बात है कि 80 lines का हो गया: https://github.com/coreutils/coreutils/blob/master/src/true....
      इसे ठीक भी माना जा सकता है, लेकिन जिस program की परिभाषा ही “कुछ न करना और सफल होना” है, उसके लिए code काफ़ी ज़्यादा है
      http://trillian.mit.edu/~jc/humor/ATT_Copyright_true.html
    • क्या ऐसा सिर्फ options के साथ चलाने पर नहीं होता? सिर्फ true चलाने से, अगर comment गुमराह नहीं कर रही है, कोई असर नहीं दिखता
  • अगर कोई beginner programmer data structures और algorithms को उपयोगी तरीके से apply करने की समझ बढ़ाना चाहता है, तो क्या यहां कुछ खास देखने लायक है?

    • coreutils में ज़्यादातर cleverness data structures और algorithms से ज़्यादा kernel के साथ effectively interact करने के तरीके में है
      जैसे data को user space में copy न करने के लिए read()/write() की जगह copy_file_range() इस्तेमाल करना। यह computer science से ज़्यादा software engineering के करीब है
    • शायद मैं गलत समझ रहा हूं, लेकिन मुझे नहीं पता कि data structures और algorithms का command-line tools से क्या संबंध है
  • हो सकता है मैं इस site का point miss कर रहा हूं, लेकिन क्या हर एक के लिए पहले से man page या info page नहीं है?

    • usage information नहीं, यह site विस्तार से बताती है कि program internally कैसे काम करता है