Path: utzoo!censor!geac!torsqnt!news-server.csri.toronto.edu!cs.utexas.edu!usc!wuarchive!psuvax1!rutgers!mcnc!uvaarpa!mmdf From: aks@hub.ucsb.edu, , ks (Alan Stebbens) Newsgroups: comp.lang.perl Subject: Re: implicit limit on number of members in netgroup Message-ID: <1990Dec4.225525.15948@uvaarpa.Virginia.EDU> Date: 4 Dec 90 22:55:25 GMT Sender: mmdf@uvaarpa.Virginia.EDU (Uvaarpa Mail System) Reply-To: aks@hub.ucsb.edu Organization: The Internet Lines: 837 | is there some arbitrary ceiling on the number of machines one can | define for membership in a netgroup id in the /etc/netgroup file ?? I | have evidence that there is some limit. Would like to know if others | have similar suspicions. Yes. If you are using the older YP routines, they use "dbm" maps, which have an internal limit of 1024 characters per record. Even the newer versions, using "ndbm", still have the internal limit, it's just a little bigger, at 4096 bytes per record. To get around this limitation for potentially large netgroups (like "undergrads" in our Computer Science YP -- err, I mean -- NIS domain), we wrote a little Perl script to automatically convert our *real* source, "/etc/netgroup.master", into the file required by "makedbm", "/etc/netgroup", with no record larger than the configured size. As part of the conversion, large netgroups are detected and broken into smaller sub-netgroups which are then chained together as part of the original netgroup. Also, the input syntax for "mknetgrp" is more lenient than "makedbm" allows, offering a convenience to the humans maintaining the netgroup file. Here's a sample output: Script started on Tue Dec 4 14:39:47 1990 # mknetgrp -v Input netgroup file is /etc/netgroup.master Output netgroup file is /etc/netgroup Maximum record length is 512 bytes cs-domain: 4 members, 70 bytes. cs-clients: 9 members, 143 bytes. cs-servers: 9 members, 143 bytes. cs-standalone: 5 members, 80 bytes. ccse-clients: 2 members, 58 bytes. csil-servers: 4 members, 73 bytes. csil-clients: 2 members, 55 bytes. cs-nextusers: 3 members, 60 bytes. ecl-clients: 5 members, 92 bytes. ecl-servers: 2 members, 50 bytes. ecl-users: 6 members, 88 bytes. tcl-clients: 2 members, 43 bytes. tcl-servers: 1 members, 34 bytes. tcl-users: 7 members, 99 bytes. rsl-clients: 7 members, 103 bytes. rsl-servers: 2 members, 50 bytes. rsl-users: 13 members, 164 bytes. gsl-clients: 7 members, 107 bytes. gsl-servers: 1 members, 36 bytes. gsl-users: 0 members, 21 bytes. csgrad-printer: 2 members, 53 bytes. cs-fac-clients: 2 members, 58 bytes. cs-fac-servers: 4 members, 75 bytes. cs-staff: 8 members, 108 bytes. cs-faculty: 28 members, 325 bytes. cs-research: 1 members, 38 bytes. cs-tempfaculty: 21 members, 263 bytes. cs-grad: 2 members, 39 bytes. cs-graduate: 375 members, 8 subgroups, 4471 bytes. cs-undergrad: 652 members, 14 subgroups, 7748 bytes. ccse-staff: 24 members, 293 bytes. ccse-consultant: 1 members, 43 bytes. ccse-help: 16 members, 227 bytes. cs-guest: 7 members, 104 bytes. ece-faculty: 1 members, 36 bytes. 69 groups in; 91 groups out. # ^D script done on Tue Dec 4 14:40:16 1990 To fully automate this, you should modify the /var/yp/Makefile so that the "netgroup.time" target causes an invocation of "mknetgrp" before running "makedbm". We've been using this script for almost two years with no problems. The following Perl scripts and "man" pages are provided for your benefit, gratis, caveat emptor. Alan Stebbens Computer Resource Manager Center for Computational Sciences and Engineering (CCSE) University of California, Santa Barbara 3111 Engineering I Santa Barbara, CA 93106 Internet: aks@hub.ucsb.edu BITNET: aks%hub@ucsbuxa.bitnet UUCP: ...{ucbvax,sdcsvax,cepu}!ucsbcsl!aks Voice: (805) 893-8135 (CCSE Office: 893-3221) ============================= cut here =================================== #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh Makefile <<'END_OF_Makefile' X# $Header: Makefile,v 1.4 89/01/20 13:22:43 aks Locked $ X# XETC_DIR = $(DEST_DIR)/usr/local/etc XPGMS = ${ETC_DIR}/addnetgrp \ X ${ETC_DIR}/mknetgrp XMAN = ${MAN_DIR}/addnetgrp.8 X# Set HOSTS to a list of hosts to which these programs will be "rdist"ed. XHOSTS = cornu raster X Xinstall: ${PGMS} Xrdist: install X rdist -d HOSTS='(${HOSTS})' -d PGMS='(${PGMS})' X XINSTALL_PGM = install -c -m 550 -o root -g wheel $? $@ XINSTALL_MAN = install -c -m 444 -o root -g bin $? $@ XMAKE_DIFF = rcsdiff $? > $@ X X$(ETC_DIR)/addnetgrp: addnetgrp ; $(INSTALL_PGM) X$(ETC_DIR)/mknetgrp: mknetgrp ; $(INSTALL_PGM) X$(MAN_DIR)/addnetgrp.8: addnetgrp.8 ; $(INSTALL_MAN) X Xdiff: addnetgrp.diff mknetgrp.diff Xaddnetgrp.diff: addnetgrp ; $(MAKE_DIFF) Xmknetgrp.diff: mknetgrp ; $(MAKE_DIFF) END_OF_Makefile if test 758 -ne `wc -c addnetgrp <<'END_OF_addnetgrp' X#!/bin/perl X# $Header: addnetgrp,v 1.7 88/10/11 11:03:01 root Exp $ X# This script creates new netgroups, adds netgroups and logins to existing X# netgroups, or removes members from netgroups, or removes entire netgroups. X# X# addnetgrp [-rvfunh] [-F netgroupfile] netgroup [member...] X# rmnetgrp [-vfunh] [-F netgroupfile] netgroup [member...] X# X# where each "member" is either another netgroup name, to be added as a X# member, or a "tuple" of "machine,user,domain" optionally parenthesized. X# Note, though, that as whitespace is used to seperate member tokens, X# no space can occur around the commas, unless the tuple is parenthesized. X# X# If the -u option is given, the members are user logins, unless they are X# parenthetical tuples. If the -h option is given, the member tokens are X# host names, otherwise they are tuples. Without either the -u or -h X# options, the tokens are netgroup names. X# X# If the netgroup is given as "-", then the operation will be applied to X# all netgroups. X# X$me = $0; # my name X$rFlag = ($me =~ /rmnetgrp/); # off for addnetgrp, on for rmgrp X$vFlag = 0; # verbose off by default X$fFlag = 0; # force off by default X$uFlag = 0; # recognize bare names as users X$hFlag = 0; # recognize bare names as hosts X$nFlag = 0; # recognize bare names as netgroups X$netGroupFile = "/etc/netgroup.master"; # by default X# Xwhile ($_ = $ARGV[0], /^-/) { X shift; X goto Usage if /^-/ && /[^-uhrnvfF]/; X /^-.*r/ && $rFlag++; X /^-.*v/ && $vFlag++; X /^-.*f/ && $fFlag++; X /^-.*h/ && $hFlag++; X /^-.*n/ && $nFlag++; X /^-.*u/ && $uFlag++; X if (/^-F/) { X die "Missing filename after '-F' option\n" unless $#ARGV >= $[; X $netGroupFile = $ARGV[0]; X shift; X } X} Xdie "Use only ONE of -h, -n, or -u!\n" if $nflag + $hFlag + $uFlag > 1; Xgoto Usage if $#ARGV < $[; # any more things left? Xdie "'$netGroupFile' does not exist.\n" unless -f $netGroupFile; X X$_ = $ARGV[0]; shift; # get the netgroup Xif (/([^a-zA-Z0-9_-])/) { # any illegal chars? X print "Illegal character '$1' in netgroup name: \"$_\"\n"; X goto Usage; X} X$uFlag++ if !($nFlag || $hFlag || $uFlag); # set default X$netGroup = $_; X@Members = (); # empty the array X$MemberStr = " "; # string to recognize things with Xforeach (@ARGV) { # scan remaining args as members X $mem = ''; X if (/^[A-Za-z0-9_-]+$/) { # simple name? X $mem = "(,$_,)" if $uFlag; # recognize users X $mem = "($_,,)" if $hFlag; # recognize hosts X $mem = "$_" if $nFlag; # recognize netgroups X } X if (/^([a-z0-9_-]*),([a-z0-9-]*),([A-Za-z0-9_-]*)/ || X /^\(?\s*([a-z0-9_-]*)\s*,\s*([a-z0-9-]*)\s*,\s*([A-Za-z0-9_-]*)\s*\)?/) { X next if /^,,?$/; # ignore empty members X $mem = "($1,$2,$3)"; # get the member token X } X die "Illegal or badly formatted member: '$_'\n" unless $mem; X $qmem = $mem; X $qmem =~ s/([()])/\\$1/g; # quote the parens X if ($MemberStr !~ /\s$qmem\s/) { # in the list yet? X $MemberStr .= "$mem "; # no, but it is now X push(@Members,$mem); # add a new member X } X} X# X# Now open the netgroup file, scan to the netgroup in question, and do the requested X# operation. X# X$newNetGroupFile = "$netGroupFile.new"; Xopen(NGFIN,$netGroupFile) X || die "Can't open '$netGroupFile' for input because $!\n"; Xif (-f $newNetGroupFile) { X $wait = 0; X print "(waiting..."; X while (-f $newNetGroupFile && ++$wait < 60) { sleep 15; print ".";} X if (-f $newNetGroupFile) { X print "\nThe wait has been too long for $newNetGroupFile.\n"; X print "Please examine the netgroup files and fix, if possible.\n"; X exit 1; X } X} Xopen(NGFOUT,">$newNetGroupFile") X || die "Can't open '$newNetGroupFile' for output because $!\n"; X X@GroupList = (); X X # copy up the netgroup file up to our group, if it exists X X$ng = $netGroup; X$ng =~ s/^-$/\w+/; # make it a regexp pattern X$found = 0; X Xwhile () { X if (!s/^$ng\b//) { print NGFOUT; next; } X $found++; X $grpName = $&; # get the real name X # yes, scan the remaining member lines, skipping comments, and place X # all the members in the group list X $tell = tell(NGFIN); X while ($_ && /^[\s#]/) { # scan member lines X push(@GroupList,split(' ')) unless /^\s*#/; X $tell = tell(NGFIN); # remember this position in case we backup X $_ = ; X } X # now, if we are removing the entire group, we're done! X if ($rFlag && $#Members < $[) { X print "Removing entire netgroup: $grpName...\n" if $vFlag; X goto Seek; # skip rest of this X } elsif ($rFlag) { # removing... X local(@removed,$groupstr); X $groupstr = ' ' . join(' ',@GroupList) . ' '; # get big string of all members X @removed = (); X foreach $mem (@Members) { # scan the member removal list X local($qmem) = $mem; X $qmem =~ s/([()])/\\$1/g; # quote the parens X if ($groupstr =~ s/\s$qmem\s/ /g) { # removed it? X push(@removed,$mem); # yes, remember it X } else { X print "$mem is not a member.\n" if $vFlag; X } X } X if ($#removed >= $[) { # anything removed? X print "Removed ",join(' ',@removed)," from $grpName.\n" if $vFlag; X @GroupList = split(' ',$groupstr); # restore the group list X } X } else { # adding... X local(@added,$groupstr); X $groupstr = ' ' . join(' ',@GroupList) . ' '; X @added = (); X foreach $mem (@Members) { X local($qmem) = $mem; X $qmem =~ s/([()])/\\$1/g; # quote the parens X if ($groupstr !~ /\s$qmem\s/) { X $groupstr .= " $mem"; # so future compares track new members X push(@added,$mem); # remember new members X } else { X print "$mem is already a member.\n" if $vFlag; X } X } X if ($#added >= $[) { # anything added? X push(@GroupList,@added); # add new groups X print "Added ",join(' ',@added)," to $grpName.\n" if $vFlag; X } X } X # we need to restore what's left of the group (or the new, bigger group) to X # the file X print NGFOUT $grpName,"\n"; X foreach (@GroupList) { print NGFOUT "\t$_\n"; } X Seek: X # prepare to continue the search X seek(NGFIN,$tell,0); X} Xclose NGFIN; Xif (!$found) { # any netgroups found? X if ($rFlag) { # unless this is set X print "$netGroup does not exist.\n" unless $fFlag && !$vFlag; X close NGFOUT; X unlink "$newNetGroupFile"; X exit 1; X } X print NGFOUT "#\n"; X print NGFOUT $netGroup,"\n"; # add new netgroup name X print "$netGroup created.\n" if $vFlag; X foreach (@Members) { # for any members of the new group X print NGFOUT "\t$_\n"; # output the member X } X print "Added ",join(' ',@Members)," to $netGroup\n" X if $vFlag && $#Members >= $[; X} Xclose NGFOUT; X$backup = "$netGroupFile.orig"; Xif (-f $backup) { # orig already exists? X $backup = "$netGroupFile.old"; X unlink $backup if -f $backup; X} Xrename($netGroupFile,$backup); Xrename($newNetGroupFile,$netGroupFile); Xexit 0; X X# X# Tell user how to use the program. X# XUsage: Xprint "Usage:$me [-vrnuhf] [netgroup|-] [names...|tuples...]\n"; Xprint "Options: -v = verbose, -r = remove (add otherwise),\n"; Xprint "-u = treat names as user logins, -h = treat names as hosts\n"; Xprint "-n = treat names as netgroups, -f = force (don't complain).\n"; Xexit 1; END_OF_addnetgrp if test 7037 -ne `wc -c addnetgrp.8 <<'END_OF_addnetgrp.8' X.TH ADDNETGRP 8 "October 10, 1988" X.UC X.SH NAME Xaddnetgrp \- add netgroups and/or members to netgroups in the netgroup file. X.LP Xrmnetgrp \- remove members from existing netgroup, or remove a netgroup Xentirely. X.SH SYNOPSIS X.B addnetgrp X[ X.B \-vrnuhf X] [ X.B \-F Xnetgroupfile ] netgroup [ member ... ] X.br X.B rmnetgrp X[ X.B \-vfuhn X] [ X.B \-F Xnetgroupfile ] netgroup [ member ... ] X.SH DESCRIPTION X.I addnetgrp Xcan be used to create new netgroups, or add new members Xto existing or newly created netgroups, or remove members from an Xexisting netgroups, or remove a netgroup entirely. X.LP X.I rmnetgrp Xremoves members from an existing netgroup, or removes Xa netgroup entirely. X.LP XThe netgroupfile affected is the /etc/netgroup.master by default. XHowever, by using the -F option the netgroupfile affected can be changed. XBoth X.I adddnetgrp Xand X.I rmnetgrp Xcan also work on either a single netgroup or all netgroups. XIf the netgroup is given as "-", all of the netgroups are affected. XThis is helpful when removing a certain member from all netgroups. XHowever, they cannot work on a specific list of netgroups. X.LP XAn important concept to the netgroup file is the "tuple". This basic Xunit helps define the format for members that belong to a particular Xnetgroup. A tuple may also be referred to as a "triple". Members Xof each netgroup can be a hostname, username, or domain-name, and Xsometimes combinations of these are grouped together. XThe members may also be a netgroup name that already has its own members; Xand in this case, no tuple is required. X.LP XThe tuple has the following format: X.B (hostname,username,domainname) X.LP XFor the X.I addnetgrp Xand X.I rmnetgrp Xprograms, Xthe -u and -h flags are important for the type of tuple you wish Xto create. With member(s) given in the command line, the -u option Xis used to form a tuple(s) like (,member1,) (,member2,) ... In Xother words, each member is treated as a username. When Xthe -h option is given, each member is treated as a hostname; and Xthe tuple format looks like (member1,,) (member2,,) ... X.LP XWhen Xthe -n option flag is used, members are treated as netgroups themselves Xand the member is taken literally. So, no tuple is formed. Each Xmember is added to the netgroup specified as shown in ascii Xwith no parentheses and commas. X.LP X.B Note: Xthe programs only work with one of these options (-u, -h, -n) Xat a given time. Also, if none of these options is given, the Xmember is treated as a username by default with tuple form (,member,). XRead the man pages for "netgroup" if you need more information Xabout what tuples look like and how the netgroup file is set-up. X.SH OPTIONS X.TP X.B \-v XInitiate a verbose mode of what X.I addnetgrp Xor X.I rmnetgrp Xis doing. X.TP X.B \-r XIf members are given, remove them from the netgroup given. XIf no members are given, remove the entire netgroup. This Xis only used with X.I addnetgrp. X.TP X.B \-n XTreat members as netgroup names with no tuples formed. X.TP X.B \-f XWhen adding, force addition without complaining about members' Xnames that are already in the netgroup given. When removing, Xremove members without complaining that they are not in the Xnetgroup specified. X.TP X.B \-u XTreat members as user login names when adding or removing, Xby using the tuple format (,member,). X.TP X.B \-h XTreat members as host machine names, by using the tuple Xformat (member,,). X.TP X.B \-F netgroupfile XInstead of using the file /etc/netgroup.master as the default Xnetgroupfile, use the netgroupfile specified in the command line. XThe entire pathname must be given if it is in a different Xdirectory. X.SH EXAMPLES X.br X.IP Xaddnetgrp cs-staff tom dick harry X.LP XThis first example adds the tuples (,tom,) (,dick,) (,harry,) Xto the netgroup "cs-staff" in the default netgroup file X(/etc/netgroup.master). X.br X.IP Xaddnetgrp -rvh -F /etc/netgroup.orig csil-clients goofy mickey X.LP XThis example removes the tuples (goofy,,) (mickey,,) Xfrom the netgroup "csil-clients" in the specified netgroup file X(/etc/netgroup.orig). It also displays messeges about the Xtuples that were added to the netgroup. X.br X.IP Xaddnetgrp -vn cs-clients new-clients old-clients X.LP XThis example does not add tuples, but adds the netgroups Xnew-clients and old-clients themselves to the netgroup called X"cs-clients." X.br X.IP Xrmnetgrp -uf cs-faculty minnie daffy X.LP XThis last example removes the tuples (,minnie,) (,daffy,) Xfrom the netgroup cs-faculty without complaining about Xusernames not in that particular netgroup. X.SH FILES X/etc/netgroup.master as the default netgroupfile. X.SH BUGS XNone reported. END_OF_addnetgrp.8 if test 4571 -ne `wc -c mknetgrp <<'END_OF_mknetgrp' X#!/bin/perl X# $Header: mknetgrp,v 1.6 89/08/04 12:00:49 aks Exp $ X# mknetgrp [-v] [-i input_file] [-o output_file] [-l record-length] X# X# This script will parse the netgroup input file, writing a source X# suitable for parsing by "makedbm" (part of YP). X# X# The whole reason for this script is due to a gross bug in X# dbm(3) (even ndbm(3) has the same limitation), in that no single X# record can be longer than 1024 (or 4096 for ndbm) chars. X# Netgroups of students can get QUITE large, and so must be broken X# up into smaller groups. X# X# To make it easy, the human-source doesn't have to worry about X# these restrictions, but the machine-source cannot have a X# netgroup record exceeding the limitations of dbm. This program X# will parse each netgroup record, and, if it finds a large X# record, breaks into smaller chucks with sequentially-named X# subgroups. X# X# The algorithm makes two passes over the file: the first just X# reads in all existing netgroup names; the second reads each X# record and if it's not too large, writes it out immediately. If X# it is too large, then as much of the group members as will fit X# onto the first record is written, including the new subgroup X# name which is created from the symbolically-incremented parent X# group name (an easy trick courtesy of Perl). This is the reason X# for pass 1: to ensure that any new subgroups names are unique. X# The next subgroup is written, and then the process repeated X# until the record is entirely written. X# X# The input format is more relaxed than the actual "makedbm" input X# format: if the subsequent line begins with a space or tab, it is X# assumed to be a continuation of the previous group, intervening X# comment lines not withstanding (in other words, you can pretty X# much place a comment line anywhere, without worrying about X# interrupting a continuation). X# X# The above "freedom" implies that a netgroup record must begin X# with the netgroup name in column one. The items which follow X# must be the subgroup names or triples. X# X# Some configuration parameters X# X$Debug = 0; X$MaxRecLen = 512; # max "ndbm" record size X$MAXLINELEN = 80; # for pretty output to terminal X X$[ = 0; # origin 0 indexing X@NetGroupNames = (); X$NetGrpIn = "/etc/netgroup.master"; X$NetGrpOut = "/etc/netgroup"; X X# Keep track of # of groups in /out. X X$InCount = 0; X$OutCount = 0; X$Verbose = 0; X$MaxNameLen = 0; X X# Process any arguments X Xwhile ($_ = shift) { X if (!/^-[viodl]$/) { X print "usage: mknetgrp [-v] [-d] [-i in] [-o out] [-l maxrec]\n"; X exit 1; X } X if (/^-i$/) { $NetGrpIn = shift; next; } X if (/^-o$/) { $NetGrpOut = shift; next; } X if (/^-l$/) { $MaxRecLen = int(shift); next; } X if (/^-v$/) { $Verbose++; next; } X if (/^-d$/) { $Debug++; next; } X} X Xif ($Debug) { X $NetGrpIn = "netgroup.master"; X $NetGrpOut = "netgroup"; X} X Xopen(NETGRPIN,$NetGrpIn) || die "Can't open $NetGrpIn\n"; Xif ($Verbose) { X print "Input netgroup file is $NetGrpIn\n"; X print "Output netgroup file is $NetGrpOut\n"; X printf "Maximum record length is %d bytes\n",$MaxRecLen; X} X X# Pass 1: scan the file for just netgroup names X Xwhile () { X chop; s/\\$//; X next if /^\s/ || /^$/; X @line = split(' '); X $NetGroupNames{$line[0]} = 1; X if ($Verbose) { X local($len) = length($line[0]); X $MaxNameLen = $len if $len > $MaxNameLen; X } X} X X# Open the output file X Xseek(NETGRPIN,0,0) || "Could not rewind $NetGrpIn!\n"; X Xopen(NETGRPOUT,">$NetGrpOut.tmp") X || die "Can't open $NetGrpOut for output!\n"; X Xprint NETGRPOUT X "# This netgroup file was produced automatically by \"mknetgrp\"\n"; X@lt = localtime(time); Xprintf NETGRPOUT "# on %02d/%02d/%02d from %s\n",$lt[4],$lt[3],$lt[5],$NetGrpIn; Xprint NETGRPOUT "# DO NOT MODIFY THIS FILE!\n"; X X@Group = (); X Xwhile () { X chop; X next if /^$/ || /^#/ || /^\s*#/; # don't write blanks or comments X $cont = /^[\t ]/; # set flag if continuation X s/\s(#.*|\\)$//; # strip any comments & continuations X s/\s*,\s*/,/g; # remove blanks inside of tuples X s/\(\s+/(/g; X s/\s+\)/)/g; X s/\\$//; X @list = split(' '); X if (!$cont) { # if new list X $OutCount += do PrintGroup() if $#Group >= $[; X $InCount++; X @Group = @list; X if ($Verbose) { X local($name) = $Group[0]; X local($len) = length($name); X printf "%s:%s",$name,(" " x ($MaxNameLen+2-$len)); X } X } else { # a continuation X push(@Group,@list); # add to the group list X } X} X$OutCount += do PrintGroup() if $#Group >= $[; Xclose NETGRPIN; Xclose NETGRPOUT; Xif (!$Debug && $> == 0) { # if root and not debug X unlink "$NetGrpOut.old" if -e "$NetGrpOut.old"; X rename($NetGrpOut,"$NetGrpOut.old") if -e $NetGrpOut; X rename("$NetGrpOut.tmp",$NetGrpOut); X} Xprintf "%d groups in; %d groups out.\n", $InCount, $OutCount if $Verbose; Xexit 0; X X# This subroutine prints the current accumulated group list X# in "grp". X# Return the # of groups printed. X Xsub PrintGroup { X local($grplen); X local($grpname) = shift(@Group); X local($firstgrp) = $grpname; X local($line); X local($member); X local($grpcount) = 1; X local($totalgrplen) = 0; X local($incname) = '01'; X X $line = "$grpname\t"; X $grplen = length($line); X foreach $member (@Group) { X if ((length($line) + length($member) + 1) >= ($MAXLINELEN - 8)) { X print NETGRPOUT $line . "\\\n"; X $grplen += length($line) + 2; X $line = "\t"; X } X if ($grplen >= ($MaxRecLen - (length($grpname) + 4))) { X local($newgrpname) = $grpname; X $newgrpname .= $incname if $grpname !~ /\d$/; X $newgrpname = $firstgrp . ++$incname X while ($NetGroupNames{$newgrpname}); X $grpname = $newgrpname; X $NetGroupNames{$grpname} = 1; X print NETGRPOUT $line . $grpname . "\n"; X $line = "$grpname\t"; X $totalgrplen += $grplen + length($grpname) + 1; X $grplen = length($line); X $grpcount++; X } X $line .= $member . ' '; X } X print NETGRPOUT ($line . "\n"); X if ($Verbose) { X $totalgrplen += $grplen + length($line) + 1; X printf "%3d members", ($#Group + 1 - $[); X printf ", %2d subgroups", ($grpcount-1) if $grpcount > 1; X printf ", %4d bytes.\n", $totalgrplen; X } X return $grpcount; X} END_OF_mknetgrp if test 6201 -ne `wc -c mknetgrp.8 <<'END_OF_mknetgrp.8' X.TH MKNETGRP 8 "October 10, 1988" X.UC X.SH NAME Xmknetgrp \- will parse the netgroup input file and write a source Xwith suitable record sizes for parsing by "makedbm" (part of YP). X.SH SYNOPSIS X.B mknetgrp X[ X.B \-v X] [ X.B \-d X] [ X.B \-i Xin ] [ X.B \-o Xout ] [ X.B \-l Xmaxrec ] X.SH DESCRIPTION X.I mknetgrp Xparses each netgroup record, and if it finds a large record, it will Xbreak it up into smaller pieces with sequentially named subgroups. XThe reason for doing this is because of bugs in the dbm(3) and ndbm(3) Xwhich limit record sizes to 1024 (or 4096 for ndbm) characters. X.LP XBy default, the netgroup input file is /etc/netgroup.master, while Xthe netgroup output file is /etc/netgroup. These can be changed Xwith the -i and -o options. X.LP XWhen editing a netgroup file manually or with addnetgrp(8), the record Xsize may exceed the limitations that makedbm can handle. Running X.I mknetgrp Xafter changing a netgroup file, will correct any problems with record Xsize limitations. See the manual pages for "netgrp" and addnetgrp to Xget an idea of how the netgroup file is set-up. X.SH OPTIONS X.TP X.B \-i in XChange the input file that is being parsed for netgroup Xlengths. Without this option, the default input netgroup file Xis /etc/netgroup.master. X.TP X.B \-v XInitiate a verbose mode of what X.I mknetgrp Xis doing. X.TP X.B \-d XUsed to set the debug flag ?? Seems to me that this is Xmore of a default flag setter. See mknetgrp for what this Xoption does. X.TP X.B \-l maxrec XUsed to set the maximum length of a netgoup's record size. XBy default, the maximum record length has been set for X4095 characters (suitable for ndbm). If you require Xsmaller record sizes for parsing, you must use this option. X.TP X.B \-o out XChange the output netgroup file that has been parsed into Xnetgroups with suitable lengths. Without this option, the Xdefault output file is /etc/netgroup. X.TP X.SH EXAMPLES X.LP XThe first example adds the tuples (,tom,) (,dick,) (,harry,) Xto the netgroup "cs-staff" in the default netgroup file X(/etc/netgroup.master). X.LP XThe second example removes the tuples (goofy,,) (mickey,,) Xfrom the netgroup "csil-clients" in the specified netgroup file X(/etc/netgroup.orig). It also displays messagges about the Xtuples that were added to the netgroup. X.LP XThe third example does not add tuples, but adds the netgroups Xnew-clients and old-clients themselves to the netgroup called Xcs-clients. X.LP XThe fourth example removes the tuples (,minnie,) (,daffy,) Xfrom the netgroup cs-faculty without complaining about Xusuernames not in that particular netgroup. X.IP Xaddnetgrp cs-staff tom dick harry X.br Xaddnetgrp -rvh -F /etc/netgroup.orig csil-clients goofy mickey X.br Xaddnetgrp -vn cs-clients new-clients old-clients X.br Xrmnetgrp -uf cs-faculty minnie daffy X.SH FILES X/etc/netgroup.master default netgroupfile. X/etc/netgroup system netgroupfile. X.SH SEE ALSO Xnetgroup(5), mknetgrp(8) X.SH BUGS XNone reported. END_OF_mknetgrp.8 if test 2915 -ne `wc -c