מידע משתמש וקבוצה

getgrent#

קריאת הרשומה הבאה ממסד הנתונים של קבוצות המערכת.

getgrent עובר על מסד הנתונים של הקבוצות במארח רשומה אחת בכל פעם, כפי שלולאה רגילה על /etc/group הייתה קוראת אותו שורה־שורה, ומחזיר תצוגה בצורת Perl של כל רשומה. זוהי צורת האיטרטור של חיפושי הקבוצות - יש להשתמש בה כאשר רוצים כל קבוצה, או כל קבוצה התואמת לתנאי כלשהו. לחיפוש רשומה בודדת לפי שם או gid, יש לפנות במקום זאת ל־getgrnam או getgrgid.

קריאה ראשונה ל־getgrent פותחת את מסד הנתונים באופן מרומז. האיטרציה ממשיכה לאורך קריאות נוספות עד שמסד הנתונים מתרוקן, ואז getgrent מחזיר את הרשימה הריקה (או undef בהקשר סקלר). יש לקרוא ל־setgrent כדי לחזור להתחלה, או ל־endgrent כדי לסגור את מסד הנתונים ולשחרר משאבים שספריית C מחזיקה.

תקציר#

my ($name, $passwd, $gid, $members) = getgrent;
my $name                            = getgrent;        # scalar context

מה מקבלים בחזרה#

בהקשר רשימה, רשימה בת ארבעה איברים - רשומה אחת לכל קבוצה:

אינדקס

שדה

משמעות

0

$name

שם קבוצה (לדוגמה "wheel")

1

$passwd

סיסמת קבוצה, בדרך כלל "x" במארחים עם shadow-password

2

$gid

gid מספרי

3

$members

מחרוזת מופרדת ברווחים של שמות login של החברים

כאשר האיטרציה חוצה את הסוף, ההחזרה היא הרשימה הריקה. אם כותבים if (my @gr = getgrent) הלולאה מסתיימת בצורה נקייה בסוף מסד הנתונים.

בהקשר סקלר, getgrent מחזיר רק את $name. כאשר מסד הנתונים מתרוקן, הוא מחזיר undef - שזהו האות שרוב הסקריפטים בודקים מולו כדי לסיים לולאת while.

$members הוא מחרוזת רגילה, לא מערך. יש לפצל אותה על רווחים כאשר נדרשת הרשימה:

my @logins = split ' ', $members;

מצב גלובלי שהוא נוגע בו#

getgrent שומר מצב איטרציה לכל־תהליך בתוך ספריית C (קונספטואלית עמדה בקובץ בתוך מסד נתוני הקבוצות). שתי קריאות באותו תהליך חולקות את המצב הזה; לולאה מקוננת הקוראת ל־getgrent בתוך לולאת getgrent אחרת תשלב רשומות ותפספס את רובן. יש לסדר את המעברים בטור, או לקלוט תחילה את כל הרשומות למערך:

my @all;
while (my @gr = getgrent) { push @all, [ @gr ] }
endgrent;

האיטרטור אינו מאופס כאשר תת־שגרה חוזרת. אם קוד ספרייה שאינך שולט בו קורא ל־getgrent, הוא מזיז את העמדה שלך. יש להישמר עם setgrent כאשר נדרשת התחלה נקייה.

דוגמאות#

מעבר על כל קבוצה והדפסת השם ומספר החברים:

while (my ($name, undef, $gid, $members) = getgrent) {
    my $n = length $members ? scalar(split ' ', $members) : 0;
    printf "%-16s gid=%d members=%d\n", $name, $gid, $n;
}
endgrent;

איסוף כל הקבוצות ש־login נתון שייך אליהן:

my $user = 'alice';
my @groups;
while (my ($name, undef, undef, $members) = getgrent) {
    push @groups, $name
        if grep { $_ eq $user } split ' ', $members;
}
endgrent;

הקשר סקלר - מנייה של כל שמות הקבוצות, אחד בכל שורה:

while (defined(my $name = getgrent)) {
    print $name, "\n";
}
endgrent;

חזרה לאחור וקריאה מחדש, לדוגמה לבניית שני אינדקסים במעבר אחד כל אחד:

