* Parse the argument to the -R or --owner flag.
*
* The format is one of the following:
- * <user> - Override user but not group
- * <user>: - Override both, group is user's default group
- * <user>:<group> - Override both
- * :<group> - Override group but not user
+ * <username|uid> - Override user but not group
+ * <username>: - Override both, group is user's default group
+ * <uid>: - Override user but not group
+ * <username|uid>:<groupname|gid> - Override both
+ * :<groupname|gid> - Override group but not user
+ *
+ * Where uid/gid are decimal representations and groupname/username
+ * are names to be looked up in system database. Note that
+ * uid/gid parsing takes priority over username/groupname lookup,
+ * so this won't do a lookup for usernames or group names that
+ * consist entirely of digits.
*
* A period can be used instead of the colon.
*
- * Sets uid/gid as appropriate, -1 indicates uid/gid not specified.
+ * Sets uid/gid return as appropriate, -1 indicates uid/gid not specified.
*
*/
+static int
+decimal_parse(const char *p)
+{
+ /* TODO: guard against overflow. */
+ int n = 0;
+ for (; *p != '\0'; ++p) {
+ if (*p < '0' || *p > '9')
+ return (-1);
+ n = n * 10 + *p - '0';
+ }
+ return (n);
+}
+
int
owner_parse(const char *spec, int *uid, int *gid)
{
}
memcpy(user, u, ue - u);
user[ue - u] = '\0';
- pwent = getpwnam(user);
- if (pwent == NULL) {
- lafe_warnc(errno, "Couldn't lookup user ``%s''", user);
- return (1);
+ *uid = decimal_parse(user);
+ if (*uid < 0) {
+ /* Couldn't parse as integer, try username lookup. */
+ pwent = getpwnam(user);
+ if (pwent == NULL) {
+ lafe_warnc(errno,
+ "Couldn't lookup user ``%s''", user);
+ return (1);
+ }
+ *uid = pwent->pw_uid;
+ if (*ue != '\0' && *g == '\0')
+ *gid = pwent->pw_gid;
}
free(user);
- *uid = pwent->pw_uid;
- if (*ue != '\0' && *g == '\0')
- *gid = pwent->pw_gid;
}
if (*g != '\0') {
- struct group *grp;
- grp = getgrnam(g);
- if (grp != NULL)
- *gid = grp->gr_gid;
- else {
- lafe_warnc(errno, "Couldn't look up group ``%s''", g);
- return (1);
+ *gid = decimal_parse(g);
+ if (*gid < 0) {
+ /* Couldn't parse int, try group name lookup. */
+ struct group *grp;
+ grp = getgrnam(g);
+ if (grp != NULL)
+ *gid = grp->gr_gid;
+ else {
+ lafe_warnc(errno,
+ "Couldn't look up group ``%s''", g);
+ return (1);
+ }
}
}
return (0);
/*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2009 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* Use CreateWellKnownSID() and LookupAccountName()?
*/
#define ROOT "Administrator"
-#define ROOT_UID 500
-#define ROOT_GID1 513
-#define ROOT_GID2 545
-#define ROOT_GID3 544
+static int root_uids[] = { 500 };
+static int root_gids[] = { 513, 545, 544 };
#else
#define ROOT "root"
-#define ROOT_UID 0
-#define ROOT_GID 0
+static int root_uids[] = { 0 };
+static int root_gids[] = { 0 };
#endif
+static int
+int_in_list(int i, int *l, size_t n)
+{
+ while (n-- > 0)
+ if (*l++ == i)
+ return (1);
+ return (0);
+}
+
DEFINE_TEST(test_owner_parse)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
#else
int uid, gid;
- lafe_progname = "Ignore this message";
+ lafe_progname = "cpio";
assertEqualInt(0, owner_parse(ROOT, &uid, &gid));
- assertEqualInt(ROOT_UID, uid);
+ assert(int_in_list(uid, root_uids,
+ sizeof(root_uids)/sizeof(root_uids[0])));
assertEqualInt(-1, gid);
assertEqualInt(0, owner_parse(ROOT ":", &uid, &gid));
- assertEqualInt(ROOT_UID, uid);
-#if defined(__CYGWIN__)
- {
- int gidIsOneOf = (ROOT_GID1 == gid)
- || (ROOT_GID2 == gid)
- || (ROOT_GID3 == gid);
- assertEqualInt(1, gidIsOneOf);
- }
-#else
- assertEqualInt(ROOT_GID, gid);
-#endif
+ assert(int_in_list(uid, root_uids,
+ sizeof(root_uids)/sizeof(root_uids[0])));
+ assert(int_in_list(gid, root_gids,
+ sizeof(root_gids)/sizeof(root_gids[0])));
assertEqualInt(0, owner_parse(ROOT ".", &uid, &gid));
- assertEqualInt(ROOT_UID, uid);
-#if defined(__CYGWIN__)
- {
- int gidIsOneOf = (ROOT_GID1 == gid)
- || (ROOT_GID2 == gid)
- || (ROOT_GID3 == gid);
- assertEqualInt(1, gidIsOneOf);
- }
-#else
- assertEqualInt(ROOT_GID, gid);
-#endif
+ assert(int_in_list(uid, root_uids,
+ sizeof(root_uids)/sizeof(root_uids[0])));
+ assert(int_in_list(gid, root_gids,
+ sizeof(root_gids)/sizeof(root_gids[0])));
+
+ assertEqualInt(0, owner_parse("111", &uid, &gid));
+ assertEqualInt(111, uid);
+ assertEqualInt(-1, gid);
+
+ assertEqualInt(0, owner_parse("112:", &uid, &gid));
+ assertEqualInt(112, uid);
+ /* Can't assert gid, since we don't know gid for user #112. */
+
+ assertEqualInt(0, owner_parse("113.", &uid, &gid));
+ assertEqualInt(113, uid);
+ /* Can't assert gid, since we don't know gid for user #113. */
+
+ assertEqualInt(0, owner_parse(":114", &uid, &gid));
+ assertEqualInt(-1, uid);
+ assertEqualInt(114, gid);
+
+ assertEqualInt(0, owner_parse(".115", &uid, &gid));
+ assertEqualInt(-1, uid);
+ assertEqualInt(115, gid);
+
+ assertEqualInt(0, owner_parse("116:117", &uid, &gid));
+ assertEqualInt(116, uid);
+ assertEqualInt(117, gid);
/*
* TODO: Lookup current user/group name, build strings and
* Alternatively, redirect stderr temporarily to suppress the output.
*/
+ lafe_progname = "Ignore this message";
assertEqualInt(1, owner_parse(":nonexistentgroup", &uid, &gid));
assertEqualInt(1, owner_parse(ROOT ":nonexistentgroup", &uid, &gid));
assertEqualInt(1,