From 94225e07fcc27f01edd4faee2391000f54a9aceb Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Wed, 19 Jan 2011 12:42:53 +0000 Subject: 28638: add $usergroups parameter --- ChangeLog | 8 ++- Doc/Zsh/mod_parameter.yo | 6 ++ NEWS | 8 +++ Src/Modules/parameter.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++- Src/zsh.h | 17 ++++++ 5 files changed, 176 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90eed33df..b73f63e45 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2011-01-19 Peter Stephenson + + * 28638: Doc/Zsh/parameter.yo, Src/zsh.h, + Src/Modules/parameter.c, plus NEWS added: add $usergroups hash + mapping from user's own groups by name to GID. + 2011-01-18 Peter Stephenson * Mikael: 28637: Src/subst.c: ${foo:0:} caused crash. @@ -14147,5 +14153,5 @@ ***************************************************** * This is used by the shell to define $ZSH_PATCHLEVEL -* $Revision: 1.5188 $ +* $Revision: 1.5189 $ ***************************************************** diff --git a/Doc/Zsh/mod_parameter.yo b/Doc/Zsh/mod_parameter.yo index d553070a8..5948d74f2 100644 --- a/Doc/Zsh/mod_parameter.yo +++ b/Doc/Zsh/mod_parameter.yo @@ -164,6 +164,12 @@ item(tt(userdirs))( This associative array maps user names to the pathnames of their home directories. ) +vindex(usergroups) +item(tt(usergroups))( +This associative array maps names of system groups of which the current +user is a member to the corresponding group identifiers. The contents +are the same as the groups output by the tt(id) command. +) vindex(funcfiletrace) item(tt(funcfiletrace))( This array contains the absolute line numbers and corresponding file diff --git a/NEWS b/NEWS index 3d2baaf56..0897bab2a 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,14 @@ CHANGES FROM PREVIOUS VERSIONS OF ZSH Note also the list of incompatibilities in the README file. +Changes since 4.3.11 +-------------------- + +The zsh/parameter module has a new readonly associative array +$usergroups whose keys are the names of system groups of which the +current user is a member and whose values are the corresponding +group identifiers. + Changes between versions 4.3.10 and 4.3.11 ------------------------------------------ diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index 793249f32..092efa0c3 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1820,6 +1820,141 @@ scanpmdissaliases(HashTable ht, ScanFunc func, int flags) scanaliases(sufaliastab, ht, func, flags, ALIAS_SUFFIX|DISABLED); } + +/* Functions for the usergroups special parameter */ + +/* + * Get GID and names for groups of which the current user is a member. + */ + +/**/ +static Groupset get_all_groups(void) +{ + Groupset gs = zhalloc(sizeof(*gs)); + Groupmap gaptr; + gid_t *list, *lptr, egid; + int add_egid; + struct group *grptr; + + egid = getegid(); + add_egid = 1; + gs->num = getgroups(0, NULL); + if (gs->num > 0) { + list = zhalloc(gs->num * sizeof(*list)); + if (getgroups(gs->num, list) < 0) { + return NULL; + } + + /* + * It's unspecified whether $EGID is included in the + * group set, so check. + */ + for (lptr = list; lptr < list + gs->num; lptr++) { + if (*lptr == egid) { + add_egid = 0; + break; + } + } + gs->array = zhalloc((gs->num + add_egid) * sizeof(*gs->array)); + /* Put EGID if needed first */ + gaptr = gs->array + add_egid; + for (lptr = list; lptr < list + gs->num; lptr++) { + gaptr->gid = *lptr; + gaptr++; + } + gs->num += add_egid; + } else { + /* Just use effective GID */ + gs->num = 1; + gs->array = zhalloc(sizeof(*gs->array)); + } + if (add_egid) { + gs->array->gid = egid; + } + + /* Get group names */ + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + grptr = getgrgid(gaptr->gid); + if (!grptr) { + return NULL; + } + gaptr->name = dupstring(grptr->gr_name); + } + + return gs; +} + +/* Standard hash element lookup. */ + +/**/ +static HashNode +getpmusergroups(UNUSED(HashTable ht), const char *name) +{ + Param pm = NULL; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + pm = (Param)hcalloc(sizeof(struct param)); + pm->node.nam = dupstring(name); + pm->node.flags = PM_SCALAR | PM_READONLY; + pm->gsu.s = &nullsetscalar_gsu; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; + } + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + if (!strcmp(name, gaptr->name)) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm->u.str = dupstring(buf); + return &pm->node; + } + } + + pm->u.str = dupstring(""); + pm->node.flags |= PM_UNSET; + return &pm->node; +} + +/* Standard hash scan. */ + +/**/ +static void +scanpmusergroups(UNUSED(HashTable ht), ScanFunc func, int flags) +{ + struct param pm; + Groupset gs = get_all_groups(); + Groupmap gaptr; + + if (!gs) { + zerr("failed to retrieve groups for user: %e", errno); + return; + } + + memset((void *)&pm, 0, sizeof(pm)); + pm.node.flags = PM_SCALAR | PM_READONLY; + pm.gsu.s = &nullsetscalar_gsu; + + for (gaptr = gs->array; gaptr < gs->array + gs->num; gaptr++) { + pm.node.nam = gaptr->name; + if (func != scancountparams && + ((flags & (SCANPM_WANTVALS|SCANPM_MATCHVAL)) || + !(flags & SCANPM_WANTKEYS))) { + char buf[DIGBUFSIZE]; + + sprintf(buf, "%d", (int)gaptr->gid); + pm.u.str = dupstring(buf); + } + func(&pm.node, flags); + } +} + + /* Table for defined parameters. */ struct pardef { @@ -1926,7 +2061,9 @@ static struct paramdef partab[] = { SPECIALPMDEF("saliases", 0, &pmsaliases_gsu, getpmsalias, scanpmsaliases), SPECIALPMDEF("userdirs", PM_READONLY, - NULL, getpmuserdir, scanpmuserdirs) + NULL, getpmuserdir, scanpmuserdirs), + SPECIALPMDEF("usergroups", PM_READONLY, + NULL, getpmusergroups, scanpmusergroups) }; static struct features module_features = { diff --git a/Src/zsh.h b/Src/zsh.h index 6d8ac0353..51ec937fe 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1731,6 +1731,23 @@ struct nameddir { #define ND_USERNAME (1<<1) /* nam is actually a username */ #define ND_NOABBREV (1<<2) /* never print as abbrev (PWD or OLDPWD) */ +/* Storage for single group/name mapping */ +typedef struct { + /* Name of group */ + char *name; + /* Group identifier */ + gid_t gid; +} groupmap; +typedef groupmap *Groupmap; + +/* Storage for a set of group/name mappings */ +typedef struct { + /* The set of name to gid mappings */ + Groupmap array; + /* A count of the valid entries in groupmap. */ + int num; +} groupset; +typedef groupset *Groupset; /* flags for controlling printing of hash table nodes */ #define PRINT_NAMEONLY (1<<0) -- cgit 1.4.1