RPM Community Forums

Mailing List Message of <rpm-cvs>

[CVS] RPM: lua/ Makefile.am lua/chkconfig/ chkconfig.c leveldb.c level...

From: Jeff Johnson <jbj@rpm5.org>
Date: Sun 17 Aug 2008 - 20:31:37 CEST
Message-Id: <20080817183137.87D5C700FE@rpm5.org>
  RPM Package Manager, CVS Repository
  http://rpm5.org/cvs/
  ____________________________________________________________________________

  Server: rpm5.org                         Name:   Jeff Johnson
  Root:   /v/rpm/cvs                       Email:  jbj@rpm5.org
  Module: rpm lua                          Date:   17-Aug-2008 20:31:37
  Branch: HEAD                             Handle: 2008081718313402

  Added files:
    lua/chkconfig           chkconfig.c leveldb.c leveldb.h
    lua/local               lshadow.c lshadow.h lwrs.c lwrs.h
    lua/shadow              chkname.h commonio.c commonio.h config.h copydir.c
                            defines.h faillog.h fputsx.c getdate.c getdate.h
                            getdef.c getdef.h groupadd.c groupio.c groupio.h
                            gshadow.c gshadow_.h list.c nscd.h prototypes.h
                            pwauth.h pwio.c pwio.h sgetgrent.c sgetpwent.c
                            sgroupio.c sgroupio.h shadowio.c shadowio.h
                            strtoday.c useradd.c xmalloc.c
  Modified files:
    lua                     Makefile.am lualib.h
    rpm                     CHANGES
    rpm/rpmio               rpmlua.c

  Log:
    - WR: add shadow/chkconfig internal lua modules.

  Summary:
    Revision    Changes     Path
    1.20        +43 -0      lua/Makefile.am
    1.1         +712 -0     lua/chkconfig/chkconfig.c
    1.1         +740 -0     lua/chkconfig/leveldb.c
    1.1         +55 -0      lua/chkconfig/leveldb.h
    1.1         +142 -0     lua/local/lshadow.c
    1.1         +7  -0      lua/local/lshadow.h
    1.1         +140 -0     lua/local/lwrs.c
    1.1         +7  -0      lua/local/lwrs.h
    1.3         +0  -1      lua/lualib.h
    1.1         +21 -0      lua/shadow/chkname.h
    1.1         +945 -0     lua/shadow/commonio.c
    1.1         +116 -0     lua/shadow/commonio.h
    1.1         +412 -0     lua/shadow/config.h
    1.1         +452 -0     lua/shadow/copydir.c
    1.1         +351 -0     lua/shadow/defines.h
    1.1         +61 -0      lua/shadow/faillog.h
    1.1         +84 -0      lua/shadow/fputsx.c
    1.1         +2575 -0    lua/shadow/getdate.c
    1.1         +14 -0      lua/shadow/getdate.h
    1.1         +419 -0     lua/shadow/getdef.c
    1.1         +21 -0      lua/shadow/getdef.h
    1.1         +647 -0     lua/shadow/groupadd.c
    1.1         +201 -0     lua/shadow/groupio.c
    1.1         +19 -0      lua/shadow/groupio.h
    1.1         +474 -0     lua/shadow/gshadow.c
    1.1         +77 -0      lua/shadow/gshadow_.h
    1.1         +231 -0     lua/shadow/list.c
    1.1         +18 -0      lua/shadow/nscd.h
    1.1         +188 -0     lua/shadow/prototypes.h
    1.1         +64 -0      lua/shadow/pwauth.h
    1.1         +191 -0     lua/shadow/pwio.c
    1.1         +19 -0      lua/shadow/pwio.h
    1.1         +141 -0     lua/shadow/sgetgrent.c
    1.1         +121 -0     lua/shadow/sgetpwent.c
    1.1         +204 -0     lua/shadow/sgroupio.c
    1.1         +20 -0      lua/shadow/sgroupio.h
    1.1         +163 -0     lua/shadow/shadowio.c
    1.1         +20 -0      lua/shadow/shadowio.h
    1.1         +205 -0     lua/shadow/strtoday.c
    1.1         +2008 -0    lua/shadow/useradd.c
    1.1         +37 -0      lua/shadow/xmalloc.c
    1.2519      +1  -0      rpm/CHANGES
    2.57        +2  -0      rpm/rpmio/rpmlua.c
  ____________________________________________________________________________

  patch -p0 <<'@@ .'
  Index: lua/Makefile.am
  ============================================================================
  $ cvs diff -u -r1.19 -r1.20 Makefile.am
  --- lua/Makefile.am	20 May 2008 07:44:59 -0000	1.19
  +++ lua/Makefile.am	17 Aug 2008 18:31:34 -0000	1.20
  @@ -11,6 +11,10 @@
   	-I$(top_srcdir) \
   	-I$(srcdir)/local \
   	-I$(builddir)/local \
  +	-I$(srcdir)/chkconfig \
  +	-I$(builddir)/chkconfig \
  +	-I$(srcdir)/shadow \
  +	-I$(builddir)/shadow \
   	-I$(srcdir)
   
   rpmlua_SOURCES = lua.c
  @@ -37,8 +41,47 @@
   		local/lrexlib_lpcre.c \
   		local/lrexlib_lpcre_f.c \
   		local/lrexlib_lposix.c \
  +		local/lshadow.h \
  +		local/lshadow.c \
   		local/luuid.h \
   		local/luuid.c \
  +		local/lwrs.h \
  +		local/lwrs.c \
  +		shadow/chkname.h \
  +		shadow/commonio.h \
  +		shadow/commonio.c \
  +		shadow/config.h \
  +		shadow/copydir.c \
  +		shadow/defines.h \
  +		shadow/faillog.h \
  +		shadow/fputsx.c \
  +		shadow/getdate.h \
  +		shadow/getdate.c \
  +		shadow/getdef.h \
  +		shadow/getdef.c \
  +		shadow/groupadd.c \
  +		shadow/groupio.h \
  +		shadow/groupio.c \
  +		shadow/gshadow_.h \
  +		shadow/gshadow.c \
  +		shadow/list.c \
  +		shadow/nscd.h \
  +		shadow/prototypes.h \
  +		shadow/pwauth.h \
  +		shadow/pwio.h \
  +		shadow/pwio.c \
  +		shadow/sgroupio.h \
  +		shadow/sgroupio.c \
  +		shadow/sgetgrent.c \
  +		shadow/sgetpwent.c \
  +		shadow/shadowio.h \
  +		shadow/shadowio.c \
  +		shadow/strtoday.c \
  +		shadow/useradd.c \
  +		shadow/xmalloc.c \
  +		chkconfig/chkconfig.c \
  +		chkconfig/leveldb.h \
  +		chkconfig/leveldb.c \
   		linit.c \
   		lauxlib.h \
   		lauxlib.c \
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/chkconfig/chkconfig.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 chkconfig.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ chkconfig.c	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,712 @@
  +/*
  + * This file was originally distributed as part of
  + * chkconfig-1.3.34-1.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* Copyright 1997-2006 Red Hat, Inc.
  + *
  + * This software may be freely redistributed under the terms of the GNU
  + * public license.
  + *
  + * You should have received a copy of the GNU General Public License
  + * along with this program; if not, write to the Free Software
  + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  + *
  + */
  +#include <ctype.h>
  +#include <dirent.h>
  +#include <errno.h>
  +#include <glob.h>
  +#include <libintl.h>
  +#include <locale.h>
  +#include <popt.h>
  +#include <stdio.h>
  +#include <stdlib.h>
  +#include <string.h>
  +#include <sys/stat.h>
  +#include <unistd.h>
  +
  +static char *progname;
  +
  +#define _(String) gettext((String))
  +
  +#include "leveldb.h"
  +
  +static void usage(void) {
  +#if 0
  +    fprintf(stderr, _("%s version %s - Copyright (C) 1997-2000 Red Hat, Inc.\n"), progname, VERSION);
  +#endif
  +    fprintf(stderr, _("This may be freely redistributed under the terms of "
  +			"the GNU Public License.\n"));
  +    fprintf(stderr, "\n");
  +    fprintf(stderr, _("usage:   %s --list [name]\n"), progname);
  +    fprintf(stderr, _("         %s --add <name>\n"), progname);
  +    fprintf(stderr, _("         %s --del <name>\n"), progname);
  +    fprintf(stderr, _("         %s --override <name>\n"), progname);
  +    fprintf(stderr, _("         %s [--level <levels>] <name> %s\n"), progname, "<on|off|reset|resetpriorities>");
  +
  +}
  +
  +static void readServiceError(int rc, char * name) {
  +    if (rc == 2) {
  +	fprintf(stderr, _("service %s supports chkconfig, but is not referenced in any runlevel (run 'chkconfig --add %s')\n"), name, name);
  +    } else if (rc == 1) {
  +	fprintf(stderr, _("service %s does not support chkconfig\n"), name);
  +    } else {
  +	fprintf(stderr, _("error reading information on service %s: %s\n"),
  +		name, strerror(errno));
  +    }
  +
  +    exit(1);
  +}
  +
  +static int delServiceOne(char *name, int level) {
  +    int i, rc;
  +    glob_t globres;
  +    struct service s;
  +
  +    if ((rc = readServiceInfo(name, &s, 0))) {
  +	readServiceError(rc, name);
  +	return 1;
  +    }
  +    if (s.type == TYPE_XINETD) return 0;
  +
  +
  +    if (!findServiceEntries(name, level, &globres)) {
  +	    for (i = 0; i < globres.gl_pathc; i++)
  +		    unlink(globres.gl_pathv[i]);
  +	    if (globres.gl_pathc) globfree(&globres);
  +    }
  +    return 0;
  +}
  +
  +static int delService(char * name) {
  +    int level, i, rc;
  +    glob_t globres;
  +    struct service s;
  +
  +    if ((rc = readServiceInfo(name, &s, 0))) {
  +	readServiceError(rc, name);
  +	return 1;
  +    }
  +    if (s.type == TYPE_XINETD) return 0;
  +
  +    for (level = 0; level < 7; level++) {
  +	    if (!findServiceEntries(name, level, &globres)) {
  +		    for (i = 0; i < globres.gl_pathc; i++)
  +		      unlink(globres.gl_pathv[i]);
  +		    if (globres.gl_pathc) globfree(&globres);
  +	    }
  +    }
  +    return 0;
  +}
  +
  +
  +static inline int laterThan(int i, int j) {
  +	if (i <= j) {
  +		i = j+1;
  +		if (i > 99)
  +			i = 99;
  +	}
  +	return i;
  +}
  +
  +static inline int earlierThan(int i, int j) {
  +	if (i >= j) {
  +		i = j -1;
  +		if (i < 0)
  +			i = 0;
  +	}
  +	return i;
  +}
  +
  +static int frobOneDependencies(struct service *s, struct service *servs, int numservs, int target) {
  +	int i, j, k;
  +	int s0 = s->sPriority;
  +	int k0 = s->kPriority;
  +
  +	if (s->sPriority < 0) s->sPriority = 50;
  +	if (s->kPriority < 0) s->kPriority = 50;
  +	for (i = 0; i < numservs ; i++) {
  +		if (s->startDeps) {
  +			for (j = 0; s->startDeps[j] ; j++) {
  +				if (!strcmp(s->startDeps[j], servs[i].name))
  +					s->sPriority = laterThan(s->sPriority, servs[i].sPriority);
  +				if (servs[i].provides) {
  +					for (k = 0; servs[i].provides[k]; k++) {
  +						if (!strcmp(s->startDeps[j], servs[i].provides[k]))
  +							s->sPriority = laterThan(s->sPriority, servs[i].sPriority);
  +					}
  +				}
  +			}
  +		}
  +		if (s->stopDeps) {
  +			for (j = 0; s->stopDeps[j] ; j++) {
  +				if (!strcmp(s->stopDeps[j], servs[i].name))
  +					s->kPriority = earlierThan(s->kPriority, servs[i].kPriority);
  +				if (servs[i].provides) {
  +					for (k = 0; servs[i].provides[k]; k++) {
  +						if (!strcmp(s->stopDeps[j], servs[i].provides[k]))
  +							s->kPriority = earlierThan(s->kPriority, servs[i].kPriority);
  +					}
  +				}
  +			}
  +		}
  +	}
  +
  +	if (target || ((s0 != s->sPriority) || (k0 != s->kPriority))) {
  +		for (i = 0; i < 7; i++) {
  +			if (isConfigured(s->name, i, NULL, NULL)) {
  +				int on = isOn(s->name, i);
  +				delServiceOne(s->name,i);
  +				doSetService(*s, i, on);
  +			} else if (target) {
  +				delServiceOne(s->name,i);
  +				doSetService(*s, i, ((1<<i) & s->levels));
  +			}
  +		}
  +		return 1; /* Resolved something */
  +	}
  +	return 0; /* Didn't resolve anything */
  +}
  +
  +
  +/* LSB-style dependency frobber. Calculates a usable start priority
  + * and stop priority.
  + * This algorithm will almost certainly break horribly at some point. */
  +static void frobDependencies(struct service *s) {
  +	DIR * dir;
  +	struct dirent * ent;
  +	struct stat sb;
  +	struct service *servs = NULL;
  +	int numservs = 0;
  +	char fn[1024];
  +	int nResolved = 0;
  +
  +	if (!(dir = opendir(RUNLEVELS "/init.d"))) {
  +		fprintf(stderr, _("failed to open %s/init.d: %s\n"), RUNLEVELS,
  +			strerror(errno));
  +		return;
  +	}
  +
  +	while ((ent = readdir(dir))) {
  +		const char *dn;
  +
  +		/* Skip any file starting with a . */
  +		if (ent->d_name[0] == '.')	continue;
  +
  +		/* Skip files with known bad extensions */
  +		if ((dn = strrchr(ent->d_name, '.')) != NULL &&
  +		    (!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp")))
  +			continue;
  +
  +		dn = ent->d_name + strlen(ent->d_name) - 1;
  +		if (*dn == '~' || *dn == ',')
  +			continue;
  +
  +		sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name);
  +		if (stat(fn, &sb)) {
  +			continue;
  +		}
  +		if (!S_ISREG(sb.st_mode)) continue;
  +		if (!strcmp(ent->d_name, s->name)) continue;
  +		servs = realloc(servs, (numservs+1) * sizeof(struct service));
  +		if (!readServiceInfo(ent->d_name, servs + numservs, 0))
  +			numservs++;
  +	}
  +
  +	/* Resolve recursively the other dependancies */
  +	do {
  +	  	nResolved = 0;
  +		int i;
  +
  +		for (i = 0; i < numservs ; i++) {
  +			if ((servs+i)->isLSB)
  +				nResolved += frobOneDependencies(servs+i, servs, numservs, 0);
  +		}
  +	} while (nResolved);
  +
  +	/* Resolve our target */
  +	frobOneDependencies(s, servs, numservs, 1);
  +}
  +
  +static int addService(char * name) {
  +    int i, rc;
  +    struct service s;
  +
  +    if ((rc = readServiceInfo(name, &s, 0))) {
  +	readServiceError(rc, name);
  +	return 1;
  +    }
  +
  +    if (s.type == TYPE_XINETD) return 0;
  +    if (s.isLSB)
  +		frobDependencies(&s);
  +    else
  +    for (i = 0; i < 7; i++) {
  +	if (!isConfigured(name, i, NULL, NULL)) {
  +	    if ((1 << i) & s.levels)
  +		doSetService(s, i, 1);
  +	    else
  +		doSetService(s, i, 0);
  +	}
  +    }
  +
  +    return 0;
  +}
  +
  +static int overrideService(char * name) {
  +    /* Apply overrides if available; no available overrides is no error */
  +    int level, i, rc;
  +    glob_t globres;
  +    struct service s;
  +    struct service o;
  +    int priority;
  +    char type;
  +    int doChange = 1;
  +    int configured = 0;
  +    int thisLevelAdded, thisLevelOn;
  +
  +    if ((rc = readServiceDifferences(name, &s, &o, 0))) {
  +	return 0;
  +    }
  +
  +    if (s.type == TYPE_XINETD) return 0;
  +
  +    if ((s.levels == o.levels) &&
  +        (s.kPriority == o.kPriority) &&
  +        (s.sPriority == o.sPriority)) {
  +        /* no relevant changes in the override file */
  +	return 0;
  +    }
  +
  +    if (s.isLSB && (s.sPriority <= -1) && (s.kPriority <= -1))
  +		frobDependencies(&s);
  +    if ((s.isLSB || o.isLSB) && (o.sPriority <= -1) && (o.kPriority <= -1))
  +		frobDependencies(&o);
  +
  +    /* Apply overrides only if the service has not been changed since
  +     * being added, and not if the service has never been configured
  +     * at all.
  +     */
  +
  +    for (level = 0; level < 7; level++) {
  +	thisLevelAdded = isConfigured(name, level, &priority, &type);
  +        thisLevelOn = s.levels & 1<<level;
  +        if (thisLevelAdded) {
  +            configured = 1;
  +            if (type == 'S') {
  +                if (priority != s.sPriority || !thisLevelOn) {
  +                    doChange = 0;
  +                    break;
  +                }
  +            } else if (type == 'K') {
  +                if (priority != s.kPriority || thisLevelOn) {
  +                    doChange = 0;
  +                    break;
  +                }
  +            }
  +	}
  +    }
  +
  +    if (configured && doChange) {
  +        for (level = 0; level < 7; level++) {
  +            if (!findServiceEntries(name, level, &globres)) {
  +                for (i = 0; i < globres.gl_pathc; i++)
  +                    unlink(globres.gl_pathv[i]);
  +                if (globres.gl_pathc)
  +                    globfree(&globres);
  +                if ((1 << level) & o.levels)
  +                    doSetService(o, level, 1);
  +                else
  +                    doSetService(o, level, 0);
  +            }
  +        }
  +    }
  +
  +    return 0;
  +}
  +
  +
  +static int showServiceInfo(char * name, int forgiving) {
  +    int rc;
  +    int i;
  +    struct service s;
  +
  +    rc = readServiceInfo(name, &s, 0);
  +
  +    if (!rc && s.type == TYPE_INIT_D) {
  +	    rc = 2;
  +	    for (i = 0 ; i < 7 ; i++) {
  +		    if (isConfigured(name, i, NULL, NULL)) {
  +			    rc = 0;
  +			    break;
  +		    }
  +	    }
  +    }
  +
  +    if (rc) {
  +	if (!forgiving)
  +	    readServiceError(rc, name);
  +	return forgiving ? 0 : 1;
  +    }
  +
  +    printf("%-15s", s.name);
  +    if (s.type == TYPE_XINETD) {
  +	    printf("\t%s\n", s.levels ? _("on") : _("off"));
  +	    return 0;
  +    }
  +
  +    for (i = 0; i < 7; i++) {
  +	printf("\t%d:%s", i, isOn(s.name, i) ? _("on") : _("off"));
  +    }
  +    printf("\n");
  +
  +    return 0;
  +}
  +
  +static int isXinetdEnabled() {
  +	int i;
  +	struct service s;
  +
  +	if (readServiceInfo("xinetd", &s, 0)) {
  +		return 0;
  +	}
  +	for (i = 0; i < 7; i++) {
  +		if (isOn("xinetd", i))
  +		  return 1;
  +	}
  +	return 0;
  +}
  +
  +static int serviceNameCmp(const void * a, const void * b) {
  +  return strcmp(* (char **)a, * (char **)b);
  +}
  +
  +static int xinetdNameCmp(const void * a, const void * b) {
  +    const struct service * first = a;
  +    const struct service * second = b;
  +
  +    return strcmp(first->name, second->name);
  +}
  +
  +
  +
  +static int listService(char * item) {
  +    DIR * dir;
  +    struct dirent * ent;
  +    struct stat sb;
  +    char fn[1024];
  +    char **services;
  +    int i;
  +    int numServices = 0;
  +    int numServicesAlloced;
  +    int err = 0;
  +
  +    if (item) return showServiceInfo(item, 0);
  +
  +    numServicesAlloced = 10;
  +    services = malloc(sizeof(*services) * numServicesAlloced);
  +
  +    if (!(dir = opendir(RUNLEVELS "/init.d"))) {
  +	fprintf(stderr, _("failed to open %s/init.d: %s\n"), RUNLEVELS,
  +		strerror(errno));
  +        return 1;
  +    }
  +
  +    while ((ent = readdir(dir))) {
  +	const char *dn;
  +
  +	/* Skip any file starting with a . */
  +	if (ent->d_name[0] == '.')	continue;
  +
  +	/* Skip files with known bad extensions */
  +	if ((dn = strrchr(ent->d_name, '.')) != NULL &&
  +    (!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp")))
  +	    continue;
  +
  +	dn = ent->d_name + strlen(ent->d_name) - 1;
  +	if (*dn == '~' || *dn == ',')
  +	    continue;
  +
  +	sprintf(fn, RUNLEVELS "/init.d/%s", ent->d_name);
  +	if (stat(fn, &sb)) {
  +	    fprintf(stderr, _("error reading info for service %s: %s\n"),
  +		ent->d_name, strerror(errno));
  +	    continue;
  +	}
  +	if (!S_ISREG(sb.st_mode)) continue;
  +
  +	if (numServices == numServicesAlloced) {
  +	    numServicesAlloced += 10;
  +	    services = realloc(services, numServicesAlloced * sizeof(*services));
  +        }
  +
  +	services[numServices] = alloca(strlen(ent->d_name) + 1);
  +	strncpy(services[numServices++], ent->d_name, strlen(ent->d_name) + 1);
  +    }
  +
  +    qsort(services, numServices, sizeof(*services), serviceNameCmp);
  +
  +    for (i = 0; i < numServices ; i++) {
  +	    if (showServiceInfo(services[i], 1)) {
  +		    free(services);
  +		    closedir(dir);
  +		    return 1;
  +	    }
  +    }
  +
  +    free(services);
  +
  +    closedir(dir);
  +
  +    if (isXinetdEnabled()) {
  +	    struct service *s, *t;
  +
  +	    printf("\n");
  +	    printf(_("xinetd based services:\n"));
  +	    if (!(dir = opendir(XINETDDIR))) {
  +		    fprintf(stderr, _("failed to open directory %s: %s\n"),
  +			    XINETDDIR, strerror(err));
  +		    return 1;
  +	    }
  +	    numServices = 0;
  +	    numServicesAlloced = 10;
  +	    s = malloc(sizeof (*s) * numServicesAlloced);
  +
  +	    while ((ent = readdir(dir))) {
  +		    const char *dn;
  +
  +		    /* Skip any file starting with a . */
  +		    if (ent->d_name[0] == '.')	continue;
  +
  +		    /* Skip files with known bad extensions */
  +		    if ((dn = strrchr(ent->d_name, '.')) != NULL &&
  +			(!strcmp(dn, ".rpmsave") || !strcmp(dn, ".rpmnew") || !strcmp(dn, ".rpmorig") || !strcmp(dn, ".swp")))
  +		      continue;
  +
  +		    dn = ent->d_name + strlen(ent->d_name) - 1;
  +		    if (*dn == '~' || *dn == ',')
  +		      continue;
  +
  +		    if (numServices == numServicesAlloced) {
  +			    numServicesAlloced += 10;
  +			    s = realloc(s, numServicesAlloced * sizeof (*s));
  +		    }
  +		    if (readXinetdServiceInfo(ent->d_name, s + numServices, 0) != -1)
  +			    numServices ++;
  +	    }
  +
  +	    qsort(s, numServices, sizeof(*s), xinetdNameCmp);
  +	    t = s;
  +	    for (i = 0; i < numServices; i++, s++) {
  +		    char *tmp = malloc(strlen(s->name) + 5);
  +		    sprintf(tmp,"%s:",s->name);
  +		    printf("\t%-15s\t%s\n", tmp,  s->levels ? _("on") : _("off"));
  +	    }
  +	    closedir(dir);
  +	    free(t);
  +    }
  +    return 0;
  +}
  +
  +int setService(char * name, int where, int state) {
  +    int i, rc;
  +    int what;
  +    struct service s;
  +
  +    if (!where && state != -1) {
  +	/* levels 2, 3, 4, 5 */
  +	where = (1 << 2) | (1 << 3) | (1 << 4) | (1 << 5);
  +    } else if (!where) {
  +	where = (1 << 0) | (1 << 1) | (1 << 2) |
  +	        (1 << 3) | (1 << 4) | (1 << 5) | (1 << 6);
  +    }
  +
  +    if ((rc = readServiceInfo(name, &s, 0))) {
  +	readServiceError(rc, name);
  +	return 1;
  +    }
  +
  +    if (s.type == TYPE_INIT_D) {
  +	    int rc = 0;
  +
  +	    if (s.isLSB)
  +		    frobDependencies(&s);
  +	    for (i = 0; i < 7; i++) {
  +
  +		    if (!((1 << i) & where)) continue;
  +
  +		    if (state == 1 || state == 0)
  +		      what = state;
  +		    else if (state == -2)
  +		      what = isOn(name, i);
  +		    else if (s.levels & (1 << i))
  +		      what = 1;
  +		    else
  +		      what = 0;
  +		    rc |= doSetService(s, i, what);
  +	    }
  +	    return rc;
  +    } else if (s.type == TYPE_XINETD) {
  +	    if (setXinetdService(s, state)) {
  +		    return 1;
  +	    }
  +	    system("/etc/init.d/xinetd reload >/dev/null 2>&1");
  +    }
  +
  +    return 0;
  +}
  +
  +int chkconfig_main(int argc, char ** argv) {
  +    int listItem = 0, addItem = 0, delItem = 0, overrideItem = 0;
  +    int rc, i, x;
  +    int LSB = 0;
  +    char * levels = NULL;
  +    int help=0, version=0;
  +    struct service s;
  +    poptContext optCon;
  +    struct poptOption optionsTable[] = {
  +	    { "add", '\0', 0, &addItem, 0 },
  +	    { "del", '\0', 0, &delItem, 0 },
  +	    { "override", '\0', 0, &overrideItem, 0 },
  +	    { "list", '\0', 0, &listItem, 0 },
  +	    { "level", '\0', POPT_ARG_STRING, &levels, 0 },
  +	    { "levels", '\0', POPT_ARG_STRING, &levels, 0 },
  +	    { "help", 'h', POPT_ARG_NONE, &help, 0 },
  +	    { "version", 'v', POPT_ARG_NONE, &version, 0 },
  +	    { 0, 0, 0, 0, 0 }
  +    };
  +
  +    if ((progname = strrchr(argv[0], '/')) != NULL)
  +	progname++;
  +    else
  +	progname = argv[0];
  +    if (!strcmp(progname,"install_initd")) {
  +	    addItem++;
  +	    LSB++;
  +    }
  +    if (!strcmp(progname,"remove_initd")) {
  +	    delItem++;
  +	    LSB++;
  +    }
  +
  +#if 0
  +    setlocale(LC_ALL, "");
  +    bindtextdomain("chkconfig","/usr/share/locale");
  +    textdomain("chkconfig");
  +#endif
  +
  +    optCon = poptGetContext("chkconfig", argc, argv, optionsTable, 0);
  +    poptReadDefaultConfig(optCon, 1);
  +
  +    if ((rc = poptGetNextOpt(optCon)) < -1) {
  +	fprintf(stderr, "%s: %s\n",
  +		poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
  +		poptStrerror(rc));
  +	return 1;
  +    }
  +
  +    if (version) {
  +	fprintf(stdout, _("%s version %s\n"), progname, "no version!");
  +	return 0;
  +    }
  +
  +    if (help || argc == 1)  { usage(); return 1; }
  +
  +    if ((listItem + addItem + delItem + overrideItem) > 1) {
  +	fprintf(stderr, _("only one of --list, --add, --del, or --override"
  +                " may be specified\n"));
  +	return 1;
  +    }
  +
  +    if (addItem) {
  +	char * name = (char *)poptGetArg(optCon);
  +
  +	if (!name || !*name || poptGetArg(optCon))
  +	    { usage(); return 1; }
  +
  +	if (LSB)
  +		    name = basename(name);
  +	return addService(name);
  +    } else if (delItem) {
  +	char * name = (char *)poptGetArg(optCon);
  +
  +	if (!name || !*name || poptGetArg(optCon))  { usage(); return 1; }
  +
  +	if (LSB)
  +		    name = basename(name);
  +	return delService(name);
  +    } else if (overrideItem) {
  +	char * name = (char *)poptGetArg(optCon);
  +
  +	if (!name || !*name || poptGetArg(optCon))  { usage(); return 1; }
  +
  +        name = basename(name);
  +	return overrideService(name);
  +    } else if (listItem) {
  +	char * item = (char *)poptGetArg(optCon);
  +
  +	if (item && poptGetArg(optCon))  { usage(); return 1; }
  +
  +	return listService(item);
  +    } else {
  +	char * name = (char *)poptGetArg(optCon);
  +	char * state = (char *)poptGetArg(optCon);
  +	int where = 0, level = -1;
  +
  +	if (!name) {
  +		usage();
  +                return 1;
  +	}
  +	if (levels) {
  +	    where = parseLevels(levels, 0);
  +	    if (where == -1)  { usage(); return 1; }
  +	}
  +
  +	if (!state) {
  +	    if (where) {
  +		rc = x = 0;
  +		i = where;
  +		while (i) {
  +		    if (i & 1) {
  +			rc++;
  +			level = x;
  +		    }
  +		    i >>= 1;
  +		    x++;
  +		}
  +
  +		if (rc > 1) {
  +		    fprintf(stderr, _("only one runlevel may be specified for "
  +			    "a chkconfig query\n"));
  +		    return 1;
  +		}
  +	    }
  +	    rc = readServiceInfo(name, &s, 0);
  +	    if (rc)
  +	       return 1;
  +	    if (s.type == TYPE_XINETD) {
  +	       if (isOn("xinetd",level))
  +		       return !s.levels;
  +	       else
  +		       return 1;
  +	    } else
  +	       return isOn(name, level) ? 0 : 1;
  +	} else if (!strcmp(state, "on"))
  +	    return setService(name, where, 1);
  +	else if (!strcmp(state, "off"))
  +	    return setService(name, where, 0);
  +	else if (!strcmp(state, "reset"))
  +	    return setService(name, where, -1);
  +	else if (!strcmp(state, "resetpriorities"))
  +	    return setService(name, where, -2);
  +	else
  +	    { usage(); return 1; }
  +    }
  +
  +    usage();
  +
  +    return 1;
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/chkconfig/leveldb.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 leveldb.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ leveldb.c	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,740 @@
  +/*
  + * This file was originally distributed as part of
  + * chkconfig-1.3.34-1.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* Copyright 1997-2006 Red Hat, Inc.
  + *
  + * This software may be freely redistributed under the terms of the GNU
  + * public license.
  + *
  + * You should have received a copy of the GNU General Public License
  + * along with this program; if not, write to the Free Software
  + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  + *
  + */
  +#include <alloca.h>
  +#include <ctype.h>
  +#include <errno.h>
  +#include <fcntl.h>
  +#include <glob.h>
  +#include <libintl.h>
  +#include <locale.h>
  +#include <sys/mman.h>
  +#include <sys/stat.h>
  +#include <stdlib.h>
  +#include <stdio.h>
  +#include <string.h>
  +#include <unistd.h>
  +
  +/* Changes
  +   1998-09-22 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
  +                i18n for init.d scripts (eg.: description(pt_BR) is a brazilian
  +		portuguese description for the package)
  +*/
  +
  +#define _(String) gettext((String))
  +
  +#include "leveldb.h"
  +
  +int parseLevels(char * str, int emptyOk) {
  +    char * chptr = str;
  +    int rc = 0;
  +
  +    if (!str || !strlen(str))
  +	return emptyOk ? 0 : -1;
  +
  +    while (*chptr) {
  +	if (!isdigit(*chptr) || *chptr > '6') return -1;
  +	rc |= 1 << (*chptr - '0');
  +	chptr++;
  +    }
  +
  +    return rc;
  +}
  +
  +int readDescription(char *start, char *bufstop, char **english_desc, char **serv_desc) {
  +	char english;
  +	char my_lang_loaded = 0;
  +	char is_my_lang = 0;
  +	char * lang = getenv ("LANG");
  +	char * final_parenthesis;
  +	char * end, *next;
  +	int i;
  +
  +	english = *start == ':';
  +	end = strchr(start, '\n');
  +	if (!end)
  +	    next = end = bufstop;
  +	else
  +	    next = end + 1;
  +
  +	if (!english) {
  +		if (*start != '(') {
  +		    return 1;
  +		}
  +
  +                ++start;
  +		final_parenthesis = strchr (start, ')');
  +
  +		if (final_parenthesis == NULL || final_parenthesis - start > 5) {
  +		    return 1;
  +		}
  +
  +		is_my_lang = lang ? strncmp (lang, start, strlen (lang)) == 0 : 0;
  +		start = final_parenthesis + 2;
  +	    } else ++start;
  +
  +	    while (isspace(*start) && start < end) start++;
  +	    if (start == end) {
  +		return 1;
  +	    }
  +          {
  +	    char* desc = malloc(end - start + 1);
  +	    strncpy(desc, start, end - start);
  +	    desc[end - start] = '\0';
  +
  +	    start = next;
  +
  +	    while (desc[strlen(desc) - 1] == '\\') {
  +		desc[strlen(desc) - 1] = '\0';
  +		start = next;
  +
  +		while (isspace(*start) && start < bufstop) start++;
  +		if (start == bufstop || *start != '#') {
  +		    return 1;
  +		}
  +
  +		start++;
  +
  +		while (isspace(*start) && start < bufstop) start++;
  +		if (start == bufstop) {
  +		    return 1;
  +		}
  +
  +		end = strchr(start, '\n');
  +		if (!end)
  +		    next = end = bufstop;
  +		else
  +		    next = end + 1;
  +
  +		i = strlen(desc);
  +		desc = realloc(desc, i + end - start + 1);
  +		strncat(desc, start, end - start);
  +		desc[i + end - start] = '\0';
  +
  +		start = next;
  +	    }
  +
  +	    if (desc) {
  +		    if (my_lang_loaded) {
  +			    free(desc);
  +		    } else if (is_my_lang) {
  +			    if (*serv_desc)
  +			      free(*serv_desc);
  +
  +			    *serv_desc = desc;
  +			    return 0;
  +		    } else if (english) {
  +			    if (*serv_desc)
  +			      free(*serv_desc);
  +
  +			    if (*english_desc)
  +			      free (*english_desc);
  +
  +			    *english_desc = desc;
  +		    } else free (desc);
  +	    }
  +	  }
  +	return 0;
  +}
  +
  +int readXinetdServiceInfo(char *name, struct service * service, int honorHide) {
  +	char * filename = alloca(strlen(name) + strlen(XINETDDIR) + 50);
  +	int fd;
  +	struct service serv = {
  +			name: NULL,
  +			levels: -1,
  +			kPriority: -1,
  +			sPriority: -1,
  +			desc: NULL,
  +			startDeps: NULL,
  +			stopDeps: NULL,
  +		        provides: NULL,
  +			type: TYPE_XINETD,
  +			isLSB: 0,
  +			enabled: -1
  +	};
  +	struct stat sb;
  +	char * buf, *ptr;
  +	char * eng_desc = NULL, *start;
  +
  +	snprintf(filename, strlen(name)+strlen(XINETDDIR)+50, XINETDDIR "/%s", name);
  +
  +	if ((fd = open(filename, O_RDONLY)) < 0) return -1;
  +	fstat(fd,&sb);
  +	if (! S_ISREG(sb.st_mode)) return -1;
  +	buf = malloc(sb.st_size+1);
  +	if (read(fd,buf,sb.st_size)!=sb.st_size) {
  +		close(fd);
  +		free(buf);
  +		return -1;
  +	}
  +	close(fd);
  +        serv.name = strdup(name);
  +	buf[sb.st_size] = '\0';
  +	start = buf;
  +	while (buf) {
  +		ptr = strchr(buf,'\n');
  +		if (*buf == '#') {
  +			buf++;
  +			while (isspace(*buf) && buf < ptr) buf++;
  +			if (!strncmp(buf,"default:", 9)) {
  +				buf+=8;
  +				while(isspace(*buf)) buf++;
  +				if (!strncmp(buf+9,"on",2)) {
  +					serv.enabled = 1;
  +				} else {
  +					serv.enabled = 0;
  +				}
  +			} else if (!strncmp(buf,"description:",12)) {
  +				buf+=11;
  +				if (readDescription(buf,start+sb.st_size,
  +						    &serv.desc,&eng_desc)) {
  +					if (serv.desc) free(serv.desc);
  +				}
  +				if (!serv.desc) {
  +					if (eng_desc)
  +					  serv.desc = eng_desc;
  +				} else if (eng_desc)
  +					  free (eng_desc);
  +			}
  +			if (ptr) {
  +				*ptr = '\0';
  +				ptr++;
  +			}
  +			buf = ptr;
  +			continue;
  +		}
  +		while (isspace(*buf) && buf < ptr) buf++;
  +		if (!strncmp(buf,"disable", 7)) {
  +			buf = strstr(buf,"=");
  +			if (buf)
  +			  do {
  +				  buf++;
  +			  } while(isspace(*buf));
  +
  +			if (buf && strncmp(buf,"yes",3)) {
  +				serv.levels = parseLevels("0123456",0);
  +				if (serv.enabled == -1)
  +				  serv.enabled = 1;
  +			} else {
  +				serv.levels = 0;
  +				if (serv.enabled == -1)
  +				  serv.enabled = 0;
  +			}
  +		}
  +		if (ptr) {
  +			*ptr = '\0';
  +			ptr++;
  +		}
  +		buf = ptr;
  +	}
  +	*service = serv;
  +	return 0;
  +}
  +
  +int readServiceInfo(char * name, struct service * service, int honorHide) {
  +    char * filename = alloca(strlen(name) + strlen(RUNLEVELS) + 50);
  +    int fd;
  +    struct service serv, serv_overrides;
  +    int parseret;
  +
  +    sprintf(filename, RUNLEVELS "/init.d/%s", name);
  +
  +    if ((fd = open(filename, O_RDONLY)) < 0) {
  +	    return readXinetdServiceInfo(name,service,honorHide);
  +    }
  +
  +    parseret = parseServiceInfo(fd, name, &serv, honorHide, 0);
  +    if (parseret) {
  +        return parseret;
  +    }
  +
  +    sprintf(filename, RUNLEVELS "/chkconfig.d/%s", name);
  +    if ((fd = open(filename, O_RDONLY)) >= 0) {
  +        parseret = parseServiceInfo(fd, name, &serv_overrides, honorHide, 1);
  +        if (parseret >= 0) {
  +            if (serv_overrides.name) serv.name = serv_overrides.name;
  +            if (serv_overrides.levels != -1) serv.levels = serv_overrides.levels;
  +            if (serv_overrides.kPriority != -2) serv.kPriority = serv_overrides.kPriority;
  +            if (serv_overrides.sPriority != -2) serv.sPriority = serv_overrides.sPriority;
  +            if (serv_overrides.desc) serv.desc = serv_overrides.desc;
  +            if (serv_overrides.startDeps) serv.startDeps = serv_overrides.startDeps;
  +            if (serv_overrides.stopDeps) serv.stopDeps = serv_overrides.stopDeps;
  +            if (serv_overrides.provides) serv.provides = serv_overrides.provides;
  +            if (serv_overrides.isLSB || serv.isLSB) serv.isLSB = 1;
  +        }
  +    }
  +
  +    *service = serv;
  +    return 0;
  +}
  +
  +int readServiceDifferences(char * name, struct service * service, struct service * service_overrides, int honorHide) {
  +    char * filename = alloca(strlen(name) + strlen(RUNLEVELS) + 50);
  +    int fd;
  +    struct service serv, serv_overrides;
  +    int parseret;
  +
  +    sprintf(filename, RUNLEVELS "/init.d/%s", name);
  +
  +    if ((fd = open(filename, O_RDONLY)) < 0) {
  +	    return readXinetdServiceInfo(name,service,honorHide);
  +    }
  +
  +    parseret = parseServiceInfo(fd, name, &serv, honorHide, 0);
  +    if (parseret) {
  +        return parseret;
  +    }
  +
  +    sprintf(filename, RUNLEVELS "/chkconfig.d/%s", name);
  +    if ((fd = open(filename, O_RDONLY)) >= 0) {
  +        parseret = parseServiceInfo(fd, name, &serv_overrides, honorHide, 1);
  +    } else {
  +        return 1;
  +    }
  +    if (parseret) {
  +        return 1;
  +    }
  +
  +    *service = serv;
  +    *service_overrides = serv_overrides;
  +    return 0;
  +}
  +
  +
  +int parseServiceInfo(int fd, char * name, struct service * service, int honorHide, int partialOk) {
  +    struct stat sb;
  +    char * bufstart, * bufstop, * start, * end, * next, *tmpbufstart;
  +    struct service serv = {
  +	    	    name: NULL,
  +		    levels: -1,
  +		    kPriority: -1,
  +		    sPriority: -1,
  +		    desc: NULL,
  +		    startDeps: NULL,
  +		    stopDeps: NULL,
  +		    provides: NULL,
  +		    type: TYPE_INIT_D,
  +		    isLSB: 0,
  +		    enabled: 0
  +    };
  +    char overflow;
  +    char levelbuf[20];
  +    char * english_desc = NULL;
  +
  +    fstat(fd, &sb);
  +
  +    bufstart = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
  +    if (bufstart == ((caddr_t) -1)) {
  +	close(fd);
  +	return -1;
  +    }
  +
  +    tmpbufstart = (char*)malloc(sb.st_size+1);
  +    if (tmpbufstart == NULL) {
  +	close(fd);
  +	return -1;
  +    }
  +
  +    memcpy(tmpbufstart, bufstart, sb.st_size);
  +    munmap(bufstart, sb.st_size);
  +
  +    bufstart = tmpbufstart;
  +    bufstop = bufstart + sb.st_size;
  +    *bufstop = 0;
  +
  +    close(fd);
  +
  +    next = bufstart;
  +    while (next < bufstop && (serv.levels == -1 || !serv.desc)) {
  +	start = next;
  +
  +	while (isspace(*start) && start < bufstop) start++;
  +	if (start == bufstop) break;
  +
  +	end = strchr(start, '\n');
  +	if (!end)
  +	    next = end = bufstop;
  +	else
  +	    next = end + 1;
  +
  +	if (*start != '#') continue;
  +
  +	start++;
  +	if (!strncmp(start, "## BEGIN INIT INFO", 18))
  +		    serv.isLSB = 1;
  +
  +	while (isspace(*start) && start < end) start++;
  +	if (start == end) continue;
  +	if (honorHide && !strncmp(start, "hide:", 5)) {
  +	    start += 5;
  +	    while (isspace(*start) && start < end) start++;
  +	    if (start == end || !strncmp(start, "true", 4)) {
  +		if (serv.desc) free(serv.desc);
  +		free(bufstart);
  +		return 1;
  +	    }
  +	}
  +
  +	if (!strncmp(start, "chkconfig:", 10)) {
  +	    int spri, kpri;
  +
  +	    start += 10;
  +	    while (isspace(*start) && start < end) start++;
  +	    if (start == end) {
  +		if (serv.desc) free(serv.desc);
  +		free(bufstart);
  +		return 1;
  +	    }
  +
  +	    if ((sscanf(start, "%s %d %d%c", levelbuf,
  +			&spri, &kpri, &overflow) != 4) ||
  +		 !isspace(overflow)) {
  +		if (serv.desc) free(serv.desc);
  +		free(bufstart);
  +		return 1;
  +	    }
  +	    if (spri > 99 || kpri > 99 || kpri < 0 || spri < 0) {
  +		    if (serv.desc) free(serv.desc);
  +		    free(bufstart);
  +		    return 1;
  +	    }
  +	    if (serv.sPriority == -1)
  +			serv.sPriority = spri;
  +	    if (serv.kPriority == -1)
  +			serv.kPriority = kpri;
  +
  +	    if (serv.levels == -1) {
  +		    if (!strcmp(levelbuf, "-"))
  +			    serv.levels = 0;
  +		    else
  +			    serv.levels = parseLevels(levelbuf, 0);
  +	    }
  +	    if (serv.levels == -1) {
  +		if (serv.desc) free(serv.desc);
  +		free(bufstart);
  +		return 1;
  +	    }
  +	} else if (!strncmp(start, "description", 11) ||
  +		   !strncmp(start, "Description:", 12) ||
  +		   !strncmp(start, "Short-Description:", 18)) {
  +		if (readDescription(start+11, bufstop, &english_desc, &serv.desc)) {
  +			if (serv.desc) free(serv.desc);
  +		}
  +	} else if (!strncmp(start, "Default-Start:", 14)) {
  +		char *t;
  +
  +		start+=14;
  +		while (1) {
  +			int lev;
  +
  +			lev = strtol(start, &t, 10);
  +			if (t && t != start)
  +				start = t;
  +			else
  +				break;
  +			if (serv.levels == -1)
  +				serv.levels = 0;
  +			serv.levels |= 1 << lev;
  +		}
  +	} else if (!strncmp(start, "Default-Stop:", 13)) {
  +		char *t;
  +
  +		start+=13;
  +		while (1) {
  +			int lev;
  +
  +			lev = strtol(start, &t, 10);
  +			if (t && t != start)
  +				start = t;
  +			else
  +				break;
  +			if (serv.levels == -1)
  +				serv.levels = 0;
  +			serv.levels &= ~(1 << lev);
  +		}
  +	} else if (!strncmp(start, "Required-Start:", 15)) {
  +		char *t;
  +		int numdeps = 0;
  +
  +		start+=15;
  +		while (1) {
  +			while (*start && isspace(*start) && start < end) start++;
  +			if (start == end)
  +				break;
  +			t = start;
  +			while (*t && !isspace(*t) && t < end) t++;
  +			if (isspace(*t)) {
  +				*t = '\0';
  +				t++;
  +			}
  +			numdeps++;
  +			serv.startDeps = realloc(serv.startDeps,
  +						 (numdeps + 1) * sizeof(char *));
  +			serv.startDeps[numdeps-1] = strdup(start);
  +			serv.startDeps[numdeps] = NULL;
  +			if (!t || t >= end)
  +				break;
  +			else
  +				start = t;
  +		}
  +	} else if (!strncmp(start, "Required-Stop:", 14)) {
  +		char *t;
  +		int numdeps = 0;
  +
  +		start+=14;
  +		while (1) {
  +			while (*start && isspace(*start) && start < end) start++;
  +			if (start == end)
  +				break;
  +			t = start;
  +			while (*t && !isspace(*t) && t < end) t++;
  +			if (isspace(*t)) {
  +				*t = '\0';
  +				t++;
  +			}
  +			numdeps++;
  +			serv.stopDeps = realloc(serv.stopDeps,
  +						 (numdeps + 1) * sizeof(char *));
  +			serv.stopDeps[numdeps-1] = strdup(start);
  +			serv.stopDeps[numdeps] = NULL;
  +			if (!t || t >= end)
  +				break;
  +			else
  +				start = t;
  +		}
  +	} else if (!strncmp(start, "Provides:", 9)) {
  +		char *t;
  +		int numdeps = 0;
  +
  +		start+=9;
  +		while (1) {
  +			while (*start && isspace(*start) && start < end) start++;
  +			if (start == end)
  +				break;
  +			t = start;
  +			while (*t && !isspace(*t) && t < end) t++;
  +			if (isspace(*t)) {
  +				*t = '\0';
  +				t++;
  +			}
  +			numdeps++;
  +			serv.provides = realloc(serv.provides,
  +						 (numdeps + 1) * sizeof(char *));
  +			serv.provides[numdeps-1] = strdup(start);
  +			serv.provides[numdeps] = NULL;
  +			if (!t || t >= end)
  +				break;
  +			else
  +				start = t;
  +		}
  +
  +	}
  +    }
  +
  +    free(bufstart);
  +
  +    if (!serv.desc) {
  +      if (english_desc)
  +	serv.desc = english_desc;
  +    } else if (english_desc)
  +	free (english_desc);
  +
  +    if (!partialOk && ((serv.levels == -1) || !serv.desc)) {
  +	return 1;
  +    }
  +
  +    serv.name = strdup(name);
  +    if (!serv.provides) {
  +	    serv.provides = malloc(2 * sizeof(char *));
  +	    serv.provides[0] = strdup(name);
  +	    serv.provides[1] = NULL;
  +    }
  +
  +    *service = serv;
  +    return 0;
  +}
  +
  +/* returns -1 on error */
  +int currentRunlevel(void) {
  +    FILE * p;
  +    char response[50];
  +
  +    p = popen("/sbin/runlevel", "r");
  +    if (!p) return -1;
  +
  +    if (!fgets(response, sizeof(response), p)) {
  +	pclose(p);
  +	return -1;
  +    }
  +
  +    pclose(p);
  +
  +    if (response[1] != ' ' || !isdigit(response[2]) || response[3] != '\n')
  +	return -1;
  +
  +    return response[2] - '0';
  +}
  +
  +int findServiceEntries(char * name, int level, glob_t * globresptr) {
  +    char match[200];
  +    glob_t globres;
  +    int rc;
  +
  +    sprintf(match, "%s/rc%d.d/[SK][0-9][0-9]%s", RUNLEVELS, level, name);
  +
  +    rc = glob(match, GLOB_ERR | GLOB_NOSORT, NULL, &globres);
  +
  +    if (rc && rc != GLOB_NOMATCH) {
  +	fprintf(stderr, _("failed to glob pattern %s: %s\n"), match,
  +		strerror(errno));
  +	return 1;
  +    } else if (rc == GLOB_NOMATCH) {
  +	globresptr->gl_pathc = 0;
  +	return 0;
  +    }
  +
  +    *globresptr = globres;
  +    return 0;
  +}
  +
  +int isConfigured(char * name, int level, int *priority, char *type) {
  +    glob_t globres;
  +    char *pri_string;
  +
  +    if (findServiceEntries(name, level, &globres))
  +	exit(1);
  +
  +    if (!globres.gl_pathc)
  +	return 0;
  +
  +    if (type) {
  +        *type = globres.gl_pathv[0][11];
  +    }
  +
  +    if (priority) {
  +        pri_string = strndup(globres.gl_pathv[0]+12, 2);
  +        if (!pri_string) return 0;
  +        sscanf(pri_string, "%d", priority);
  +        free(pri_string);
  +    }
  +
  +    globfree(&globres);
  +    return 1;
  +}
  +
  +int isOn(char * name, int level) {
  +    glob_t globres;
  +
  +    if (level == -1) {
  +	level = currentRunlevel();
  +	if (level == -1) {
  +	    fprintf(stderr, _("cannot determine current run level\n"));
  +	    return 0;
  +	}
  +    }
  +
  +    if (findServiceEntries(name, level, &globres))
  +	exit(1);
  +
  +    if (!globres.gl_pathc || !strstr(globres.gl_pathv[0], "/S"))
  +	return 0;
  +
  +    globfree(&globres);
  +    return 1;
  +}
  +
  +int setXinetdService(struct service s, int on) {
  +	int oldfd, newfd;
  +	char oldfname[100], newfname[100];
  +	char tmpstr[50];
  +	char *buf, *ptr, *tmp;
  +	struct stat sb;
  +
  +	if (on == -1) {
  +		on = s.enabled ? 1 : 0;
  +	}
  +	snprintf(oldfname,100,"%s/%s",XINETDDIR,s.name);
  +	if ( (oldfd = open(oldfname,O_RDONLY)) == -1 ) {
  +		return -1;
  +	}
  +	fstat(oldfd,&sb);
  +	buf = malloc(sb.st_size+1);
  +	if (read(oldfd,buf,sb.st_size)!=sb.st_size) {
  +		close(oldfd);
  +		free(buf);
  +		return -1;
  +	}
  +	close(oldfd);
  +	buf[sb.st_size] = '\0';
  +	snprintf(newfname,100,"%s/%s.XXXXXX",XINETDDIR,s.name);
  +	newfd = mkstemp(newfname);
  +	if (newfd == -1) {
  +		free(buf);
  +		return -1;
  +	}
  +	while (buf) {
  +		tmp = buf;
  +		ptr = strchr(buf,'\n');
  +		if (ptr) {
  +			*ptr = '\0';
  +			ptr++;
  +		}
  +		while (isspace(*buf)) buf++;
  +		if (strncmp(buf,"disable", 7) && strlen(buf)) {
  +			write(newfd,tmp,strlen(tmp));
  +			write(newfd,"\n",1);
  +			if (buf[0] == '{') {
  +				snprintf(tmpstr,50,"\tdisable\t= %s", on ? "no" : "yes");
  +				write(newfd,tmpstr,strlen(tmpstr));
  +				write(newfd,"\n",1);
  +			}
  +		}
  +		buf = ptr;
  +	}
  +	close(newfd);
  +	chmod(newfname,0644);
  +	unlink(oldfname);
  +	return(rename(newfname,oldfname));
  +}
  +
  +int doSetService(struct service s, int level, int on) {
  +    int priority = on ? s.sPriority : s.kPriority;
  +    char linkname[200];
  +    char linkto[200];
  +    glob_t globres;
  +    int i;
  +
  +    if (!findServiceEntries(s.name, level, &globres)) {
  +	for (i = 0; i < globres.gl_pathc; i++)
  +	    unlink(globres.gl_pathv[i]);
  +	if (globres.gl_pathc) globfree(&globres);
  +    }
  +
  +    sprintf(linkname, "%s/rc%d.d/%c%02d%s", RUNLEVELS, level,
  +			on ? 'S' : 'K', priority, s.name);
  +    sprintf(linkto, "../init.d/%s", s.name);
  +
  +    unlink(linkname);	/* just in case */
  +    if (symlink(linkto, linkname)) {
  +	fprintf(stderr, _("failed to make symlink %s: %s\n"), linkname,
  +		strerror(errno));
  +	return 1;
  +    }
  +
  +    return 0;
  +}
  +
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/chkconfig/leveldb.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 leveldb.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ leveldb.h	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,55 @@
  +/*
  + * This file was originally distributed as part of
  + * chkconfig-1.3.34-1.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* Copyright 1997-2006 Red Hat, Inc.
  + *
  + * This software may be freely redistributed under the terms of the GNU
  + * public license.
  + *
  + * You should have received a copy of the GNU General Public License
  + * along with this program; if not, write to the Free Software
  + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  + *
  + */
  +#ifndef H_LEVELDB
  +#define H_LEVELDB
  +
  +#define RUNLEVELS "/etc/rc.d"
  +#define XINETDDIR "/etc/xinetd.d"
  +
  +#include <glob.h>
  +
  +#define TYPE_INIT_D	0
  +#define TYPE_XINETD	1
  +
  +struct service {
  +    char * name;
  +    int levels, kPriority, sPriority;
  +    char * desc;
  +    char **startDeps;
  +    char **stopDeps;
  +    char **provides;
  +    int type;
  +    int isLSB;
  +    int enabled;
  +};
  +
  +int parseLevels(char * str, int emptyOk);
  +
  +/* returns 0 on success, 1 if the service is not chkconfig-able, -1 if an
  +   I/O error occurs (in which case errno can be checked) */
  +int readServiceInfo(char * name, struct service * service, int honorHide);
  +int readServiceDifferences(char * name, struct service * service, struct service * service_overrides, int honorHide);
  +int parseServiceInfo(int fd, char * name, struct service * service, int honorHide, int partialOk);
  +int currentRunlevel(void);
  +int isOn(char * name, int where);
  +int isConfigured(char * name, int level, int *priority, char *type);
  +int doSetService(struct service s, int level, int on);
  +int findServiceEntries(char * name, int level, glob_t * globresptr);
  +int readXinetdServiceInfo(char *name, struct service *service, int honorHide);
  +int setXinetdService(struct service s, int on);
  +
  +#endif
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/local/lshadow.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 lshadow.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ lshadow.c	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,142 @@
  +/*
  +** $Id: lshadow.c,v 1.1 2008/08/17 18:31:35 jbj Exp $
  +** Standard mathematical library
  +** See Copyright Notice in lua.h
  +*/
  +
  +
  +#include <stdlib.h>
  +#include <math.h>
  +#include <string.h>
  +
  +#define lshadow_c
  +
  +#include "lua.h"
  +
  +#include "lauxlib.h"
  +#include "lshadow.h"
  +
  +extern int useradd_main (int argc, char **argv);
  +extern int chkconfig_main (int argc, char **argv);
  +
  +static int lcl_makeArgv(char *in, char **argv, int max)
  + {
  + int i;
  + char delim = ' ';
  + char *start = NULL;
  + char c;
  +
  + printf("Parsing [%s]\n", in);
  +
  + for ( i=0; i < max; ++i)
  +  {
  +   while (*in == ' ')  ++in;        /* skip spaces */
  +   if (!*in)  return i;             /* ignore traing spaces */
  +   if (*in == '"')  delim = *in++;  /* begin a quoted string */
  +   start = in;                      /* beginning of token */
  +   for ( c = *in; c != delim && c; c = *in)  ++in;  /* find end of token */
  +   *in++ = '\0';         /* mark end */
  +   *(argv+i) = start;    /* might be 0 length! */
  +   if (!c)  return i+1;  /* end of input string */
  +   delim = ' ';
  +  }
  + return -1;
  + }
  +
  +static int shadow_version (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  printf("version 6\n");
  +  return 0;
  +}
  +
  +static int shadow_groupadd (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  useradd_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +static int shadow_useradd (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  useradd_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +static int shadow_chkconfig (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  chkconfig_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +/*@-readonlytrans@*/
  +/*@unchecked@*/
  +static const luaL_reg shadow[] = {
  +  {"version",   shadow_version},
  +  {"groupadd",  shadow_groupadd},
  +  {"useradd",  shadow_useradd},
  +  {"chkconfig",  shadow_chkconfig},
  +  {NULL, NULL}
  +};
  +/*@=readonlytrans@*/
  +
  +
  +/*
  +** Open shadow library
  +*/
  +LUALIB_API int luaopen_shadow (lua_State *L) {
  +  luaL_openlib(L, "shadow", shadow, 0);
  +  return 1;
  +}
  +
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/local/lshadow.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 lshadow.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ lshadow.h	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,7 @@
  +#ifndef LSHADOW_H
  +#define LSHADOW_H
  +
  +int luaopen_shadow(lua_State *L)
  +	/*@modifies L @*/;
  +
  +#endif
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/local/lwrs.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 lwrs.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ lwrs.c	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,140 @@
  +/*
  +** $Id: lwrs.c,v 1.1 2008/08/17 18:31:35 jbj Exp $
  +** WRLinux utilities
  +*/
  +
  +
  +#include <stdlib.h>
  +#include <string.h>
  +
  +#define lwrs_c
  +
  +#include "lua.h"
  +
  +#include "lualib.h"
  +#include "lauxlib.h"
  +#include "lwrs.h"
  +
  +extern int useradd_main (int argc, char **argv);
  +extern int chkconfig_main (int argc, char **argv);
  +
  +static int lcl_makeArgv(char *in, char **argv, int max)
  + {
  + int i;
  + char delim = ' ';
  + char *start = NULL;
  + char c;
  +
  + printf("Creating argv from [%s]\n", in);
  +
  + for ( i=0; i < max; ++i)
  +  {
  +   while (*in == ' ')  ++in;        /* skip spaces */
  +   if (!*in)  return i;             /* ignore traing spaces */
  +   if (*in == '"')  delim = *in++;  /* begin a quoted string */
  +   start = in;                      /* beginning of token */
  +   for ( c = *in; c != delim && c; c = *in)  ++in;  /* find end of token */
  +   *in++ = '\0';         /* mark end */
  +   *(argv+i) = start;    /* might be 0 length! */
  +   if (!c)  return i+1;  /* end of input string */
  +   delim = ' ';
  +  }
  + return -1;
  + }
  +
  +static int wrs_version (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  printf("version 7\n");
  +  return 0;
  +}
  +
  +static int wrs_groupadd (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  useradd_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +static int wrs_useradd (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  useradd_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +static int wrs_chkconfig (lua_State *L)
  +	/*@globals internalState @*/
  +	/*@modifies L, internalState @*/
  +{
  +  int argc;
  +  char *argv[32];  /* yeah, well, this is big enough */
  +  char *cmdline;   /* copy string from lua just to be safe */
  +
  +  argc = lua_gettop(L);  /* number of arguments */
  +  if (argc != 1)  return luaL_error(L, "One argument is required!");
  +
  +  cmdline = strdup(luaL_checklstring(L, 1, NULL));   /* we don't need the size */
  +
  +  argc = 1 + lcl_makeArgv(cmdline, argv+1, 31);
  +
  +  argv[0] = "rpm_lua";   /* make up a program name */
  +
  +  chkconfig_main(argc, argv);
  +
  +  free(cmdline);
  +  return 0;
  +}
  +
  +/*@-readonlytrans@*/
  +/*@unchecked@*/
  +static const luaL_reg wrs[] = {
  +  {"version",   wrs_version},
  +  {"groupadd",  wrs_groupadd},
  +  {"useradd",  wrs_useradd},
  +  {"chkconfig",  wrs_chkconfig},
  +  {NULL, NULL}
  +};
  +/*@=readonlytrans@*/
  +
  +
  +/*
  +** Open wrs library
  +*/
  +LUALIB_API int luaopen_wrs (lua_State *L) {
  +  luaL_openlib(L, "wrs", wrs, 0);
  +  return 1;
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/local/lwrs.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 lwrs.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ lwrs.h	2008-08-17 20:31:35 +0200
  @@ -0,0 +1,7 @@
  +#ifndef LWRS_H
  +#define LWRS_H
  +
  +int luaopen_wrs(lua_State *L)
  +	/*@modifies L @*/;
  +
  +#endif
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/lualib.h
  ============================================================================
  $ cvs diff -u -r1.2 -r1.3 lualib.h
  --- lua/lualib.h	25 Jan 2008 16:54:30 -0000	1.2
  +++ lua/lualib.h	17 Aug 2008 18:31:34 -0000	1.3
  @@ -39,7 +39,6 @@
   #define LUA_LOADLIBNAME	"package"
   LUALIB_API int (luaopen_package) (lua_State *L);
   
  -
   /* open all previous libraries */
   LUALIB_API void (luaL_openlibs) (lua_State *L); 
   
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/chkname.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 chkname.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ chkname.h	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,21 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* $Id: chkname.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */
  +#ifndef _CHKNAME_H_
  +#define _CHKNAME_H_
  +
  +/*
  + * check_user_name(), check_group_name() - check the new user/group
  + * name for validity; return value: 1 - OK, 0 - bad name
  + */
  +
  +#include "defines.h"
  +
  +extern int check_user_name (const char *);
  +extern int check_group_name (const char *name);
  +
  +#endif
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/commonio.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 commonio.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ commonio.c	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,945 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +
  +#include "config.h"
  +
  +#ident "$Id: commonio.c,v 1.1 2008/08/17 18:31:35 jbj Exp $"
  +
  +#include "defines.h"
  +#include <sys/stat.h>
  +#include <stdlib.h>
  +#include <limits.h>
  +#include <utime.h>
  +#include <fcntl.h>
  +#include <errno.h>
  +#include <stdio.h>
  +#include <signal.h>
  +#include <pwd.h>
  +#include "nscd.h"
  +#ifdef HAVE_SHADOW_H
  +#include <shadow.h>
  +#endif
  +#ifdef WITH_SELINUX
  +#include <selinux/selinux.h>
  +static security_context_t old_context = NULL;
  +#endif
  +#include "commonio.h"
  +
  +/* local function prototypes */
  +static int lrename (const char *, const char *);
  +static int check_link_count (const char *);
  +static int do_lock_file (const char *, const char *);
  +static FILE *fopen_set_perms (const char *, const char *, const struct stat *);
  +static int create_backup (const char *, FILE *);
  +static void free_linked_list (struct commonio_db *);
  +static void add_one_entry (struct commonio_db *, struct commonio_entry *);
  +static int name_is_nis (const char *);
  +static int write_all (const struct commonio_db *);
  +static struct commonio_entry *find_entry_by_name (struct commonio_db *,
  +						  const char *);
  +
  +static int lock_count = 0;
  +static int nscd_need_reload = 0;
  +
  +/*
  + * Simple rename(P) alternative that attempts to rename to symlink
  + * target.
  + */
  +int lrename (const char *old, const char *new)
  +{
  +
  +	char resolved_path[PATH_MAX];
  +	int res;
  +
  +#if defined(S_ISLNK)
  +	struct stat sb = { 0 };
  +	if (lstat (new, &sb) == 0 && S_ISLNK (sb.st_mode)) {
  +		if (realpath (new, resolved_path) == NULL) {
  +			perror ("realpath in lrename()");
  +		} else {
  +			new = resolved_path;
  +		}
  +	}
  +#endif
  +	res = rename (old, new);
  +	return res;
  +}
  +
  +static int check_link_count (const char *file)
  +{
  +	struct stat sb;
  +
  +	if (stat (file, &sb) != 0)
  +		return 0;
  +
  +	if (sb.st_nlink != 2)
  +		return 0;
  +
  +	return 1;
  +}
  +
  +
  +static int do_lock_file (const char *file, const char *lock)
  +{
  +	int fd;
  +	int pid;
  +	int len;
  +	int retval;
  +	char buf[32];
  +
  +	if ((fd = open (file, O_CREAT | O_EXCL | O_WRONLY, 0600)) == -1)
  +		return 0;
  +
  +	pid = getpid ();
  +	snprintf (buf, sizeof buf, "%d", pid);
  +	len = strlen (buf) + 1;
  +	if (write (fd, buf, len) != len) {
  +		close (fd);
  +		unlink (file);
  +		return 0;
  +	}
  +	close (fd);
  +
  +	if (link (file, lock) == 0) {
  +		retval = check_link_count (file);
  +		unlink (file);
  +		return retval;
  +	}
  +
  +	if ((fd = open (lock, O_RDWR)) == -1) {
  +		unlink (file);
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	len = read (fd, buf, sizeof (buf) - 1);
  +	close (fd);
  +	if (len <= 0) {
  +		unlink (file);
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	buf[len] = '\0';
  +	if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
  +		unlink (file);
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	if (kill (pid, 0) == 0) {
  +		unlink (file);
  +		errno = EEXIST;
  +		return 0;
  +	}
  +	if (unlink (lock) != 0) {
  +		unlink (file);
  +		return 0;
  +	}
  +
  +	retval = 0;
  +	if (link (file, lock) == 0 && check_link_count (file))
  +		retval = 1;
  +
  +	unlink (file);
  +	return retval;
  +}
  +
  +
  +static FILE *fopen_set_perms (const char *name, const char *mode,
  +			      const struct stat *sb)
  +{
  +	FILE *fp;
  +	mode_t mask;
  +
  +	mask = umask (0777);
  +	fp = fopen (name, mode);
  +	umask (mask);
  +	if (!fp)
  +		return NULL;
  +
  +#ifdef HAVE_FCHOWN
  +	if (fchown (fileno (fp), sb->st_uid, sb->st_gid))
  +		goto fail;
  +#else
  +	if (chown (name, sb->st_mode))
  +		goto fail;
  +#endif
  +
  +#ifdef HAVE_FCHMOD
  +	if (fchmod (fileno (fp), sb->st_mode & 0664))
  +		goto fail;
  +#else
  +	if (chmod (name, sb->st_mode & 0664))
  +		goto fail;
  +#endif
  +	return fp;
  +
  +      fail:
  +	fclose (fp);
  +	unlink (name);
  +	return NULL;
  +}
  +
  +
  +static int create_backup (const char *backup, FILE * fp)
  +{
  +	struct stat sb;
  +	struct utimbuf ub;
  +	FILE *bkfp;
  +	int c;
  +	mode_t mask;
  +
  +	if (fstat (fileno (fp), &sb))
  +		return -1;
  +
  +	mask = umask (077);
  +	bkfp = fopen (backup, "w");
  +	umask (mask);
  +	if (!bkfp)
  +		return -1;
  +
  +	/* TODO: faster copy, not one-char-at-a-time.  --marekm */
  +	c = 0;
  +	if (fseek (fp, 0, SEEK_SET) == 0)
  +		while ((c = getc (fp)) != EOF) {
  +			if (putc (c, bkfp) == EOF)
  +				break;
  +		}
  +	if (c != EOF || ferror (fp) || fflush (bkfp)) {
  +		fclose (bkfp);
  +		return -1;
  +	}
  +	if (fclose (bkfp))
  +		return -1;
  +
  +	ub.actime = sb.st_atime;
  +	ub.modtime = sb.st_mtime;
  +	utime (backup, &ub);
  +	return 0;
  +}
  +
  +
  +static void free_linked_list (struct commonio_db *db)
  +{
  +	struct commonio_entry *p;
  +
  +	while (db->head) {
  +		p = db->head;
  +		db->head = p->next;
  +
  +		if (p->line)
  +			free (p->line);
  +
  +		if (p->eptr)
  +			db->ops->free (p->eptr);
  +
  +		free (p);
  +	}
  +	db->tail = NULL;
  +}
  +
  +
  +int commonio_setname (struct commonio_db *db, const char *name)
  +{
  +	snprintf (db->filename, sizeof (db->filename), "%s", name);
  +	return 1;
  +}
  +
  +
  +int commonio_present (const struct commonio_db *db)
  +{
  +	return (access (db->filename, F_OK) == 0);
  +}
  +
  +
  +int commonio_lock_nowait (struct commonio_db *db)
  +{
  +	char file[1024];
  +	char lock[1024];
  +
  +	if (db->locked)
  +		return 1;
  +
  +	snprintf (file, sizeof file, "%s.%ld", db->filename, (long) getpid ());
  +	snprintf (lock, sizeof lock, "%s.lock", db->filename);
  +	if (do_lock_file (file, lock)) {
  +		db->locked = 1;
  +		lock_count++;
  +		return 1;
  +	}
  +	return 0;
  +}
  +
  +
  +int commonio_lock (struct commonio_db *db)
  +{
  +
  +
  +#ifdef HAVE_LCKPWDF
  +#if 0
  +   printf("Locking file with LCKPWDF %s\n", db->filename);
  +#endif
  +	/*
  +	 * only if the system libc has a real lckpwdf() - the one from
  +	 * lockpw.c calls us and would cause infinite recursion!
  +	 */
  +
  +	/*
  +	 * Call lckpwdf() on the first lock.
  +	 * If it succeeds, call *_lock() only once
  +	 * (no retries, it should always succeed).
  +	 */
  +	if (lock_count == 0) {
  +		if (lckpwdf () == -1)
  +			return 0;	/* failure */
  +	}
  +
  +	if (commonio_lock_nowait (db))
  +		return 1;	/* success */
  +
  +	ulckpwdf ();
  +	return 0;		/* failure */
  +#else
  +	int i;
  +
  +   printf("Locking file without LCKPWDF %s\n", db->filename);
  +
  +	/*
  +	 * lckpwdf() not used - do it the old way.
  +	 */
  +#ifndef LOCK_TRIES
  +#define LOCK_TRIES 15
  +#endif
  +
  +#ifndef LOCK_SLEEP
  +#define LOCK_SLEEP 1
  +#endif
  +	for (i = 0; i < LOCK_TRIES; i++) {
  +		if (i > 0)
  +			sleep (LOCK_SLEEP);	/* delay between retries */
  +		if (commonio_lock_nowait (db))
  +			return 1;	/* success */
  +		/* no unnecessary retries on "permission denied" errors */
  +		if (geteuid () != 0)
  +			return 0;
  +	}
  +	return 0;		/* failure */
  +#endif
  +}
  +
  +static void dec_lock_count (void)
  +{
  +	if (lock_count > 0) {
  +		lock_count--;
  +		if (lock_count == 0) {
  +			/* Tell nscd when lock count goes to zero,
  +			   if any of the files were changed.  */
  +			if (nscd_need_reload) {
  +#if 0  /* no cache flushin' */
  +				nscd_flush_cache ("passwd");
  +				nscd_flush_cache ("group");
  +#endif
  +				nscd_need_reload = 0;
  +			}
  +#ifdef HAVE_LCKPWDF
  +			ulckpwdf ();
  +#endif
  +		}
  +	}
  +}
  +
  +
  +int commonio_unlock (struct commonio_db *db)
  +{
  +	char lock[1024];
  +
  +	if (db->isopen) {
  +		db->readonly = 1;
  +		if (!commonio_close (db)) {
  +			if (db->locked)
  +				dec_lock_count ();
  +			return 0;
  +		}
  +	}
  +	if (db->locked) {
  +		/*
  +		 * Unlock in reverse order: remove the lock file,
  +		 * then call ulckpwdf() (if used) on last unlock.
  +		 */
  +		db->locked = 0;
  +		snprintf (lock, sizeof lock, "%s.lock", db->filename);
  +		unlink (lock);
  +		dec_lock_count ();
  +		return 1;
  +	}
  +	return 0;
  +}
  +
  +
  +static void add_one_entry (struct commonio_db *db, struct commonio_entry *p)
  +{
  +	p->next = NULL;
  +	p->prev = db->tail;
  +	if (!db->head)
  +		db->head = p;
  +	if (db->tail)
  +		db->tail->next = p;
  +	db->tail = p;
  +}
  +
  +
  +static int name_is_nis (const char *n)
  +{
  +	return (n[0] == '+' || n[0] == '-');
  +}
  +
  +
  +/*
  + * New entries are inserted before the first NIS entry.  Order is preserved
  + * when db is written out.
  + */
  +#ifndef KEEP_NIS_AT_END
  +#define KEEP_NIS_AT_END 1
  +#endif
  +
  +#if KEEP_NIS_AT_END
  +static void add_one_entry_nis (struct commonio_db *, struct commonio_entry *);
  +
  +static void
  +add_one_entry_nis (struct commonio_db *db, struct commonio_entry *newp)
  +{
  +	struct commonio_entry *p;
  +
  +	for (p = db->head; p; p = p->next) {
  +		if (name_is_nis
  +		    (p->eptr ? db->ops->getname (p->eptr) : p->line)) {
  +			newp->next = p;
  +			newp->prev = p->prev;
  +			if (p->prev)
  +				p->prev->next = newp;
  +			else
  +				db->head = newp;
  +			p->prev = newp;
  +			return;
  +		}
  +	}
  +	add_one_entry (db, newp);
  +}
  +#endif				/* KEEP_NIS_AT_END */
  +
  +/* Initial buffer size, as well as increment if not sufficient
  +   (for reading very long lines in group files).  */
  +#define BUFLEN 4096
  +
  +int commonio_open (struct commonio_db *db, int mode)
  +{
  +	char *buf;
  +	char *cp;
  +	char *line;
  +	struct commonio_entry *p;
  +	void *eptr;
  +	int flags = mode;
  +	int buflen;
  +	int saved_errno;
  +
  +	mode &= ~O_CREAT;
  +
  +	if (db->isopen || (mode != O_RDONLY && mode != O_RDWR)) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	db->readonly = (mode == O_RDONLY);
  +	if (!db->readonly && !db->locked) {
  +		errno = EACCES;
  +		return 0;
  +	}
  +
  +	db->head = db->tail = db->cursor = NULL;
  +	db->changed = 0;
  +
  +	db->fp = fopen (db->filename, db->readonly ? "r" : "r+");
  +
  +	/*
  +	 * If O_CREAT was specified and the file didn't exist, it will be
  +	 * created by commonio_close().  We have no entries to read yet.  --marekm
  +	 */
  +	if (!db->fp) {
  +		if ((flags & O_CREAT) && errno == ENOENT) {
  +			db->isopen = 1;
  +			return 1;
  +		}
  +		return 0;
  +	}
  +
  +	/* not not inherit fd */
  +	fcntl(fileno(db->fp), F_SETFD, FD_CLOEXEC);
  +
  +#ifdef WITH_SELINUX
  +	db->scontext = NULL;
  +	if ((is_selinux_enabled () > 0) && (!db->readonly)) {
  +		if (fgetfilecon (fileno (db->fp), &db->scontext) < 0) {
  +			goto cleanup_errno;
  +		}
  +	}
  +#endif
  +
  +	buflen = BUFLEN;
  +	buf = (char *) malloc (buflen);
  +	if (!buf)
  +		goto cleanup_ENOMEM;
  +
  +	while (db->ops->fgets (buf, buflen, db->fp)) {
  +#if 0
  +                printf("Reading from %s\n",db->filename);
  +#endif
  +		while (!(cp = strrchr (buf, '\n')) && !feof (db->fp)) {
  +			int len;
  +
  +			buflen += BUFLEN;
  +			cp = (char *) realloc (buf, buflen);
  +			if (!cp)
  +				goto cleanup_buf;
  +			buf = cp;
  +			len = strlen (buf);
  +			db->ops->fgets (buf + len, buflen - len, db->fp);
  +		}
  +		if ((cp = strrchr (buf, '\n')))
  +			*cp = '\0';
  +
  +		if (!(line = strdup (buf)))
  +			goto cleanup_buf;
  +
  +		if (name_is_nis (line)) {
  +			eptr = NULL;
  +		} else if ((eptr = db->ops->parse (line))) {
  +			eptr = db->ops->dup (eptr);
  +			if (!eptr)
  +				goto cleanup_line;
  +		}
  +
  +		p = (struct commonio_entry *) malloc (sizeof *p);
  +		if (!p)
  +			goto cleanup_entry;
  +
  +		p->eptr = eptr;
  +		p->line = line;
  +		p->changed = 0;
  +
  +		add_one_entry (db, p);
  +	}
  +
  +	free (buf);
  +
  +	if (ferror (db->fp))
  +		goto cleanup_errno;
  +
  +	db->isopen = 1;
  +	return 1;
  +
  +      cleanup_entry:
  +	if (eptr)
  +		db->ops->free (eptr);
  +      cleanup_line:
  +	free (line);
  +      cleanup_buf:
  +	free (buf);
  +      cleanup_ENOMEM:
  +	errno = ENOMEM;
  +      cleanup_errno:
  +	saved_errno = errno;
  +	free_linked_list (db);
  +#ifdef WITH_SELINUX
  +	if (db->scontext != NULL) {
  +		freecon (db->scontext);
  +		db->scontext = NULL;
  +	}
  +#endif
  +	fclose (db->fp);
  +	db->fp = NULL;
  +	errno = saved_errno;
  +	return 0;
  +}
  +
  +/*
  + * Sort given db according to cmp function (usually compares uids)
  + */
  +int
  +commonio_sort (struct commonio_db *db, int (*cmp) (const void *, const void *))
  +{
  +	struct commonio_entry **entries, *ptr;
  +	int n = 0, i;
  +
  +	for (ptr = db->head; ptr; ptr = ptr->next)
  +		n++;
  +
  +	if (n <= 1)
  +		return 0;
  +
  +	entries = malloc (n * sizeof (struct commonio_entry *));
  +	if (entries == NULL)
  +		return -1;
  +
  +	n = 0;
  +	for (ptr = db->head; ptr; ptr = ptr->next)
  +		entries[n++] = ptr;
  +	qsort (entries, n, sizeof (struct commonio_entry *), cmp);
  +
  +	db->head = entries[0];
  +	db->tail = entries[--n];
  +	db->head->prev = NULL;
  +	db->head->next = entries[1];
  +	db->tail->prev = entries[n - 1];
  +	db->tail->next = NULL;
  +
  +	for (i = 1; i < n; i++) {
  +		entries[i]->prev = entries[i - 1];
  +		entries[i]->next = entries[i + 1];
  +	}
  +
  +	free (entries);
  +	db->changed = 1;
  +
  +	return 0;
  +}
  +
  +/*
  + * Sort entries in db according to order in another.
  + */
  +int commonio_sort_wrt (struct commonio_db *shadow, struct commonio_db *passwd)
  +{
  +	struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
  +	const char *name;
  +
  +	if (!shadow || !shadow->head)
  +		return 0;
  +
  +	for (pw_ptr = passwd->head; pw_ptr; pw_ptr = pw_ptr->next) {
  +		if (pw_ptr->eptr == NULL)
  +			continue;
  +		name = passwd->ops->getname (pw_ptr->eptr);
  +		for (spw_ptr = shadow->head; spw_ptr; spw_ptr = spw_ptr->next)
  +			if (strcmp (name, shadow->ops->getname (spw_ptr->eptr))
  +			    == 0)
  +				break;
  +		if (spw_ptr == NULL)
  +			continue;
  +		commonio_del_entry (shadow, spw_ptr);
  +		spw_ptr->next = head;
  +		head = spw_ptr;
  +	}
  +
  +	for (spw_ptr = head; spw_ptr; spw_ptr = head) {
  +		head = head->next;
  +
  +		if (shadow->head)
  +			shadow->head->prev = spw_ptr;
  +		spw_ptr->next = shadow->head;
  +		shadow->head = spw_ptr;
  +	}
  +
  +	shadow->head->prev = NULL;
  +	shadow->changed = 1;
  +
  +	return 0;
  +}
  +
  +static int write_all (const struct commonio_db *db)
  +{
  +	const struct commonio_entry *p;
  +	void *eptr;
  +
  +	for (p = db->head; p; p = p->next) {
  +		if (p->changed) {
  +			eptr = p->eptr;
  +			if (db->ops->put (eptr, db->fp))
  +				return -1;
  +		} else if (p->line) {
  +			if (db->ops->fputs (p->line, db->fp) == EOF)
  +				return -1;
  +			if (putc ('\n', db->fp) == EOF)
  +				return -1;
  +		}
  +	}
  +	return 0;
  +}
  +
  +
  +int commonio_close (struct commonio_db *db)
  +{
  +	char buf[1024];
  +	int errors = 0;
  +	struct stat sb;
  +
  +	if (!db->isopen) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	db->isopen = 0;
  +
  +	if (!db->changed || db->readonly) {
  +		fclose (db->fp);
  +		db->fp = NULL;
  +		goto success;
  +	}
  +
  +	memzero (&sb, sizeof sb);
  +	if (db->fp) {
  +		if (fstat (fileno (db->fp), &sb)) {
  +			fclose (db->fp);
  +			db->fp = NULL;
  +			goto fail;
  +		}
  +#ifdef WITH_SELINUX
  +		if (db->scontext != NULL) {
  +			int stat = getfscreatecon (&old_context);
  +
  +			if (stat < 0) {
  +				errors++;
  +				goto fail;
  +			}
  +			if (setfscreatecon (db->scontext) < 0) {
  +				errors++;
  +				goto fail;
  +			}
  +		}
  +#endif
  +		/*
  +		 * Create backup file.
  +		 */
  +		snprintf (buf, sizeof buf, "%s-", db->filename);
  +
  +		if (create_backup (buf, db->fp))
  +			errors++;
  +
  +		if (fclose (db->fp))
  +			errors++;
  +
  +		if (errors) {
  +			db->fp = NULL;
  +			goto fail;
  +		}
  +	} else {
  +		/*
  +		 * Default permissions for new [g]shadow files.
  +		 * (passwd and group always exist...)
  +		 */
  +		sb.st_mode = 0400;
  +		sb.st_uid = 0;
  +		sb.st_gid = 0;
  +	}
  +
  +	snprintf (buf, sizeof buf, "%s+", db->filename);
  +
  +	db->fp = fopen_set_perms (buf, "w", &sb);
  +	if (!db->fp)
  +		goto fail;
  +
  +	if (write_all (db))
  +		errors++;
  +
  +	if (fflush (db->fp))
  +		errors++;
  +#ifdef HAVE_FSYNC
  +	if (fsync (fileno (db->fp)))
  +		errors++;
  +#else
  +	sync ();
  +#endif
  +	if (fclose (db->fp))
  +		errors++;
  +
  +	db->fp = NULL;
  +
  +	if (errors) {
  +		unlink (buf);
  +		goto fail;
  +	}
  +
  +	if (lrename (buf, db->filename))
  +		goto fail;
  +
  +	nscd_need_reload = 1;
  +	goto success;
  +      fail:
  +	errors++;
  +      success:
  +
  +#ifdef WITH_SELINUX
  +	if (db->scontext != NULL) {
  +		if (setfscreatecon (old_context) < 0) {
  +			errors++;
  +		}
  +		if (old_context != NULL) {
  +			freecon (old_context);
  +			old_context = NULL;
  +		}
  +		freecon (db->scontext);
  +		db->scontext = NULL;
  +	}
  +#endif
  +	free_linked_list (db);
  +	return errors == 0;
  +}
  +
  +
  +static struct commonio_entry *find_entry_by_name (struct commonio_db *db,
  +						  const char *name)
  +{
  +	struct commonio_entry *p;
  +	void *ep;
  +
  +	for (p = db->head; p; p = p->next) {
  +		ep = p->eptr;
  +		if (ep && strcmp (db->ops->getname (ep), name) == 0)
  +			break;
  +	}
  +	return p;
  +}
  +
  +
  +int commonio_update (struct commonio_db *db, const void *eptr)
  +{
  +	struct commonio_entry *p;
  +	void *nentry;
  +
  +	if (!db->isopen || db->readonly) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	if (!(nentry = db->ops->dup (eptr))) {
  +		errno = ENOMEM;
  +		return 0;
  +	}
  +	p = find_entry_by_name (db, db->ops->getname (eptr));
  +	if (p) {
  +		db->ops->free (p->eptr);
  +		p->eptr = nentry;
  +		p->changed = 1;
  +		db->cursor = p;
  +
  +		db->changed = 1;
  +		return 1;
  +	}
  +	/* not found, new entry */
  +	p = (struct commonio_entry *) malloc (sizeof *p);
  +	if (!p) {
  +		db->ops->free (nentry);
  +		errno = ENOMEM;
  +		return 0;
  +	}
  +
  +	p->eptr = nentry;
  +	p->line = NULL;
  +	p->changed = 1;
  +
  +#if KEEP_NIS_AT_END
  +	add_one_entry_nis (db, p);
  +#else
  +	add_one_entry (db, p);
  +#endif
  +#if 0
  +        printf("Entry added to db\n");
  +#endif
  +	db->changed = 1;
  +	return 1;
  +}
  +
  +
  +void commonio_del_entry (struct commonio_db *db, const struct commonio_entry *p)
  +{
  +	if (p == db->cursor)
  +		db->cursor = p->next;
  +
  +	if (p->prev)
  +		p->prev->next = p->next;
  +	else
  +		db->head = p->next;
  +
  +	if (p->next)
  +		p->next->prev = p->prev;
  +	else
  +		db->tail = p->prev;
  +
  +	db->changed = 1;
  +}
  +
  +
  +int commonio_remove (struct commonio_db *db, const char *name)
  +{
  +	struct commonio_entry *p;
  +
  +	if (!db->isopen || db->readonly) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	p = find_entry_by_name (db, name);
  +	if (!p) {
  +		errno = ENOENT;
  +		return 0;
  +	}
  +
  +	commonio_del_entry (db, p);
  +
  +	if (p->line)
  +		free (p->line);
  +
  +	if (p->eptr)
  +		db->ops->free (p->eptr);
  +
  +	return 1;
  +}
  +
  +
  +const void *commonio_locate (struct commonio_db *db, const char *name)
  +{
  +	struct commonio_entry *p;
  +
  +	if (!db->isopen) {
  +		errno = EINVAL;
  +		return NULL;
  +	}
  +	p = find_entry_by_name (db, name);
  +	if (!p) {
  +		errno = ENOENT;
  +		return NULL;
  +	}
  +	db->cursor = p;
  +	return p->eptr;
  +}
  +
  +
  +int commonio_rewind (struct commonio_db *db)
  +{
  +	if (!db->isopen) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	db->cursor = NULL;
  +	return 1;
  +}
  +
  +
  +const void *commonio_next (struct commonio_db *db)
  +{
  +	void *eptr;
  +
  +	if (!db->isopen) {
  +		errno = EINVAL;
  +		return 0;
  +	}
  +	if (db->cursor == NULL)
  +		db->cursor = db->head;
  +	else
  +		db->cursor = db->cursor->next;
  +
  +	while (db->cursor) {
  +		eptr = db->cursor->eptr;
  +		if (eptr)
  +			return eptr;
  +
  +		db->cursor = db->cursor->next;
  +	}
  +	return NULL;
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/commonio.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 commonio.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ commonio.h	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,116 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* $Id: commonio.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */
  +
  +#ifdef WITH_SELINUX
  +#include <selinux/selinux.h>
  +#endif
  +/*
  + * Linked list entry.
  + */
  +struct commonio_entry {
  +	char *line;
  +	void *eptr;		/* struct passwd, struct spwd, ... */
  +	struct commonio_entry *prev, *next;
  +	int changed:1;
  +};
  +
  +/*
  + * Operations depending on database type: passwd, group, shadow etc.
  + */
  +struct commonio_ops {
  +	/*
  +	 * Make a copy of the object (for example, struct passwd)
  +	 * and all strings pointed by it, in malloced memory.
  +	 */
  +	void *(*dup) (const void *);
  +
  +	/*
  +	 * free() the object including any strings pointed by it.
  +	 */
  +	void (*free) (void *);
  +
  +	/*
  +	 * Return the name of the object (for example, pw_name
  +	 * for struct passwd).
  +	 */
  +	const char *(*getname) (const void *);
  +
  +	/*
  +	 * Parse a string, return object (in static area -
  +	 * should be copied using the dup operation above).
  +	 */
  +	void *(*parse) (const char *);
  +
  +	/*
  +	 * Write the object to the file (this calls putpwent()
  +	 * for struct passwd, for example).
  +	 */
  +	int (*put) (const void *, FILE *);
  +
  +	/*
  +	 * fgets and fputs (can be replaced by versions that
  +	 * understand line continuation conventions).
  +	 */
  +	char *(*fgets) (char *, int, FILE *);
  +	int (*fputs) (const char *, FILE *);
  +};
  +
  +/*
  + * Database structure.
  + */
  +struct commonio_db {
  +	/*
  +	 * Name of the data file.
  +	 */
  +	char filename[1024];
  +
  +	/*
  +	 * Operations from above.
  +	 */
  +	struct commonio_ops *ops;
  +
  +	/*
  +	 * Currently open file stream.
  +	 */
  +	FILE *fp;
  +
  +#ifdef WITH_SELINUX
  +	security_context_t scontext;
  +#endif
  +	/*
  +	 * Head, tail, current position in linked list.
  +	 */
  +	struct commonio_entry *head, *tail, *cursor;
  +
  +	/*
  +	 * Various flags.
  +	 */
  +	int changed:1;
  +	int isopen:1;
  +	int locked:1;
  +	int readonly:1;
  +};
  +
  +extern int commonio_setname (struct commonio_db *, const char *);
  +extern int commonio_present (const struct commonio_db *);
  +extern int commonio_lock (struct commonio_db *);
  +extern int commonio_lock_nowait (struct commonio_db *);
  +extern int commonio_open (struct commonio_db *, int);
  +extern const void *commonio_locate (struct commonio_db *, const char *);
  +extern int commonio_update (struct commonio_db *, const void *);
  +extern int commonio_remove (struct commonio_db *, const char *);
  +extern int commonio_rewind (struct commonio_db *);
  +extern const void *commonio_next (struct commonio_db *);
  +extern int commonio_close (struct commonio_db *);
  +extern int commonio_unlock (struct commonio_db *);
  +extern void commonio_del_entry (struct commonio_db *,
  +				const struct commonio_entry *);
  +extern int commonio_sort_wrt (struct commonio_db *shadow,
  +			      struct commonio_db *passwd);
  +extern int commonio_sort (struct commonio_db *db,
  +			  int (*cmp) (const void *, const void *));
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/config.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 config.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ config.h	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,412 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* config.h.  Generated by configure.  */
  +/* config.h.in.  Generated from configure.in by autoheader.  */
  +
  +/* Define to 1 if translation of program messages to the user's native
  +   language is requested. */
  +#define ENABLE_NLS 1
  +
  +/* Path for faillog file. */
  +#define FAILLOG_FILE "/var/log/faillog"
  +
  +/* Define to the type of elements in the array set by `getgroups'. Usually
  +   this is either `int' or `gid_t'. */
  +#define GETGROUPS_T gid_t
  +
  +/* Define to 1 if you have the `a64l' function. */
  +#define HAVE_A64L 1
  +
  +/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
  +   CoreFoundation framework. */
  +/* #undef HAVE_CFLOCALECOPYCURRENT */
  +
  +/* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
  +   the CoreFoundation framework. */
  +/* #undef HAVE_CFPREFERENCESCOPYAPPVALUE */
  +
  +/* Define if the GNU dcgettext() function is already present or preinstalled.
  +   */
  +#define HAVE_DCGETTEXT 1
  +
  +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
  +   */
  +#define HAVE_DIRENT_H 1
  +
  +/* Define to 1 if you have the <dlfcn.h> header file. */
  +#define HAVE_DLFCN_H 1
  +
  +/* Define to 1 if you have the <errno.h> header file. */
  +#define HAVE_ERRNO_H 1
  +
  +/* Define to 1 if you have the `fchmod' function. */
  +#define HAVE_FCHMOD 1
  +
  +/* Define to 1 if you have the `fchown' function. */
  +#define HAVE_FCHOWN 1
  +
  +/* Define to 1 if you have the <fcntl.h> header file. */
  +#define HAVE_FCNTL_H 1
  +
  +/* Define to 1 if you have the `fsync' function. */
  +#define HAVE_FSYNC 1
  +
  +/* Define to 1 if you have the `getgroups' function. */
  +#define HAVE_GETGROUPS 1
  +
  +/* Define to 1 if you have the `gethostname' function. */
  +#define HAVE_GETHOSTNAME 1
  +
  +/* Define to 1 if you have the `getspnam' function. */
  +#define HAVE_GETSPNAM 1
  +
  +/* Define if the GNU gettext() function is already present or preinstalled. */
  +#define HAVE_GETTEXT 1
  +
  +/* Define to 1 if you have the `gettimeofday' function. */
  +#define HAVE_GETTIMEOFDAY 1
  +
  +/* Define to 1 if you have the `getusershell' function. */
  +#define HAVE_GETUSERSHELL 1
  +
  +/* Define to 1 if you have the `getutent' function. */
  +#define HAVE_GETUTENT 1
  +
  +/* Define to 1 if you have the <gshadow.h> header file. */
  +/* #undef HAVE_GSHADOW_H */
  +
  +/* Define if you have the iconv() function. */
  +/* #undef HAVE_ICONV */
  +
  +/* Define to 1 if you have the `initgroups' function. */
  +#define HAVE_INITGROUPS 1
  +
  +/* Define to 1 if you have the <inttypes.h> header file. */
  +#define HAVE_INTTYPES_H 1
  +
  +/* Define to 1 if you have the <lastlog.h> header file. */
  +#define HAVE_LASTLOG_H 1
  +
  +/* Define to 1 if you have the `lchown' function. */
  +#define HAVE_LCHOWN 1
  +
  +/* Define to 1 if you have the `lckpwdf' function. */
  +#define HAVE_LCKPWDF 1
  +
  +/* Defined if you have libcrack. */
  +/* #undef HAVE_LIBCRACK */
  +
  +/* Defined if you have the ts&szs cracklib. */
  +/* #undef HAVE_LIBCRACK_HIST */
  +
  +/* Defined if it includes *Pw functions. */
  +/* #undef HAVE_LIBCRACK_PW */
  +
  +/* Define to 1 if you have the <limits.h> header file. */
  +#define HAVE_LIMITS_H 1
  +
  +/* Define if struct lastlog has ll_host */
  +#define HAVE_LL_HOST 1
  +
  +/* Define to 1 if you have the <locale.h> header file. */
  +#define HAVE_LOCALE_H 1
  +
  +/* Define to 1 if you have the `lstat' function. */
  +#define HAVE_LSTAT 1
  +
  +/* Define to 1 if you have the `memcpy' function. */
  +#define HAVE_MEMCPY 1
  +
  +/* Define to 1 if you have the <memory.h> header file. */
  +#define HAVE_MEMORY_H 1
  +
  +/* Define to 1 if you have the `memset' function. */
  +#define HAVE_MEMSET 1
  +
  +/* Define to 1 if you have the `mkdir' function. */
  +#define HAVE_MKDIR 1
  +
  +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
  +/* #undef HAVE_NDIR_H */
  +
  +/* Define to 1 if you have the <paths.h> header file. */
  +#define HAVE_PATHS_H 1
  +
  +/* Define to 1 if you have the `putgrent' function. */
  +#define HAVE_PUTGRENT 1
  +
  +/* Define to 1 if you have the `putpwent' function. */
  +#define HAVE_PUTPWENT 1
  +
  +/* Define to 1 if you have the `putspent' function. */
  +#define HAVE_PUTSPENT 1
  +
  +/* Define to 1 if you have the `rename' function. */
  +#define HAVE_RENAME 1
  +
  +/* Define to 1 if you have the `rmdir' function. */
  +#define HAVE_RMDIR 1
  +
  +/* Define to 1 if you have the <rpc/key_prot.h> header file. */
  +#define HAVE_RPC_KEY_PROT_H 1
  +
  +/* Define to 1 if you have the <selinux/selinux.h> header file. */
  +/* #undef HAVE_SELINUX_SELINUX_H */
  +
  +/* Define to 1 if you have the `setgroups' function. */
  +#define HAVE_SETGROUPS 1
  +
  +/* Define to 1 if you have the `sgetgrent' function. */
  +/* #undef HAVE_SGETGRENT */
  +
  +/* Define to 1 if you have the `sgetpwent' function. */
  +/* #undef HAVE_SGETPWENT */
  +
  +/* Define to 1 if you have the `sgetspent' function. */
  +#define HAVE_SGETSPENT 1
  +
  +/* Define to 1 if you have the <sgtty.h> header file. */
  +#define HAVE_SGTTY_H 1
  +
  +/* Have working shadow group support in libc */
  +/* #undef HAVE_SHADOWGRP */
  +
  +/* Define to 1 if you have the <shadow.h> header file. */
  +#define HAVE_SHADOW_H 1
  +
  +/* Define to 1 if you have the `sigaction' function. */
  +#define HAVE_SIGACTION 1
  +
  +/* Define to 1 if you have the `snprintf' function. */
  +#define HAVE_SNPRINTF 1
  +
  +/* Define to 1 if you have the <stdint.h> header file. */
  +#define HAVE_STDINT_H 1
  +
  +/* Define to 1 if you have the <stdlib.h> header file. */
  +#define HAVE_STDLIB_H 1
  +
  +/* Define to 1 if you have the `strcasecmp' function. */
  +#define HAVE_STRCASECMP 1
  +
  +/* Define to 1 if you have the `strchr' function. */
  +#define HAVE_STRCHR 1
  +
  +/* Define to 1 if you have the `strdup' function. */
  +#define HAVE_STRDUP 1
  +
  +/* Define to 1 if you have the `strerror' function. */
  +#define HAVE_STRERROR 1
  +
  +/* Define to 1 if you have the `strftime' function. */
  +#define HAVE_STRFTIME 1
  +
  +/* Define to 1 if you have the <strings.h> header file. */
  +#define HAVE_STRINGS_H 1
  +
  +/* Define to 1 if you have the <string.h> header file. */
  +#define HAVE_STRING_H 1
  +
  +/* Define to 1 if you have the `strstr' function. */
  +#define HAVE_STRSTR 1
  +
  +/* Define to 1 if `st_rdev' is member of `struct stat'. */
  +#define HAVE_STRUCT_STAT_ST_RDEV 1
  +
  +/* Define to 1 if you have the <syslog.h> header file. */
  +#define HAVE_SYSLOG_H 1
  +
  +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
  +   */
  +/* #undef HAVE_SYS_DIR_H */
  +
  +/* Define to 1 if you have the <sys/ioctl.h> header file. */
  +#define HAVE_SYS_IOCTL_H 1
  +
  +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
  +   */
  +/* #undef HAVE_SYS_NDIR_H */
  +
  +/* Define to 1 if you have the <sys/resource.h> header file. */
  +#define HAVE_SYS_RESOURCE_H 1
  +
  +/* Define to 1 if you have the <sys/stat.h> header file. */
  +#define HAVE_SYS_STAT_H 1
  +
  +/* Define to 1 if you have the <sys/time.h> header file. */
  +#define HAVE_SYS_TIME_H 1
  +
  +/* Define to 1 if you have the <sys/types.h> header file. */
  +#define HAVE_SYS_TYPES_H 1
  +
  +/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
  +#define HAVE_SYS_WAIT_H 1
  +
  +/* Define to 1 if you have the <termios.h> header file. */
  +#define HAVE_TERMIOS_H 1
  +
  +/* Define to 1 if you have the <termio.h> header file. */
  +#define HAVE_TERMIO_H 1
  +
  +/* Define to 1 if you have the <ulimit.h> header file. */
  +#define HAVE_ULIMIT_H 1
  +
  +/* Define to 1 if you have the <unistd.h> header file. */
  +#define HAVE_UNISTD_H 1
  +
  +/* Define to 1 if you have the `updwtmp' function. */
  +#define HAVE_UPDWTMP 1
  +
  +/* Define to 1 if you have the `updwtmpx' function. */
  +#define HAVE_UPDWTMPX 1
  +
  +/* Define to 1 if you have the <utime.h> header file. */
  +#define HAVE_UTIME_H 1
  +
  +/* Define to 1 if `utime(file, NULL)' sets file's timestamp to the present. */
  +#define HAVE_UTIME_NULL 1
  +
  +/* Define to 1 if you have the <utmpx.h> header file. */
  +#define HAVE_UTMPX_H 1
  +
  +/* Define to 1 if you have the <utmp.h> header file. */
  +#define HAVE_UTMP_H 1
  +
  +/* Path for lastlog file. */
  +#define LASTLOG_FILE "/var/log/lastlog"
  +
  +/* Location of system mail spool directory. */
  +#define MAIL_SPOOL_DIR "/var/mail"
  +
  +/* Name of user's mail spool file if stored in user's home directory. */
  +/* #undef MAIL_SPOOL_FILE */
  +
  +#if 0
  +/* Name of package */
  +#define PACKAGE "shadow"
  +
  +/* Define to the address where bug reports for this package should be sent. */
  +#define PACKAGE_BUGREPORT ""
  +
  +/* Define to the full name of this package. */
  +#define PACKAGE_NAME ""
  +
  +/* Define to the full name and version of this package. */
  +#define PACKAGE_STRING ""
  +
  +/* Define to the one symbol short name of this package. */
  +#define PACKAGE_TARNAME ""
  +
  +/* Define to the version of this package. */
  +#define PACKAGE_VERSION ""
  +#endif
  +
  +/* Path to passwd program. */
  +#define PASSWD_PROGRAM "/usr/bin/passwd"
  +
  +/* Define to 1 if the C compiler supports function prototypes. */
  +#define PROTOTYPES 1
  +
  +/* Define as the return type of signal handlers (`int' or `void'). */
  +#define RETSIGTYPE void
  +
  +/* Define if login should support the -r flag for rlogind. */
  +#define RLOGIN 1
  +
  +/* Define to the ruserok() "success" return value (0 or 1). */
  +#define RUSEROK 0
  +
  +/* Define to 1 if the `setpgrp' function takes no argument. */
  +#define SETPGRP_VOID 1
  +
  +/* Define to support the shadow group file. */
  +#define SHADOWGRP 1
  +
  +/* Define to support S/Key logins. */
  +/* #undef SKEY */
  +
  +/* Define to support newer BSD S/Key API */
  +/* #undef SKEY_BSD_STYLE */
  +
  +/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
  +/* #undef STAT_MACROS_BROKEN */
  +
  +/* Define to 1 if you have the ANSI C header files. */
  +#define STDC_HEADERS 1
  +
  +/* Define to support /etc/suauth su access control. */
  +#define SU_ACCESS 1
  +
  +/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
  +#define TIME_WITH_SYS_TIME 1
  +
  +/* Define to 1 if your <sys/time.h> declares `struct tm'. */
  +/* #undef TM_IN_SYS_TIME */
  +
  +/* Define to support Pluggable Authentication Modules */
  +/* #undef USE_PAM */
  +
  +/* Define to use syslog(). */
  +#define USE_SYSLOG 1
  +
  +/* Define if you have ut_host in struct utmp. */
  +#define UT_HOST 1
  +
  +#if 0
  +/* Version number of package */
  +#define VERSION "4.0.17"
  +#endif
  +
  +/* Define if you want to enable Audit messages */
  +/* #undef WITH_AUDIT */
  +
  +/* Build shadow with SELinux support */
  +/* #undef WITH_SELINUX */
  +
  +/* Number of bits in a file offset, on hosts where this is settable. */
  +#define _FILE_OFFSET_BITS 64
  +
  +/* Enable GNU extensions on systems that have them.  */
  +#ifndef _GNU_SOURCE
  +# define _GNU_SOURCE 1
  +#endif
  +
  +/* Define for large files, on AIX-style hosts. */
  +/* #undef _LARGE_FILES */
  +
  +/* Path for utmp file. */
  +#define _UTMP_FILE "/var/run/utmp"
  +
  +/* Path for wtmp file. */
  +#define _WTMP_FILE "/var/log/wtmp"
  +
  +/* Define like PROTOTYPES; this can be used by system headers. */
  +#define __PROTOTYPES 1
  +
  +/* Define to empty if `const' does not conform to ANSI C. */
  +/* #undef const */
  +
  +/* Define to libshadow_getpass to use our own version of getpass(). */
  +/* #undef getpass */
  +
  +/* Define to `int' if <sys/types.h> doesn't define. */
  +/* #undef gid_t */
  +
  +/* Define to `int' if <sys/types.h> does not define. */
  +/* #undef mode_t */
  +
  +/* Define to `long' if <sys/types.h> does not define. */
  +/* #undef off_t */
  +
  +/* Define to `int' if <sys/types.h> does not define. */
  +/* #undef pid_t */
  +
  +/* Define to `int' if <sys/types.h> doesn't define. */
  +/* #undef uid_t */
  +
  +/* Define to ut_name if struct utmp has ut_name (not ut_user). */
  +/* #undef ut_user */
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/copydir.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 copydir.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ copydir.c	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,452 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/*
  + * Copyright 1991 - 1994, Julianne Frances Haugh
  + * All rights reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in the
  + *    documentation and/or other materials provided with the distribution.
  + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
  + *    may be used to endorse or promote products derived from this software
  + *    without specific prior written permission.
  + *
  + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
  + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  + * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + */
  +
  +#include "config.h"
  +
  +#ident "$Id: copydir.c,v 1.1 2008/08/17 18:31:35 jbj Exp $"
  +
  +#include <sys/stat.h>
  +#include <sys/types.h>
  +#include <fcntl.h>
  +#include <stdio.h>
  +#include "prototypes.h"
  +#include "defines.h"
  +#ifdef WITH_SELINUX
  +#include <selinux/selinux.h>
  +static int selinux_enabled = -1;
  +#endif
  +static const char *src_orig;
  +static const char *dst_orig;
  +
  +struct link_name {
  +	dev_t ln_dev;
  +	ino_t ln_ino;
  +	int ln_count;
  +	char *ln_name;
  +	struct link_name *ln_next;
  +};
  +static struct link_name *links;
  +
  +#ifdef WITH_SELINUX
  +static int selinux_file_context (const char *dst_name)
  +{
  +	security_context_t scontext = NULL;
  +
  +	if (selinux_enabled < 0)
  +		selinux_enabled = is_selinux_enabled () > 0;
  +	if (selinux_enabled) {
  +		if (matchpathcon (dst_name, 0, &scontext) < 0)
  +			if (security_getenforce ())
  +				return 1;
  +		if (setfscreatecon (scontext) < 0)
  +			if (security_getenforce ())
  +				return 1;
  +		freecon (scontext);
  +	}
  +	return 0;
  +}
  +#endif
  +
  +/*
  + * remove_link - delete a link from the link list
  + */
  +
  +static void remove_link (struct link_name *ln)
  +{
  +	struct link_name *lp;
  +
  +	if (links == ln) {
  +		links = ln->ln_next;
  +		free (ln->ln_name);
  +		free (ln);
  +		return;
  +	}
  +	for (lp = links; lp; lp = lp->ln_next)
  +		if (lp->ln_next == ln)
  +			break;
  +
  +	if (!lp)
  +		return;
  +
  +	lp->ln_next = lp->ln_next->ln_next;
  +	free (ln->ln_name);
  +	free (ln);
  +}
  +
  +/*
  + * check_link - see if a file is really a link
  + */
  +
  +static struct link_name *check_link (const char *name, const struct stat *sb)
  +{
  +	struct link_name *lp;
  +	int src_len;
  +	int dst_len;
  +	int name_len;
  +	int len;
  +
  +	for (lp = links; lp; lp = lp->ln_next)
  +		if (lp->ln_dev == sb->st_dev && lp->ln_ino == sb->st_ino)
  +			return lp;
  +
  +	if (sb->st_nlink == 1)
  +		return 0;
  +
  +	lp = (struct link_name *) xmalloc (sizeof *lp);
  +	src_len = strlen (src_orig);
  +	dst_len = strlen (dst_orig);
  +	name_len = strlen (name);
  +	lp->ln_dev = sb->st_dev;
  +	lp->ln_ino = sb->st_ino;
  +	lp->ln_count = sb->st_nlink;
  +	len = name_len - src_len + dst_len + 1;
  +	lp->ln_name = xmalloc (len);
  +	snprintf (lp->ln_name, len, "%s%s", dst_orig, name + src_len);
  +	lp->ln_next = links;
  +	links = lp;
  +
  +	return 0;
  +}
  +
  +/*
  + * copy_tree - copy files in a directory tree
  + *
  + *	copy_tree() walks a directory tree and copies ordinary files
  + *	as it goes.
  + */
  +
  +int copy_tree (const char *src_root, const char *dst_root, uid_t uid, gid_t gid)
  +{
  +	char src_name[1024];
  +	char dst_name[1024];
  +	char buf[1024];
  +	int ifd;
  +	int ofd;
  +	int err = 0;
  +	int cnt;
  +	int set_orig = 0;
  +	struct DIRECT *ent;
  +	struct stat sb;
  +	struct link_name *lp;
  +	DIR *dir;
  +
  +	/*
  +	 * Make certain both directories exist.  This routine is called
  +	 * after the home directory is created, or recursively after the
  +	 * target is created.  It assumes the target directory exists.
  +	 */
  +
  +	if (access (src_root, F_OK) != 0 || access (dst_root, F_OK) != 0)
  +		return -1;
  +
  +	/*
  +	 * Open the source directory and read each entry.  Every file
  +	 * entry in the directory is copied with the UID and GID set
  +	 * to the provided values.  As an added security feature only
  +	 * regular files (and directories ...) are copied, and no file
  +	 * is made set-ID.
  +	 */
  +
  +	if (!(dir = opendir (src_root)))
  +		return -1;
  +
  +	if (src_orig == 0) {
  +		src_orig = src_root;
  +		dst_orig = dst_root;
  +		set_orig++;
  +	}
  +	while ((ent = readdir (dir))) {
  +
  +		/*
  +		 * Skip the "." and ".." entries
  +		 */
  +
  +		if (strcmp (ent->d_name, ".") == 0 ||
  +		    strcmp (ent->d_name, "..") == 0)
  +			continue;
  +
  +		/*
  +		 * Make the filename for both the source and the
  +		 * destination files.
  +		 */
  +
  +		if (strlen (src_root) + strlen (ent->d_name) + 2 >
  +		    sizeof src_name) {
  +			err++;
  +			break;
  +		}
  +		snprintf (src_name, sizeof src_name, "%s/%s", src_root,
  +			  ent->d_name);
  +
  +		if (strlen (dst_root) + strlen (ent->d_name) + 2 >
  +		    sizeof dst_name) {
  +			err++;
  +			break;
  +		}
  +		snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root,
  +			  ent->d_name);
  +
  +		if (LSTAT (src_name, &sb) == -1)
  +			continue;
  +
  +		if (S_ISDIR (sb.st_mode)) {
  +
  +			/*
  +			 * Create a new target directory, make it owned by
  +			 * the user and then recursively copy that directory.
  +			 */
  +
  +#ifdef WITH_SELINUX
  +			selinux_file_context (dst_name);
  +#endif
  +			if (mkdir (dst_name, sb.st_mode)
  +			    || chown (dst_name,
  +				      uid == (uid_t) - 1 ? sb.st_uid : uid,
  +				      gid == (gid_t) - 1 ? sb.st_gid : gid)
  +			    || chmod (dst_name, sb.st_mode)
  +			    || copy_tree (src_name, dst_name, uid, gid)) {
  +				err++;
  +				break;
  +			}
  +			continue;
  +		}
  +#ifdef	S_IFLNK
  +		/*
  +		 * Copy any symbolic links
  +		 */
  +
  +		if (S_ISLNK (sb.st_mode)) {
  +			char oldlink[1024];
  +			char dummy[1024];
  +			int len;
  +
  +			/*
  +			 * Get the name of the file which the link points
  +			 * to.  If that name begins with the original
  +			 * source directory name, that part of the link
  +			 * name will be replaced with the original
  +			 * destinateion directory name.
  +			 */
  +
  +			if ((len =
  +			     readlink (src_name, oldlink,
  +				       sizeof (oldlink) - 1)) < 0) {
  +				err++;
  +				break;
  +			}
  +			oldlink[len] = '\0';	/* readlink() does not NUL-terminate */
  +			if (!strncmp (oldlink, src_orig, strlen (src_orig))) {
  +				snprintf (dummy, sizeof dummy, "%s%s",
  +					  dst_orig,
  +					  oldlink + strlen (src_orig));
  +				strcpy (oldlink, dummy);
  +			}
  +#ifdef WITH_SELINUX
  +			selinux_file_context (dst_name);
  +#endif
  +			if (symlink (oldlink, dst_name) ||
  +			    lchown (dst_name,
  +				    uid == (uid_t) - 1 ? sb.st_uid : uid,
  +				    gid == (gid_t) - 1 ? sb.st_gid : gid)) {
  +				err++;
  +				break;
  +			}
  +			continue;
  +		}
  +#endif
  +
  +		/*
  +		 * See if this is a previously copied link
  +		 */
  +
  +		if ((lp = check_link (src_name, &sb))) {
  +			if (link (lp->ln_name, dst_name)) {
  +				err++;
  +				break;
  +			}
  +			if (unlink (src_name)) {
  +				err++;
  +				break;
  +			}
  +			if (--lp->ln_count <= 0)
  +				remove_link (lp);
  +
  +			continue;
  +		}
  +
  +		/*
  +		 * Deal with FIFOs and special files.  The user really
  +		 * shouldn't have any of these, but it seems like it
  +		 * would be nice to copy everything ...
  +		 */
  +
  +		if (!S_ISREG (sb.st_mode)) {
  +#ifdef WITH_SELINUX
  +			selinux_file_context (dst_name);
  +#endif
  +			if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev)
  +			    || chown (dst_name,
  +				      uid == (uid_t) - 1 ? sb.st_uid : uid,
  +				      gid == (gid_t) - 1 ? sb.st_gid : gid)
  +			    || chmod (dst_name, sb.st_mode & 07777)) {
  +				err++;
  +				break;
  +			}
  +			continue;
  +		}
  +
  +		/*
  +		 * Create the new file and copy the contents.  The new
  +		 * file will be owned by the provided UID and GID values.
  +		 */
  +
  +		if ((ifd = open (src_name, O_RDONLY)) < 0) {
  +			err++;
  +			break;
  +		}
  +#ifdef WITH_SELINUX
  +		selinux_file_context (dst_name);
  +#endif
  +		if ((ofd =
  +		     open (dst_name, O_WRONLY | O_CREAT | O_TRUNC, 0)) < 0
  +		    || chown (dst_name,
  +			      uid == (uid_t) - 1 ? sb.st_uid : uid,
  +			      gid == (gid_t) - 1 ? sb.st_gid : gid)
  +		    || chmod (dst_name, sb.st_mode & 07777)) {
  +			close (ifd);
  +			err++;
  +			break;
  +		}
  +		while ((cnt = read (ifd, buf, sizeof buf)) > 0) {
  +			if (write (ofd, buf, cnt) != cnt) {
  +				cnt = -1;
  +				break;
  +			}
  +		}
  +		close (ifd);
  +		close (ofd);
  +
  +		if (cnt == -1) {
  +			err++;
  +			break;
  +		}
  +	}
  +	closedir (dir);
  +
  +	if (set_orig) {
  +		src_orig = 0;
  +		dst_orig = 0;
  +	}
  +	return err ? -1 : 0;
  +}
  +
  +/*
  + * remove_tree - remove files in a directory tree
  + *
  + *	remove_tree() walks a directory tree and deletes all the files
  + *	and directories.
  + */
  +
  +int remove_tree (const char *root)
  +{
  +	char new_name[1024];
  +	int err = 0;
  +	struct DIRECT *ent;
  +	struct stat sb;
  +	DIR *dir;
  +
  +	/*
  +	 * Make certain the directory exists.
  +	 */
  +
  +	if (access (root, F_OK) != 0)
  +		return -1;
  +
  +	/*
  +	 * Open the source directory and read each entry.  Every file
  +	 * entry in the directory is copied with the UID and GID set
  +	 * to the provided values.  As an added security feature only
  +	 * regular files (and directories ...) are copied, and no file
  +	 * is made set-ID.
  +	 */
  +
  +	if (!(dir = opendir (root)))
  +		return -1;
  +
  +	while ((ent = readdir (dir))) {
  +
  +		/*
  +		 * Skip the "." and ".." entries
  +		 */
  +
  +		if (strcmp (ent->d_name, ".") == 0 ||
  +		    strcmp (ent->d_name, "..") == 0)
  +			continue;
  +
  +		/*
  +		 * Make the filename for the current entry.
  +		 */
  +
  +		if (strlen (root) + strlen (ent->d_name) + 2 > sizeof new_name) {
  +			err++;
  +			break;
  +		}
  +		snprintf (new_name, sizeof new_name, "%s/%s", root,
  +			  ent->d_name);
  +		if (LSTAT (new_name, &sb) == -1)
  +			continue;
  +
  +		if (S_ISDIR (sb.st_mode)) {
  +
  +			/*
  +			 * Recursively delete this directory.
  +			 */
  +
  +			if (remove_tree (new_name)) {
  +				err++;
  +				break;
  +			}
  +			if (rmdir (new_name)) {
  +				err++;
  +				break;
  +			}
  +			continue;
  +		}
  +		unlink (new_name);
  +	}
  +	closedir (dir);
  +
  +	return err ? -1 : 0;
  +}
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/defines.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 defines.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ defines.h	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,351 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/* $Id: defines.h,v 1.1 2008/08/17 18:31:35 jbj Exp $ */
  +/* some useful defines */
  +
  +#ifndef _DEFINES_H_
  +#define _DEFINES_H_
  +
  +#define ISDIGIT_LOCALE(c) (IN_CTYPE_DOMAIN (c) && isdigit (c))
  +
  +/* Take care of NLS matters.  */
  +
  +#if HAVE_LOCALE_H
  +# include <locale.h>
  +#endif
  +
  +#define gettext_noop(String) (String)
  +/* #define gettext_def(String) "#define String" */
  +
  +#if ENABLE_NLS
  +# include <libintl.h>
  +# define _(Text) gettext (Text)
  +#else
  +# undef bindtextdomain
  +# define bindtextdomain(Domain, Directory)	/* empty */
  +# undef textdomain
  +# define textdomain(Domain)	/* empty */
  +# define _(Text) Text
  +# define ngettext(Msgid1, Msgid2, N) \
  +    ((N) == 1 ? (const char *) (Msgid1) : (const char *) (Msgid2))
  +#endif
  +
  +#if STDC_HEADERS
  +# include <stdlib.h>
  +# include <string.h>
  +#else				/* not STDC_HEADERS */
  +# ifndef HAVE_STRCHR
  +#  define strchr index
  +#  define strrchr rindex
  +# endif
  +char *strchr (), *strrchr (), *strtok ();
  +
  +# ifndef HAVE_MEMCPY
  +#  define memcpy(d, s, n) bcopy((s), (d), (n))
  +# endif
  +#endif				/* not STDC_HEADERS */
  +
  +#if HAVE_ERRNO_H
  +# include <errno.h>
  +#endif
  +
  +#include <sys/stat.h>
  +#include <sys/types.h>
  +#if HAVE_SYS_WAIT_H
  +# include <sys/wait.h>
  +#endif
  +#ifndef WEXITSTATUS
  +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
  +#endif
  +#ifndef WIFEXITED
  +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
  +#endif
  +
  +#if HAVE_UNISTD_H
  +# include <unistd.h>
  +#endif
  +
  +#if TIME_WITH_SYS_TIME
  +# include <sys/time.h>
  +# include <time.h>
  +#else				/* not TIME_WITH_SYS_TIME */
  +# if HAVE_SYS_TIME_H
  +#  include <sys/time.h>
  +# else
  +#  include <time.h>
  +# endif
  +#endif				/* not TIME_WITH_SYS_TIME */
  +
  +#ifdef HAVE_MEMSET
  +# define memzero(ptr, size) memset((void *)(ptr), 0, (size))
  +#else
  +# define memzero(ptr, size) bzero((char *)(ptr), (size))
  +#endif
  +#define strzero(s) memzero(s, strlen(s))	/* warning: evaluates twice */
  +
  +#ifdef HAVE_DIRENT_H		/* DIR_SYSV */
  +# include <dirent.h>
  +# define DIRECT dirent
  +#else
  +# ifdef HAVE_SYS_NDIR_H		/* DIR_XENIX */
  +#  include <sys/ndir.h>
  +# endif
  +# ifdef HAVE_SYS_DIR_H		/* DIR_??? */
  +#  include <sys/dir.h>
  +# endif
  +# ifdef HAVE_NDIR_H		/* DIR_BSD */
  +#  include <ndir.h>
  +# endif
  +# define DIRECT direct
  +#endif
  +
  +/*
  + * Possible cases:
  + * - /usr/include/shadow.h exists and includes the shadow group stuff.
  + * - /usr/include/shadow.h exists, but we use our own gshadow.h.
  + * - /usr/include/shadow.h doesn't exist, use our own shadow.h and gshadow.h.
  + */
  +#if HAVE_SHADOW_H
  +#include <shadow.h>
  +#if defined(SHADOWGRP) && !defined(GSHADOW)
  +#include "gshadow_.h"
  +#endif
  +#else				/* not HAVE_SHADOW_H */
  +#include "shadow_.h"
  +#ifdef SHADOWGRP
  +#include "gshadow_.h"
  +#endif
  +#endif				/* not HAVE_SHADOW_H */
  +
  +#include <limits.h>
  +
  +#ifndef	NGROUPS_MAX
  +#ifdef	NGROUPS
  +#define	NGROUPS_MAX	NGROUPS
  +#else
  +#define	NGROUPS_MAX	64
  +#endif
  +#endif
  +
  +#ifdef USE_SYSLOG
  +#include <syslog.h>
  +
  +#ifndef LOG_WARN
  +#define LOG_WARN LOG_WARNING
  +#endif
  +
  +/* LOG_NOWAIT is deprecated */
  +#ifndef LOG_NOWAIT
  +#define LOG_NOWAIT 0
  +#endif
  +
  +/* LOG_AUTH is deprecated, use LOG_AUTHPRIV instead */
  +#ifndef LOG_AUTHPRIV
  +#define LOG_AUTHPRIV LOG_AUTH
  +#endif
  +
  +/* cleaner than lots of #ifdefs everywhere - use this as follows:
  +   SYSLOG((LOG_CRIT, "user %s cracked root", user)); */
  +#if ENABLE_NLS
  +/* Temporarily set LC_TIME to "C" to avoid strange dates in syslog.
  +   This is a workaround for a more general syslog(d) design problem -
  +   syslogd should log the current system time for each event, and not
  +   trust the formatted time received from the unix domain (or worse,
  +   UDP) socket.  -MM */
  +#define SYSLOG(x)							\
  +	do {								\
  +		char *saved_locale = setlocale(LC_ALL, NULL);		\
  +		if (saved_locale)					\
  +			saved_locale = strdup(saved_locale);		\
  +		if (saved_locale)					\
  +			setlocale(LC_TIME, "C");			\
  +		syslog x ;						\
  +		if (saved_locale) {					\
  +			setlocale(LC_ALL, saved_locale);		\
  +			free(saved_locale);				\
  +		}							\
  +	} while (0)
  +#else				/* !ENABLE_NLS */
  +#define SYSLOG(x) syslog x
  +#endif				/* !ENABLE_NLS */
  +
  +#else				/* !USE_SYSLOG */
  +
  +#define SYSLOG(x)		/* empty */
  +#define openlog(a,b,c)		/* empty */
  +#define closelog()		/* empty */
  +
  +#endif				/* !USE_SYSLOG */
  +
  +/* The default syslog settings can now be changed here,
  +   in just one place.  */
  +
  +#ifndef SYSLOG_OPTIONS
  +/* #define SYSLOG_OPTIONS (LOG_PID | LOG_CONS | LOG_NOWAIT) */
  +#define SYSLOG_OPTIONS (LOG_PID)
  +#endif
  +
  +#ifndef SYSLOG_FACILITY
  +#define SYSLOG_FACILITY LOG_AUTHPRIV
  +#endif
  +
  +#define OPENLOG(progname) openlog(progname, SYSLOG_OPTIONS, SYSLOG_FACILITY)
  +
  +#ifndef F_OK
  +# define F_OK 0
  +# define X_OK 1
  +# define W_OK 2
  +# define R_OK 4
  +#endif
  +
  +#ifndef SEEK_SET
  +# define SEEK_SET 0
  +# define SEEK_CUR 1
  +# define SEEK_END 2
  +#endif
  +
  +#ifdef STAT_MACROS_BROKEN
  +# define S_ISDIR(x) ((x) & S_IFMT) == S_IFDIR)
  +# define S_ISREG(x) ((x) & S_IFMT) == S_IFREG)
  +# ifdef S_IFLNK
  +#  define S_ISLNK(x) ((x) & S_IFMT) == S_IFLNK)
  +# endif
  +#endif
  +
  +#ifndef S_ISLNK
  +#define S_ISLNK(x) (0)
  +#endif
  +
  +#if HAVE_LCHOWN
  +#define LCHOWN lchown
  +#else
  +#define LCHOWN chown
  +#endif
  +
  +#if HAVE_LSTAT
  +#define LSTAT lstat
  +#else
  +#define LSTAT stat
  +#endif
  +
  +#if HAVE_TERMIOS_H
  +# include <termios.h>
  +# define STTY(fd, termio) tcsetattr(fd, TCSANOW, termio)
  +# define GTTY(fd, termio) tcgetattr(fd, termio)
  +# define TERMIO struct termios
  +# define USE_TERMIOS
  +#else				/* assumed HAVE_TERMIO_H */
  +# include <sys/ioctl.h>
  +# include <termio.h>
  +# define STTY(fd, termio) ioctl(fd, TCSETA, termio)
  +# define GTTY(fd, termio) ioctl(fd, TCGETA, termio)
  +# define TEMRIO struct termio
  +# define USE_TERMIO
  +#endif
  +
  +/*
  + * Password aging constants
  + *
  + * DAY - seconds / day
  + * WEEK - seconds / week
  + * SCALE - seconds / aging unit
  + */
  +
  +/* Solaris defines this in shadow.h */
  +#ifndef DAY
  +#define DAY (24L*3600L)
  +#endif
  +
  +#define WEEK (7*DAY)
  +
  +#ifdef ITI_AGING
  +#define SCALE 1
  +#else
  +#define SCALE DAY
  +#endif
  +
  +/* Copy string pointed by B to array A with size checking.  It was originally
  +   in lmain.c but is _very_ useful elsewhere.  Some setuid root programs with
  +   very sloppy coding used to assume that BUFSIZ will always be enough...  */
  +
  +					/* danger - side effects */
  +#define STRFCPY(A,B) \
  +	(strncpy((A), (B), sizeof(A) - 1), (A)[sizeof(A) - 1] = '\0')
  +
  +/* get rid of a few ugly repeated #ifdefs in pwent.c and grent.c */
  +/* XXX - this is ugly too, configure should test it and not check for
  +   any hardcoded system names, if possible.  --marekm */
  +#if defined(AIX) || defined(__linux__)
  +#define SETXXENT_TYPE void
  +#define SETXXENT_RET(x) return
  +#define SETXXENT_TEST(x) x; if (0)	/* compiler should optimize this away */
  +#else
  +#define SETXXENT_TYPE int
  +#define SETXXENT_RET(x) return(x)
  +#define SETXXENT_TEST(x) if (x)
  +#endif
  +
  +#ifndef PASSWD_FILE
  +#define PASSWD_FILE "/etc/passwd"
  +#endif
  +
  +#ifndef GROUP_FILE
  +#define GROUP_FILE "/etc/group"
  +#endif
  +
  +#ifndef SHADOW_FILE
  +#define SHADOW_FILE "/etc/shadow"
  +#endif
  +
  +#ifdef SHADOWGRP
  +#ifndef SGROUP_FILE
  +#define SGROUP_FILE "/etc/gshadow"
  +#endif
  +#endif
  +
  +#define PASSWD_PAG_FILE  PASSWD_FILE ".pag"
  +#define GROUP_PAG_FILE   GROUP_FILE  ".pag"
  +#define SHADOW_PAG_FILE  SHADOW_FILE ".pag"
  +#define SGROUP_PAG_FILE  SGROUP_FILE ".pag"
  +
  +#ifndef NULL
  +#define NULL ((void *) 0)
  +#endif
  +
  +#ifdef sun			/* hacks for compiling on SunOS */
  +# ifndef SOLARIS
  +extern int fputs ();
  +extern char *strdup ();
  +extern char *strerror ();
  +# endif
  +#endif
  +
  +#ifndef HAVE_SNPRINTF
  +#include "snprintf.h"
  +#endif
  +
  +/*
  + * string to use for the pw_passwd field in /etc/passwd when using
  + * shadow passwords - most systems use "x" but there are a few
  + * exceptions, so it can be changed here if necessary.  --marekm
  + */
  +#ifndef SHADOW_PASSWD_STRING
  +#define SHADOW_PASSWD_STRING "x"
  +#endif
  +
  +#ifdef WITH_AUDIT
  +#ifdef __u8			/* in case we use pam < 0.80 */
  +#undef __u8
  +#endif
  +#ifdef __u32
  +#undef __u32
  +#endif
  +
  +#include <libaudit.h>
  +#endif
  +
  +#endif				/* _DEFINES_H_ */
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/faillog.h
  ============================================================================
  $ cvs diff -u -r0 -r1.1 faillog.h
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ faillog.h	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,61 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/*
  + * Copyright 1989 - 1994, Julianne Frances Haugh
  + * All rights reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in the
  + *    documentation and/or other materials provided with the distribution.
  + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
  + *    may be used to endorse or promote products derived from this software
  + *    without specific prior written permission.
  + *
  + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
  + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  + * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + */
  +
  +/*
  + * faillog.h - login failure logging file format
  + *
  + *	$Id: faillog.h,v 1.1 2008/08/17 18:31:35 jbj Exp $
  + *
  + * The login failure file is maintained by login(1) and faillog(8)
  + * Each record in the file represents a separate UID and the file
  + * is indexed in that fashion.
  + */
  +
  +#ifndef _FAILLOG_H
  +#define _FAILLOG_H
  +
  +struct faillog {
  +	short fail_cnt;		/* failures since last success */
  +	short fail_max;		/* failures before turning account off */
  +	char fail_line[12];	/* last failure occured here */
  +	time_t fail_time;	/* last failure occured then */
  +	/*
  +	 * If nonzero, the account will be re-enabled if there are no
  +	 * failures for fail_locktime seconds since last failure.
  +	 */
  +	long fail_locktime;
  +};
  +
  +#endif
  @@ .
  patch -p0 <<'@@ .'
  Index: lua/shadow/fputsx.c
  ============================================================================
  $ cvs diff -u -r0 -r1.1 fputsx.c
  --- /dev/null	2008-08-17 20:31:29 +0200
  +++ fputsx.c	2008-08-17 20:31:36 +0200
  @@ -0,0 +1,84 @@
  +/*
  + * This file was originally distributed as part of
  + * shadow-utils-4.0.17-12.fc6.src.rpm and has been modified
  + * in WRLinux for inclusion in rpm.
  + */
  +
  +/*
  + * Copyright 1990 - 1994, Julianne Frances Haugh
  + * All rights reserved.
  + *
  + * Redistribution and use in source and binary forms, with or without
  + * modification, are permitted provided that the following conditions
  + * are met:
  + * 1. Redistributions of source code must retain the above copyright
  + *    notice, this list of conditions and the following disclaimer.
  + * 2. Redistributions in binary form must reproduce the above copyright
  + *    notice, this list of conditions and the following disclaimer in the
  + *    documentation and/or other materials provided with the distribution.
  + * 3. Neither the name of Julianne F. Haugh nor the names of its contributors
  + *    may be used to endorse or promote products derived from this software
  + *    without specific prior written permission.
  + *
  + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
  + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  + * ARE DISCLAIMED.  IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
  + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  + * SUCH DAMAGE.
  + */
  +
  +#include "config.h"
  +
  +#include <stdio.h>
  +#include "defines.h"
  +
  +#ident "$Id: fputsx.c,v 1.1 2008/08/17 18:31:35 jbj Exp $"
  +
  +
  +char *fgetsx (char *buf, int cnt, FILE * f)
  +{
  +	char *cp = buf;
  +	char *ep;
  +
  +	while (cnt > 0) {
  +		if (fgets (cp, cnt, f) == 0) {
  +			if (cp == buf)
  +				return 0;
  +			else
  +				break;
  +		}
  +		if ((ep =