about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2011-01-19 12:42:53 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2011-01-19 12:42:53 +0000
commit94225e07fcc27f01edd4faee2391000f54a9aceb (patch)
treed3d5386215fd2a19fb9ca3a06cf2b7fa52b3b01b
parentaa58d139ff3ffa7258a6273bf279d70f9ee31916 (diff)
downloadzsh-94225e07fcc27f01edd4faee2391000f54a9aceb.tar.gz
zsh-94225e07fcc27f01edd4faee2391000f54a9aceb.tar.xz
zsh-94225e07fcc27f01edd4faee2391000f54a9aceb.zip
28638: add $usergroups parameter
-rw-r--r--ChangeLog8
-rw-r--r--Doc/Zsh/mod_parameter.yo6
-rw-r--r--NEWS8
-rw-r--r--Src/Modules/parameter.c139
-rw-r--r--Src/zsh.h17
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  <pws@csr.com>
+
+	* 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  <pws@csr.com>
 
 	* 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)