groups command
teklabs!tekmdp!azure!rogers
teklabs!tekmdp!azure!rogers
Sat Jun 12 16:24:30 AEST 1982
: run this file as a shell script
mkdir groups.src
cd groups.src
echo "Extracting README..."
cat > README <<'E*O*F'
Information regarding the groups command:
Groups is a C program designed to provide
the user with a list of the valid groups
which he may newgrp to. There are several
options available, and the user may find out
the group names other users are in.
USAGE:
groups [-ncdxl] [user user ...]
Here is a brief summary of the options:
none: Provides list of gid names only.
-n: Gives the addtional group id number
-c: Gives the user's current group.
-d: Gives the user's default group.
-x: Expands the group name (see below)
-l: Provides all the above functions.
Options may be combined, of course, to get desired results.
IF THE FILE /etc/groupnames is not present,
you may want to add this file so that groups
will do the expansion of the groupnames. The
program will run fine without ti though.
HERE IS THE FORMAT OF /etc/groupnames recognized
by groups:
grnam:gid:longname[;more info if desired]\n
where : grnam is the name of the group as in
group(5),
gid is the group id number as in
group(5),
longname is ascii text describing the
group (also can contain other info after
the semicolon if desired.
\n is a newline to terminate the line
between entries.
After the make has completed it's appointed task,
The following should happen:
Test the groups command by running the executable
with each option seperately, and then combine options.
Test the 'user' option by adding the name of several
users to the end of the groups invoking.
Move the file groups to /usr/bin or equivalent.
Move the file groups.1 to /usr/man/man1 or equivalent,
and test out the manual page (man groups).
GOOD LUCK!!!!!!! Roger Southwick.
E*O*F
echo "Extracting Manual Page..."
cat > groups.1 <<'E*O*F'
.TH GROUPS 1 "6/12/82"
.SH NAME
groups \- give valid group names for current user.
.SH SYNOPSIS
.B groups [\-ncdxl] [user user ...]
.SH DESCRIPTION
.I Groups
gives a list of valid group names to which the user may
change to by using a newgrp command. By using the option
flags, the user may get the following additional data:
.IP
\-n : Provides the current group number.
.IP
\-c : Provides the current group name (as in whoami(1)).
.IP
\-d : Provides the user's default group name.
.IP
\-x : Expands the group name for more description.
.IP
\-l : Provides all the above options.
.IP
user : Provides the group names for the user(s) listed. This
has the effect of turning off the -c and -d options.
.LP
The options may be combined as in:
.IP
groups -x -n
.LP
\-or\-
.IP
groups -xn
.SH FILES USED
/etc/group \- to get the user names and group names.
/etc/groupnames \- to get the group name expansions.
.SH NOTES
If /etc/groupnames is not on the system, the -x and
-l option will not provide group name expansion.
.LP
The effective user name is used, so if you are su'd,
you will get the group names for the current user name.
.SH AUTHOR
Roger Southwick
Tektronix, Inc.
P.O. Box 500, D.S. 92-525
Beaverton, Oregon 97077
.SH "SEE ALSO"
newgrp(1), whoami(1)
.SH BUGS
To be discovered.
E*O*F
echo "Extracting code ..."
cat > groups.c <<'E*O*F'
/***************************************************************
groups By: Roger Southwick
Tektronix, Inc.
P.O. Box 500, D.S. 92-525
Beaverton, Oregon 97077
Date : 6/10/82
This program is designed to do the groups command. This command
provides the user with the valid groupnames he may newgrp to.
Using the option flags, the user may get different other info
(described below). The user may also stack arguments together
for even more into.
USAGE: groups [-ncdxl] [user user ...]
The flags allowed are:
none : This provides a list of the gid names only.
-n : This provides the addtional group id number.
-c : This provides the current group name (as in whoami).
-d : This provides the user's default group name.
-x : This provides the expansion of the gid names
into the long name. (This works only if
/etc/groupnames is present).
-l : This provides the user with all of the functions.
(This works only if /etc/groupnames is present).
user : The groups function will also print out the
group names for each user name specified, but this
also has the effect of turning off the -c and -d
options.
---------------------------------------------------------------
Files used:
/etc/group - provides the names of all the groups the
user is valid to newgrp to.
/etc/groupnames - provides the expansion for the names.
(This file is optionally not in unix, so
is not required, but option -l & -x won't
work without it.)
<grp.h> - provides the needed mold for getgrgid & getgid.
<pwd.h> - mold for getpwuid and getuid.
------------------------------------------------------------------
MODIFICATION HISTORY:
6/11/82 - Changed the pnode structure so it has different names
than the tnode structure (left becomes lft, right
becomes rght). Makes program portable.
6/11/82 - Added the define for NCMP. This change allows the
makes the string comparisons only look at this many
characters. This is used in all strncmp's.
6/11/82 - Added the knowuser function. This checks the user
names (entered as parameters especially) to be valid
user names or not. This can be disabled by removing
the #define KNOWENABLE statement (or commenting
it out) in the defines section.
********************************************************************/
#include <stdio.h>
/*-----------------------------------------------------------
Structure pnode holds the name of a user which is allowed
in the group. The group structure, tnode, points to this
structure at the name of the first user in the group.
-----------------------------------------------------------*/
struct pnode {
char *name; /* point to a user's name */
struct pnode *lft; /* left child */
struct pnode *rght; /* right child */
};
/*-----------------------------------------------------------
Structure tnode holds a group name, the gid number,
the group long name (if available), and the pointer
to the first user (pnode) in the group
-----------------------------------------------------------*/
struct tnode {
char *grpnm; /* point to the group name */
int gid; /* hold the gid number */
char *longname; /* hold the expanded group name */
struct pnode *frst; /* point to the first person in the pnode */
struct tnode *left; /* left child */
struct tnode *right; /* right child */
};
/*-----------------------------------------------------------
Structure helpmsg (init'ed into stuf), holds the
help messages.
-----------------------------------------------------------*/
struct helpmsg {
char *msgstr;
}stuf[] = {
"none : Provides a list of the gid names only.",
" -n : Provides group id number.",
" -c : Provides current group name (as in whoami).",
" -d : Provides default group name.",
" -x : Expands of the gid names into long name.",
" -l : Invokes all of the functions.",
"Flags may be combined to give desired results.",
"Other user names may be added, this turns off -d & -c "
};
#define NHLPMSGS (sizeof(stuf) / sizeof(struct helpmsg))
main(argc,argv)
int argc; /* number of arguments */
char *argv[]; /* pointers to the actual arguments */
{
char *s, *username();
struct tnode *stash(), *pntr;
FILE *fp, *fgn, *fopen();
int gnum = 0; /* put out gid num if set to 1 */
int cnam = 0; /* put out current group name if 1 */
int defgp = 0; /* put out default group name if 1 */
int xpnam = 0; /* expand names if set to 1 */
/*-----------------------------------------------------------
Now process the arguments. Set the appropriate flag
to invoke the userpr afterwards
-----------------------------------------------------------*/
while(--argc > 0 && (*++argv)[0] == '-')
for (s = argv[0]+1; *s != '\0'; s++)
switch (*s) {
case 'n' : /* give gid number */
gnum = 1;
break;
case 'c' : /* give current group */
cnam = 1;
break;
case 'd' : /* give default group */
defgp = 1;
break;
case 'x' : /* expand the names */
xpnam = 1;
break;
case 'l' : /* give all the above */
gnum = 1;
cnam = 1;
defgp = 1;
xpnam = 1;
break;
default : /* opps! bad flags */
help();
exit(1);
break;
}
/*--------------------------------------------------------------
Now open up the files: /etc/group & /etc/groupnames. It is
an error if /etc/group can't be opened, but not an error if
/etc/groupnames can't be opened (this file is not std unix,
so we must make allowances).
--------------------------------------------------------------*/
if((fp = fopen("/etc/group","r")) == NULL){
fprintf(stderr,"groups: can not open /etc/group\n");
exit(1);
}
else {
fgn = fopen("/etc/groupnames","r");
/*--------------------------------------------------------------
Now to finally do the print out. This is done by calling
userpr with the top of the tnode tree (supplied by stash),
the name of the user (supplied by username, which also prints
out the header), the flags gnum and xpnam for expanding the
printout. We then call up the functions curname (if cnam is
set) and defgrp (if defgp is set). If there are more
arguments on the line, assume they are user names, which
it is desired to give groups for. In this case, we keep
doing headers for each name (which must be known). When
getting groupnames for users OTHER THAN the logged in user,
we cannot do the current or default group printouts.
--------------------------------------------------------------*/
pntr = stash(fp,fgn); /* init the trees */
if(argc == 0){ /* if no users named... */
header(username()); /* use the current user */
userpr(pntr,username(),gnum,xpnam);
}
else { /* use args as user names */
defgp = cnam = 0; /* turn off options */
while (argc-- > 0)
if(knowuser(pntr,*argv) == 1){ /* see if user is known */
header(*argv);
userpr(pntr,*argv++,gnum,xpnam);
}
else /* we don't know this user */
fprintf(stderr,"\ngroups: Unknown user: %s\n",*argv++);
}
putchar('\n'); /* add a <cr> */
if(cnam == 1)
curname();
if(defgp == 1)
defgrp();
if(cnam == 1 || defgp == 1)
printf("\n\n"); /* add 2 <cr>'s */
exit(0);
}
}
/*--------------------------------------------------------------
Function help: This provides the usage message and a
brief description of each flag.
--------------------------------------------------------------*/
help()
{
int i;
fprintf(stderr,"\nUsage: groups [-ncdxl] [user user ...]\n\n");
for(i = 0; i < NHLPMSGS ; i++)
fprintf(stderr,"%s\n\n",stuf[i].msgstr);
}
/*--------------------------------------------------------------
Format notes:
The format for the file /etc/group is given
in group(5) of the V7 unix manual.
The format assumed for /etc/groupnames is:
grpnm:gid:longname[;other info]
where: grpnm - is the group name as in group(5),
gid - is the group number, as in group(5),
longname - is the long group name (ascii text
describing the group name (grpnm).
--------------------------------------------------------------*/
/*--------------------------------------------------------------
Globally available variables and constants
--------------------------------------------------------------*/
#define MAXLINE 10000 /* Maximum number of chars in a line of group */
#define EOL '\012' /* end of line character in groups and groupnames */
#define NAMESIZE 10 /* the maximum length of a user's name */
#define GNAME 20 /* the maximum length of a group name */
#define LNAME 50 /* the maximum length of a long grp name */
#define GIDLEN 5 /* maximum length of the gid number string */
#define TAB 15 /* the place to tab out to after group name */
#define NCMP 8 /* # of chars compared between groupnames & group */
#define KNOWENABLE /* remove if you do not want to test params */
int cnt; /* the count of letters done in a line */
char line[MAXLINE]; /* the line of text read */
/*--------------------------------------------------------------
Function stash: returns a pointer to the top of the
tnode tree. Reads lines of fp (/etc/group) and places
the group name, gid number, and user names into tnode tree
by hashing these values out, and calling function tree. The
longnames are hashed out of fgn (/etc/groupnames, if available)
when all the group names are done (/etc/group fully read out),
and added to the tnodes with calls to addlong function.
--------------------------------------------------------------*/
struct tnode *stash(fp,fgn)
FILE *fp,*fgn;
{
struct tnode *top,*tree();
char gname[GNAME];
char longnm[LNAME];
char gidstr[GIDLEN];
int gid,n;
top = NULL;
while (fgets(line,MAXLINE,fp)!= NULL){ /* read a line of input */
for(cnt = 0; line[cnt] != ':';cnt++) /* get group name place into gname */
gname[cnt] = line[cnt];
gname[cnt++] = '\0'; /* add a null */
for( ; line[cnt] != ':'; cnt++) /* throw away group passwd */
;
for(++cnt,n = 0; line[cnt] != ':';cnt++,n++) /* get the gid number */
gidstr[n] = line[cnt];
gidstr[++n] = '\0'; /* add a null */
gid = atoi(gidstr); /* convert to a number */
top = tree(top,gname,gid);
}
/*---------------------------------------------------------
Now add the expanded groupnames to the list, if
file fgn (/etc/groupnames) is available.
---------------------------------------------------------*/
if(fgn != NULL){
while (fgets(line,MAXLINE,fgn) != NULL){
for(cnt = 0;line[cnt] != ':';cnt ++) /* grab groupname */
gname[cnt] = line[cnt];
gname[cnt++] = '\0'; /* add a null */
for( ; line[cnt] != ':';cnt++) /* discard gid number */
;
/* now grab the long name */
for(++cnt,n = 0; line[cnt] != EOL && line[cnt] != ';';cnt++,n++)
longnm[n] = line[cnt];
longnm[n] = '\0'; /* add a null */
addlong(top,gname,longnm); /* call addlong to install */
}
}
return(top); /* go back to calling program (main) */
}
/*---------------------------------------------------------
Function tree provides a recursive method of storing the
group name (nm) at node p or below. Also stores the gid
number. Then it gets one user name at a time and calls
ptree to install the user name in the associated pnode
tree.
---------------------------------------------------------*/
struct tnode *tree(p,nm,gid)
struct tnode *p;
char *nm;
int gid;
{
struct tnode *talloc();
char *strsave(),name[NAMESIZE];
struct pnode *ptree();
int n;
if (p == NULL) { /* a new node is desired */
p = talloc(); /* make a new node in main memory */
p->grpnm = strsave(nm); /* save the group name */
p->gid = gid; /* save the gid number */
p->longname = NULL; /* make longname point nowhere */
p->left = p->right = NULL; /* init pointers */
p->frst = NULL;
while(line[cnt] != EOL){ /* get a person's name */
cnt++; /* increment past , */
/* grab the person's name */
for(n = 0;line[cnt]!=',' && line[cnt]!=EOL;n++,cnt++)
name[n] = line[cnt];
name[n] = '\0'; /* add a null */
p->frst = ptree(p->frst,name); /* save the name */
}
}
else if (strncmp(nm,p->grpnm,NCMP) <= 0) /* goes in left tree */
p->left = tree(p->left,nm,gid);
else
p->right = tree(p->right,nm,gid); /* goes right */
return(p); /* return pointer to tnode */
}
/*---------------------------------------------------------
Function ptree installs the user name (name) in the
pnode tree at node p or below, by use of recursion.
---------------------------------------------------------*/
struct pnode *ptree(p,name)
struct pnode *p;
char *name;
{
struct pnode *palloc();
char *strsave();
if(p == NULL) { /* make a new node */
p = palloc(); /* create a new node in memory */
p->name = strsave(name); /* save the name of the user */
p->lft = p->rght = NULL; /* init the pointers */
}
else if(strncmp(name,p->name,NCMP) <= 0) /* goes in left tree */
p->lft = ptree(p->lft,name);
else /* goes in right tree */
p->rght = ptree(p->rght,name);
return(p); /* return pointer to pnode */
}
/*----------------------------------------------------------------
Add the longname lnm to the structure tnode for each groupname
This is done by looking up the gid name nm in the list, and
adding the lnm to p->longname.
----------------------------------------------------------------*/
addlong(p,nm,lnm)
struct tnode *p;
char *nm,*lnm;
{
int cmp;
if(p != NULL){ /* Don't add the long name if no short match */
if((cmp = strncmp(nm,p->grpnm,NCMP)) == 0) /* found a match */
p->longname = strsave(lnm);
else if(cmp < 0) /* go left */
addlong(p->left,nm,lnm);
else /* go right */
addlong(p->right,nm,lnm);
}
}
/*--------------------------------------------------------------
Memory allocation routine: talloc. This provides main
memory for a tnode by doing a cast of the main memory
allocator malloc. It returns a pointer to the new node
out in memory.
--------------------------------------------------------------*/
struct tnode *talloc()
{
return((struct tnode *) malloc(sizeof(struct tnode)));
}
/*--------------------------------------------------------------
Memory allocation routine: palloc. This provides main
memory to a pnode by doing a cast of the main memory
allocator malloc. It returns a pointer to the new node
out in memory.
--------------------------------------------------------------*/
struct pnode *palloc()
{
return((struct pnode *) malloc(sizeof(struct pnode)));
}
/*--------------------------------------------------------------
The strsave routine allocates some main memory for the
string s, copys the string there and returns a pointer
to the place in memory
--------------------------------------------------------------*/
char *strsave(s)
char *s;
{
char *p;
p = (char *)malloc(strlen(s) +1);
strcpy(p,s);
return(p);
}
/*--------------------------------------------------------------
Print out the group names for the user: name. This is
done with recursive calls to userpr, which transverses the
tnode tree, looking for the user name with the function:
namein (below). The info is printed out according to the
parameters gnum (add the group id number) and xpnam (add the
expanded group name)
--------------------------------------------------------------*/
userpr(p,name,gnum,xpnam)
struct tnode *p;
char *name;
int gnum, xpnam;
{
int namein();
int len; /* the length of the group name */
if (p != NULL) { /* only print out if not a NULL node */
userpr(p->left,name,gnum,xpnam); /* go all the way left */
if(namein(p->frst,name)){ /* found a match */
len = strlen(p->grpnm); /* get the string length */
printf("%s",p->grpnm); /* print group name */
for( ; len <= TAB ; len ++) /* add spaces to TAB */
putchar(' ');
if(gnum == 1) /* print out gid number */
printf("%d",p->gid);
if(xpnam == 1) /* add expanded name */
if(p->longname != NULL) /* only if there, tho */
printf("\t%s",p->longname);
putchar('\n'); /* add <cr> */
}
userpr(p->right,name,gnum,xpnam); /* go down the right tree */
}
}
/*--------------------------------------------------------------
Function knowuser returns a 1 if the user name: name is
anywhere in any of the pnode trees. This function could
be done without (since it takes time to check), and can be
quickly disabled by removing the #define KNOWENABLE in the
defines section.
--------------------------------------------------------------*/
int status = 0; /* the status variable */
int knowuser(p,name)
struct tnode *p;
char *name;
{
#ifdef KNOWENABLE
if(p != NULL) { /* don't do anything for a NULL node */
knowuser(p->left,name); /* go all the way left */
if(namein(p->frst,name)) /* test for user in this group */
status = 1;
knowuser(p->right,name); /* go all the way right */
}
#else
status = 1; /* if not enabled, we know invalid users */
#endif
return(status);
}
/*--------------------------------------------------------------
Function namein returns a 1 if user name: name is in
the pnode tree pointed to by p. This is done by recursively
calling namein looking for a match.
--------------------------------------------------------------*/
int namein(p,name)
struct pnode *p;
char *name;
{
int cond;
if(p == NULL) /* End of tree and name not found */
return(0);
else {
if((cond =strncmp(name,p->name,NCMP)) == 0) /* test name for match */
return(1);
else if (cond < 0) /* go left if less than */
return(namein(p->lft,name));
else /* go right */
return(namein(p->rght,name));
}
}
/*-----------------------------------------------------------
This function provides the current group name for the
user.
------------------------------------------------------------*/
#include <grp.h>
struct group *gp;
struct group *getgrgid();
curname()
{
gp = getgrgid(getgid());
printf("Current group is: %s\t",gp->gr_name);
}
/*-----------------------------------------------------------
This function returns a pointer to current user's name.
------------------------------------------------------------*/
#include <pwd.h>
struct passwd *getpwuid();
struct passwd *pp;
char *username()
{
pp = getpwuid(getuid());
return(pp->pw_name);
}
/*-----------------------------------------------------------
This function prints a nice looking header for user
name nm
-----------------------------------------------------------*/
header(nm)
char *nm;
{
printf("\nValid groups for %s:\n",nm);
}
/*-----------------------------------------------------------
This function prints out the user's default groupname
------------------------------------------------------------*/
defgrp()
{
pp = getpwuid(getuid());
gp = getgrgid(pp->pw_gid);
printf("Default group is: %s",gp->gr_name);
}
E*O*F
echo "Extracting makefile..."
cat > makefile <<'E*O*F'
FILES = /usr/include/stdio.h /usr/include/grp.h /usr/include/pwd.h /etc/group
groups : groups.c $(FILES)
cc -O -o groups groups.c
E*O*F
echo "Running Makefile..."
make
More information about the Comp.sources.unix
mailing list