/* userspec.c -- Parse a user and group string.
- Copyright (C) 1989, 1990, 1991, 1992, 1997, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1989-1992, 1997, 1998, 2000 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
# include <unistd.h>
#endif
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
+#endif
+#define N_(Text) Text
+
#ifndef _POSIX_VERSION
struct passwd *getpwnam ();
struct group *getgrnam ();
} \
while (0)
-#define isdigit(c) ((c) >= '0' && (c) <= '9')
+/* ISDIGIT differs from isdigit, as follows:
+ - Its arg may be any int or unsigned int; it need not be an unsigned char.
+ - It's guaranteed to evaluate its argument exactly once.
+ - It's typically faster.
+ Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+ only '0' through '9' are digits. Prefer ISDIGIT to isdigit unless
+ it's important to use the locale's definition of `digit' even when the
+ host does not conform to Posix. */
+#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
#ifndef strdup
char *strdup ();
is_number (const char *str)
{
for (; *str; str++)
- if (!isdigit (*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.
Either user or group, or both, must be present.
- If the group is omitted but the ":" or "." separator is given,
+ If the group is omitted but the ":" separator is given,
use the given user's login group.
+ If SPEC_ARG contains a `:', then use that as the separator, ignoring
+ any `.'s. If there is no `:', but there is a `.', then first look
+ up SPEC_ARG as a login name. If that look-up fails, then try again
+ interpreting the `.' as a separator.
USERNAME and GROUPNAME will be in newly malloc'd memory.
Either one might be NULL instead, indicating that it was not
Return NULL if successful, a static error message string if not. */
const char *
-parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid, char **username_arg, char **groupname_arg)
+parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
+ char **username_arg, char **groupname_arg)
{
- static const char *tired = "virtual memory exhausted";
+ static const char *E_no_memory = N_("virtual memory exhausted");
+ static const char *E_invalid_user = N_("invalid user");
+ static const char *E_invalid_group = N_("invalid group");
+ static const char *E_bad_spec =
+ N_("cannot get the login group of a numeric UID");
+ static const char *E_cannot_omit_both =
+ N_("cannot omit both user and group");
+
const char *error_msg;
char *spec; /* A copy we can write on. */
struct passwd *pwd;
struct group *grp;
char *g, *u, *separator;
char *groupname;
+ int maybe_retry = 0;
+ char *dot = NULL;
error_msg = NULL;
*username_arg = *groupname_arg = NULL;
V_STRDUP (spec, spec_arg);
- /* Find the separator if there is one. */
+ /* Find the POSIX `:' separator if there is one. */
separator = strchr (spec, ':');
+
+ /* If there is no colon, then see if there's a `.'. */
if (separator == NULL)
- separator = strchr (spec, '.');
+ {
+ dot = strchr (spec, '.');
+ /* If there's no colon but there is a `.', then first look up the
+ whole spec, in case it's an OWNER name that includes a dot.
+ If that fails, then we'll try again, but interpreting the `.'
+ as a separator. */
+ /* FIXME: accepting `.' as the separator is contrary to POSIX.
+ someday we should drop support for this. */
+ if (dot)
+ maybe_retry = 1;
+ }
+
+ retry:
/* Replace separator with a NUL. */
if (separator != NULL)
: separator + 1);
if (u == NULL && g == NULL)
- return "can not omit both user and group";
+ return _(E_cannot_omit_both);
#ifdef __DJGPP__
/* Pretend that we are the user U whose group is G. This makes
{
if (!is_number (u))
- error_msg = "invalid user";
+ error_msg = _(E_invalid_user);
else
{
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";
+ error_msg = _(E_bad_spec);
else
- *uid = atoi (u);
+ {
+ /* FIXME: don't use atoi! */
+ *uid = atoi (u);
+ }
}
}
else
if (grp == NULL)
{
if (!is_number (g))
- error_msg = "invalid group";
+ error_msg = _(E_invalid_group);
else
- *gid = atoi (g);
+ {
+ /* FIXME: don't use atoi! */
+ *gid = atoi (g);
+ }
}
else
*gid = grp->gr_gid;
{
*username_arg = strdup (u);
if (*username_arg == NULL)
- error_msg = tired;
+ error_msg = _(E_no_memory);
}
if (groupname != NULL && error_msg == NULL)
free (*username_arg);
*username_arg = NULL;
}
- error_msg = tired;
+ error_msg = _(E_no_memory);
}
}
}
+ if (error_msg && maybe_retry)
+ {
+ maybe_retry = 0;
+ separator = dot;
+ error_msg = NULL;
+ goto retry;
+ }
+
return error_msg;
}