CFLAGS = @CFLAGS@
YACC = @YACC@
-prefix = /usr/local
+prefix = @prefix@
exec_prefix = $(prefix)
libdir = $(exec_prefix)/lib
SOURCES = getdate.y posixtm.y \
argmatch.c backupfile.c basename.c dirname.c eaccess.c \
error.c filemode.c fsusage.c full-write.c getopt.c getopt1.c \
-getversion.c idcache.c isdir.c makepath.c \
+getversion.c group-member.c idcache.c isdir.c makepath.c \
modechange.c mountlist.c safe-read.c savedir.c \
stripslash.c xgetcwd.c xmalloc.c xstrdup.c userspec.c yesno.c \
fileblocks.c fnmatch.c ftruncate.c mkdir.c mktime.c rename.c stpcpy.c \
-strdup.c strstr.c alloca.c
+strdup.c strstr.c alloca.c long-options.c
OBJECTS = getdate.o posixtm.o \
argmatch.o backupfile.o basename.o dirname.o eaccess.o \
error.o filemode.o full-write.o getopt.o getopt1.o \
-getversion.o idcache.o isdir.o makepath.o \
+getversion.o group-member.o idcache.o isdir.o long-options.o makepath.o \
modechange.o safe-read.o savedir.o \
stripslash.o xgetcwd.o xmalloc.o xstrdup.o userspec.o yesno.o \
@LIBOBJS@ @ALLOCA@
DISTFILES = Makefile.in backupfile.h getopt.h modechange.h \
-fnmatch.h fsusage.h mountlist.h pathmax.h system.h $(SOURCES)
+fnmatch.h fsusage.h mountlist.h pathmax.h $(SOURCES)
all: libfu.a
.c.o:
$(CC) -c $(CPPFLAGS) $(DEFS) -I.. -I$(srcdir) $(CFLAGS) $<
+Makefile: ../config.status Makefile.in
+ CONFIG_FILES=$@ CONFIG_HEADERS= ../config.status
+
install: all
uninstall:
#endif
/* Return the number of TOSIZE-byte blocks used by
- BLOCKS FROMSIZE-byte blocks, rounding away from zero. */
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+ TOSIZE must be positive. Return -1 if FROMSIZE is not positive. */
static long
adjust_blocks (blocks, fromsize, tosize)
long blocks;
int fromsize, tosize;
{
+ if (tosize <= 0)
+ abort ();
+ if (fromsize <= 0)
+ return -1;
+
if (fromsize == tosize) /* E.g., from 512 to 512. */
return blocks;
else if (fromsize > tosize) /* E.g., from 2048 to 512. */
struct statfs fsd;
if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
- return (-1);
-#define convert_blocks(b) adjust_blocks ((b),fsd.f_fsize, 512)
+ return -1;
+#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512)
#endif /* STAT_STATFS3_OSF1 */
#ifdef STAT_STATFS2_FS_DATA /* Ultrix. */
if (statfs (path, &fsd) != 1)
return -1;
-#define convert_blocks(b) adjust_blocks ((b), 1024, 512)
- fsp->fsu_blocks = convert_blocks (fsd.fd_req.btot);
- fsp->fsu_bfree = convert_blocks (fsd.fd_req.bfree);
- fsp->fsu_bavail = convert_blocks (fsd.fd_req.bfreen);
+#define CONVERT_BLOCKS(b) adjust_blocks ((b), 1024, 512)
+ fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot);
+ fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree);
+ fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen);
fsp->fsu_files = fsd.fd_req.gtot;
fsp->fsu_ffree = fsd.fd_req.gfree;
#endif
return -1;
}
close (fd);
-#define convert_blocks(b) adjust_blocks ((b), (fsd.s_type == Fs2b ? 1024 : 512), 512)
- fsp->fsu_blocks = convert_blocks (fsd.s_fsize);
- fsp->fsu_bfree = convert_blocks (fsd.s_tfree);
- fsp->fsu_bavail = convert_blocks (fsd.s_tfree);
+#define CONVERT_BLOCKS(b) adjust_blocks ((b), (fsd.s_type == Fs2b ? 1024 : 512), 512)
+ fsp->fsu_blocks = CONVERT_BLOCKS (fsd.s_fsize);
+ fsp->fsu_bfree = CONVERT_BLOCKS (fsd.s_tfree);
+ fsp->fsu_bavail = CONVERT_BLOCKS (fsd.s_tfree);
fsp->fsu_files = (fsd.s_isize - 2) * INOPB * (fsd.s_type == Fs2b ? 2 : 1);
fsp->fsu_ffree = fsd.s_tinode;
#endif
if (statfs (path, &fsd) < 0)
return -1;
-#define convert_blocks(b) adjust_blocks ((b), fsd.f_bsize, 512)
+#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_bsize, 512)
#endif
#ifdef STAT_STATFS2_FSIZE /* 4.4BSD. */
if (statfs (path, &fsd) < 0)
return -1;
-#define convert_blocks(b) adjust_blocks ((b), fsd.f_fsize, 512)
+#define CONVERT_BLOCKS(b) adjust_blocks ((b), fsd.f_fsize, 512)
#endif
#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix. */
/* Empirically, the block counts on most SVR3 and SVR3-derived
systems seem to always be in terms of 512-byte blocks,
no matter what value f_bsize has. */
-#define convert_blocks(b) (b)
+#define CONVERT_BLOCKS(b) (b)
#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
#ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
#define f_bavail f_bfree
if (statvfs (path, &fsd) < 0)
return -1;
/* f_frsize isn't guaranteed to be supported. */
-#define convert_blocks(b) \
+#define CONVERT_BLOCKS(b) \
adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
#endif
#if !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ) /* !Ultrix && !SVR2. */
- fsp->fsu_blocks = convert_blocks (fsd.f_blocks);
- fsp->fsu_bfree = convert_blocks (fsd.f_bfree);
- fsp->fsu_bavail = convert_blocks (fsd.f_bavail);
+ fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks);
+ fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree);
+ fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail);
fsp->fsu_files = fsd.f_files;
fsp->fsu_ffree = fsd.f_ffree;
#endif
/* full-write.c -- an interface to write that retries after interrupts
- Copyright (C) 1993 Free Software Foundation, Inc.
+ Copyright (C) 1993, 1994 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
umask (umask_value); /* Restore the old value. */
head = NULL;
+#ifdef lint
+ change = NULL;
+#endif
--mode_string;
/* One loop iteration for each "ugoa...=+-rwxXstugo...[=+-rwxXstugo...]". */
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.
+ */
#ifdef HAVE_CONFIG_H
#if defined (CONFIG_BROKETS)
#endif
#endif
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#else
+#ifdef _AIX
+ #pragma alloca
+#else
+char *alloca ();
+#endif
+#endif
+#endif
+
#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#ifdef STDC_HEADERS
#include <stdlib.h>
-#else
-char *malloc ();
#endif
#ifdef HAVE_UNISTD_H
#define endgrent()
#endif
+/* Perform the equivalent of the statement `dest = strdup (src);',
+ but obtaining storage via alloca instead of from the heap. */
+
+#define V_STRDUP(dest, src) \
+ do \
+ { \
+ int _len = strlen ((src)); \
+ (dest) = (char *) alloca (_len + 1); \
+ strcpy (dest, src); \
+ } \
+ while (0)
+
#define isdigit(c) ((c) >= '0' && (c) <= '9')
char *strdup ();
-static int isnumber ();
+
+/* Return nonzero if STR represents an unsigned decimal integer,
+ otherwise return 0. */
+
+static int
+isnumber (str)
+ const char *str;
+{
+ for (; *str; str++)
+ if (!isdigit (*str))
+ return 0;
+ return 1;
+}
/* Extract from NAME, which has the form "[user][:.][group]",
a USERNAME, UID U, GROUPNAME, and GID G.
USERNAME and GROUPNAME will be in newly malloc'd memory.
Either one might be NULL instead, indicating that it was not
given and the corresponding numeric ID was left unchanged.
- Might write NULs into NAME.
Return NULL if successful, a static error message string if not. */
-char *
-parse_user_spec (name, uid, gid, username, groupname)
- char *name;
+const char *
+parse_user_spec (spec_arg, uid, gid, username_arg, groupname_arg)
+ const char *spec_arg;
uid_t *uid;
gid_t *gid;
- char **username, **groupname;
+ char **username_arg, **groupname_arg;
{
- static char *tired = "virtual memory exhausted";
+ static const char *tired = "virtual memory exhausted";
+ const char *error_msg;
+ char *spec; /* A copy we can write on. */
struct passwd *pwd;
struct group *grp;
- char *cp;
- int use_login_group = 0;
+ char *g, *u, *separator;
+ char *groupname;
+
+ error_msg = NULL;
+ *username_arg = *groupname_arg = NULL;
+ groupname = NULL;
+
+ V_STRDUP (spec, spec_arg);
- *username = *groupname = NULL;
+ /* Find the separator if there is one. */
+ separator = index (spec, ':');
+ if (separator == NULL)
+ separator = index (spec, '.');
- /* Check whether a group is given. */
- cp = index (name, ':');
- if (cp == NULL)
- cp = index (name, '.');
- if (cp != NULL)
+ /* Replace separator with a NUL. */
+ if (separator != NULL)
+ *separator = '\0';
+
+ /* Set U and G to non-zero length strings corresponding to user and
+ group specifiers or to NULL. */
+ u = (*spec == '\0' ? NULL : spec);
+
+ g = (separator == NULL || *(separator + 1) == '\0'
+ ? NULL
+ : separator + 1);
+
+ if (u == NULL && g == NULL)
+ return "can not omit both user and group";
+
+ if (u != NULL)
{
- *cp++ = '\0';
- if (*cp == '\0')
+ pwd = getpwnam (u);
+ if (pwd == NULL)
{
- if (cp == name + 1)
- /* Neither user nor group given, just "." or ":". */
- return "can not omit both user and group";
+
+ if (!isnumber (u))
+ error_msg = "invalid user";
else
- /* "user.". */
- use_login_group = 1;
+ {
+ int use_login_group;
+ use_login_group = (separator != NULL && g == NULL);
+ if (use_login_group)
+ error_msg = "cannot get the login group of a numeric UID";
+ else
+ *uid = atoi (u);
+ }
}
else
{
- /* Explicit group. */
- *groupname = strdup (cp);
- if (*groupname == NULL)
- return tired;
- grp = getgrnam (cp);
- if (grp == NULL)
+ *uid = pwd->pw_uid;
+ if (g == NULL && separator != NULL)
{
- if (!isnumber (cp))
- return "invalid group";
- *gid = atoi (cp);
+ /* A separator was given, but a group was not specified,
+ so get the login group. */
+ *gid = pwd->pw_gid;
+ grp = getgrgid (pwd->pw_gid);
+ if (grp == NULL)
+ {
+ /* This is enough room to hold the unsigned decimal
+ representation of any 32-bit quantity and the trailing
+ zero byte. */
+ char uint_buf[21];
+ sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
+ V_STRDUP (groupname, uint_buf);
+ }
+ else
+ {
+ V_STRDUP (groupname, grp->gr_name);
+ }
+ endgrent ();
}
- else
- *gid = grp->gr_gid;
- endgrent (); /* Save a file descriptor. */
}
+ endpwent ();
}
- /* Parse the user name, now that any group has been removed. */
-
- if (name[0] == '\0')
- /* No user name was given, just a group. */
- return NULL;
-
- *username = strdup (name);
- if (*username == NULL)
- return tired;
-
- pwd = getpwnam (name);
- if (pwd == NULL)
+ if (g != NULL && error_msg == NULL)
{
- if (!isnumber (name))
- return "invalid user";
- if (use_login_group)
- return "cannot get the login group of a numeric UID";
- *uid = atoi (name);
+ /* Explicit group. */
+ grp = getgrnam (g);
+ if (grp == NULL)
+ {
+ if (!isnumber (g))
+ error_msg = "invalid group";
+ else
+ *gid = atoi (g);
+ }
+ else
+ *gid = grp->gr_gid;
+ endgrent (); /* Save a file descriptor. */
+
+ if (error_msg == NULL)
+ V_STRDUP (groupname, g);
}
- else
+
+ if (error_msg == NULL)
{
- *uid = pwd->pw_uid;
- if (use_login_group)
+ if (u != NULL)
{
- *gid = pwd->pw_gid;
- grp = getgrgid (pwd->pw_gid);
- if (grp == NULL)
- {
- *groupname = malloc (15);
- if (*groupname == NULL)
- return tired;
- sprintf (*groupname, "%u", (unsigned) (pwd->pw_gid));
- }
- else
+ *username_arg = strdup (u);
+ if (*username_arg == NULL)
+ error_msg = tired;
+ }
+
+ if (groupname != NULL && error_msg == NULL)
+ {
+ *groupname_arg = strdup (groupname);
+ if (*groupname_arg == NULL)
{
- *groupname = strdup (grp->gr_name);
- if (*groupname == NULL)
- return tired;
+ if (*username_arg != NULL)
+ {
+ free (*username_arg);
+ *username_arg = NULL;
+ }
+ error_msg = tired;
}
- endgrent ();
}
}
- endpwent ();
- return NULL;
+
+ return error_msg;
}
-/* Return nonzero if STR represents an unsigned decimal integer,
- otherwise return 0. */
+#ifdef TEST
-static int
-isnumber (str)
- char *str;
+#define NULL_CHECK(s) ((s) == NULL ? "(null)" : (s))
+
+int
+main (int argc, char **argv)
{
- for (; *str; str++)
- if (!isdigit (*str))
- return 0;
- return 1;
+ int i;
+
+ for (i = 1; i < argc; i++)
+ {
+ const char *e;
+ char *username, *groupname;
+ uid_t uid;
+ gid_t gid;
+ char *tmp;
+
+ tmp = strdup (argv[i]);
+ e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
+ free (tmp);
+ printf ("%s: %u %u %s %s %s\n",
+ argv[i],
+ (unsigned int) uid,
+ (unsigned int) gid,
+ NULL_CHECK (username),
+ NULL_CHECK (groupname),
+ NULL_CHECK (e));
+ }
+
+ exit (0);
}
+
+#endif