setgrent;
my %by_name = map { $_->[0] => $_ }
              map { [ getgrent ] } 1 .. ();   # collect…
# …or just loop twice with an explicit setgrent before each pass.
setgrent;
while (my @gr = getgrent) { ... }
endgrent;

המרת gid מספרי מ־stat לשם קבוצה ללא חיפוש שני על־ידי שמירה במטמון של פלט האיטרטור:

my %name_of;
while (my ($name, undef, $gid) = getgrent) {
    $name_of{$gid} = $name;
}
endgrent;

my $gid = (stat $path)[5];
print "group: $name_of{$gid}\n";

מקרי קצה#

  • סוף האיטרציה מול רשומה אמיתית: בהקשר רשימה, מסד נתונים שהתרוקן מחזיר את הרשימה הריקה - שמוקצת כאפס איברים, כך ש־my @gr = getgrent; @gr or last; הוא בדיקת הסיום האידיומטית. בהקשר סקלר, יש לבדוק עם defined ולא עם אמיתיות, מאחר ששם קבוצה לגיטימי יכול בעיקרון להיות המחרוזת "0".

  • אין שדה סיסמה ב־Linux מודרני: $passwd הוא כמעט תמיד "x" (ה־hashes האמיתיים חיים ב־/etc/gshadow). אין להתייחס לערך שאינו "x" כ“סיסמה מוגדרת“ מבלי להתייעץ עם מסד הנתונים shadow.

  • $members ריק: לקבוצות ללא חברים מפורשים (משתמשים הרשומים רק לפי gid ראשי) $members הוא המחרוזת הריקה. split ' ', "" מחזיר רשימה ריקה - הדרך האידיומטית לקבל חברים כמערך ללא מקרה מיוחד.

  • חברות מרומזת לפי primary-gid אינה מדווחת: $members מציג רק את המשתמשים הנקובים במפורש ברשומת /etc/group של הקבוצה. משתמש שה־primary gid שלו תואם לקבוצה הזו אך אינו רשום גם בשדה members אינו מופיע. יש להצליב עם getpwent אם נדרשים שני סוגי החברות.

  • איטרציה מקוננת הורסת את העמדה: לולאת getgrent שנייה שמתחילה לפני שהראשונה מסתיימת חולקת את אותו סמן. יש להשתמש ב־setgrent בין מעברים, או לקלוט תחילה תמונת מצב של מסד הנתונים לזיכרון.

  • מצב taint: השדה $passwd מסומן כ־tainted תחת -T, בדומה ל־getpwent - יש להתייחס אליו כקלט בלתי־אמין על אף שהערך הרגיל הוא "x".

  • ברמת תהליך, לא ברמת thread: במערכות ללא וריאנטים בטוחים ל־threads, מצב האיטרציה הוא לכל־תהליך, לא לכל־thread. שני threads שמהלכים על getgrent בו־זמנית יפספסו רשומות.

  • endgrent אופציונלי אך מנומס: השארת מסד הנתונים פתוח עד יציאת התוכנית עובדת, אך אם סיימת לאיטר, יש לקרוא ל־endgrent כדי שספריית C תוכל לוותר על המאגרים שלה.

הבדלים מהמקור#

תאימות מלאה עם Perl 5.42 המקורי.

ראו גם#

  • getgrnam - חיפוש בודד לפי שם קבוצה; לשימוש כאשר השם כבר ידוע ונרצית רק רשומה אחת

  • getgrgid - חיפוש בודד לפי gid מספרי; השותף הרגיל של stat כאשר נדרש שם קבוצה עבור קובץ

  • setgrent - חזרה לאחור של האיטרטור להתחלת מסד הנתונים של הקבוצות לפני מעבר סריקה מלאה נוסף

  • endgrent - סגירת מסד הנתונים ושחרור משאבים שספריית C מחזיקה פתוחים

  • getpwent - האיטרטור המקביל על מסד הנתונים passwd; יש לשלב עם getgrent בעת פתרון יחסי משתמש־לקבוצה מלאים

  • scalar - אילוץ הקשר סקלר כאשר נדרש רק שם הקבוצה ורוצים לדלג על השדות האחרים