diff options
author | Elliott Hughes <enh@google.com> | 2014-02-28 16:48:49 -0800 |
---|---|---|
committer | Elliott Hughes <enh@google.com> | 2014-02-28 16:48:49 -0800 |
commit | 0b024677ec64ebbf298de810929292a693436ad6 (patch) | |
tree | c3381222053daf5cb43d16907e9f3230a6a4189b /toolbox | |
parent | 1a1c42fda7ec6087355529337573dd3ec5e85d91 (diff) | |
download | system_core-0b024677ec64ebbf298de810929292a693436ad6.zip system_core-0b024677ec64ebbf298de810929292a693436ad6.tar.gz system_core-0b024677ec64ebbf298de810929292a693436ad6.tar.bz2 |
Switch to BSD chown (for -R, primarily).
Change-Id: I45381b8a04f4cb651123a2d43860418e06df6e65
Diffstat (limited to 'toolbox')
-rw-r--r-- | toolbox/Android.mk | 16 | ||||
-rw-r--r-- | toolbox/chown.c | 359 | ||||
-rw-r--r-- | toolbox/uid_from_user.c | 48 |
3 files changed, 354 insertions, 69 deletions
diff --git a/toolbox/Android.mk b/toolbox/Android.mk index 4fff9f5..682ce59 100644 --- a/toolbox/Android.mk +++ b/toolbox/Android.mk @@ -80,15 +80,23 @@ ALL_TOOLS += \ grep LOCAL_SRC_FILES := \ + cp/cp.c \ + cp/utils.c \ dynarray.c \ - toolbox.c \ + grep/fastgrep.c \ + grep/file.c \ + grep/grep.c \ + grep/queue.c \ + grep/util.c \ $(patsubst %,%.c,$(TOOLS)) \ - cp/cp.c cp/utils.c \ - grep/grep.c grep/fastgrep.c grep/file.c grep/queue.c grep/util.c + toolbox.c \ + uid_from_user.c \ LOCAL_C_INCLUDES := bionic/libc/bionic -LOCAL_CFLAGS += -Wno-unused-parameter +LOCAL_CFLAGS += \ + -Wno-unused-parameter \ + -DSUPPORT_DOT \ LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/toolbox/chown.c b/toolbox/chown.c index 92efee6..6ac2233 100644 --- a/toolbox/chown.c +++ b/toolbox/chown.c @@ -1,73 +1,302 @@ -#include <stdio.h> -#include <stdlib.h> -#include <string.h> +/* $NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $ */ + +/* + * Copyright (c) 1988, 1993, 1994, 2003 + * The Regents of the University of California. 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 the University 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 THE REGENTS 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 THE REGENTS 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 <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994, 2003\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)chown.c 8.8 (Berkeley) 4/4/94"; +#else +__RCSID("$NetBSD: chown.c,v 1.8 2012/10/24 01:12:51 enami Exp $"); +#endif +#endif /* not lint */ + #include <sys/types.h> +#include <sys/stat.h> + +#include <ctype.h> #include <dirent.h> +#include <err.h> #include <errno.h> -#include <pwd.h> +#include <locale.h> +#include <fts.h> #include <grp.h> - +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> #include <unistd.h> -#include <time.h> +#include <getopt.h> + +static void a_gid(const char *); +static void a_uid(const char *); +static id_t id(const char *, const char *); +__dead static void usage(void); + +static uid_t uid; +static gid_t gid; +static int ischown; +static const char *myname; + +struct option chown_longopts[] = { + { "reference", required_argument, 0, + 1 }, + { NULL, 0, 0, + 0 }, +}; -int chown_main(int argc, char **argv) +int +chown_main(int argc, char **argv) { - int i; - - if (argc < 3) { - fprintf(stderr, "Usage: chown <USER>[:GROUP] <FILE1> [FILE2] ...\n"); - return 10; - } - - // Copy argv[1] to 'user' so we can truncate it at the period - // if a group id specified. - char user[32]; - char *group = NULL; - strncpy(user, argv[1], sizeof(user)); - if ((group = strchr(user, ':')) != NULL) { - *group++ = '\0'; - } else if ((group = strchr(user, '.')) != NULL) { - *group++ = '\0'; - } - - // Lookup uid (and gid if specified) - struct passwd *pw; - struct group *grp = NULL; - uid_t uid; - gid_t gid = -1; // passing -1 to chown preserves current group - - pw = getpwnam(user); - if (pw != NULL) { - uid = pw->pw_uid; - } else { - char* endptr; - uid = (int) strtoul(user, &endptr, 0); - if (endptr == user) { // no conversion - fprintf(stderr, "No such user '%s'\n", user); - return 10; - } - } - - if (group != NULL) { - grp = getgrnam(group); - if (grp != NULL) { - gid = grp->gr_gid; - } else { - char* endptr; - gid = (int) strtoul(group, &endptr, 0); - if (endptr == group) { // no conversion - fprintf(stderr, "No such group '%s'\n", group); - return 10; - } - } - } - - for (i = 2; i < argc; i++) { - if (chown(argv[i], uid, gid) < 0) { - fprintf(stderr, "Unable to chown %s: %s\n", argv[i], strerror(errno)); - return 10; - } - } - - return 0; + FTS *ftsp; + FTSENT *p; + int Hflag, Lflag, Rflag, ch, fflag, fts_options, hflag, rval, vflag; + char *cp, *reference; + int (*change_owner)(const char *, uid_t, gid_t); + + setprogname(*argv); + + (void)setlocale(LC_ALL, ""); + + myname = getprogname(); + ischown = (myname[2] == 'o'); + reference = NULL; + + Hflag = Lflag = Rflag = fflag = hflag = vflag = 0; + while ((ch = getopt_long(argc, argv, "HLPRfhv", + chown_longopts, NULL)) != -1) + switch (ch) { + case 1: + reference = optarg; + break; + case 'H': + Hflag = 1; + Lflag = 0; + break; + case 'L': + Lflag = 1; + Hflag = 0; + break; + case 'P': + Hflag = Lflag = 0; + break; + case 'R': + Rflag = 1; + break; + case 'f': + fflag = 1; + break; + case 'h': + /* + * In System V the -h option causes chown/chgrp to + * change the owner/group of the symbolic link. + * 4.4BSD's symbolic links didn't have owners/groups, + * so it was an undocumented noop. + * In NetBSD 1.3, lchown(2) is introduced. + */ + hflag = 1; + break; + case 'v': + vflag = 1; + break; + case '?': + default: + usage(); + } + argv += optind; + argc -= optind; + + if (argc == 0 || (argc == 1 && reference == NULL)) + usage(); + + fts_options = FTS_PHYSICAL; + if (Rflag) { + if (Hflag) + fts_options |= FTS_COMFOLLOW; + if (Lflag) { + if (hflag) + errx(EXIT_FAILURE, + "the -L and -h options " + "may not be specified together."); + fts_options &= ~FTS_PHYSICAL; + fts_options |= FTS_LOGICAL; + } + } else if (!hflag) + fts_options |= FTS_COMFOLLOW; + + uid = (uid_t)-1; + gid = (gid_t)-1; + if (reference == NULL) { + if (ischown) { + if ((cp = strchr(*argv, ':')) != NULL) { + *cp++ = '\0'; + a_gid(cp); + } +#ifdef SUPPORT_DOT + else if ((cp = strrchr(*argv, '.')) != NULL) { + if (uid_from_user(*argv, &uid) == -1) { + *cp++ = '\0'; + a_gid(cp); + } + } +#endif + a_uid(*argv); + } else + a_gid(*argv); + argv++; + } else { + struct stat st; + + if (stat(reference, &st) == -1) + err(EXIT_FAILURE, "Cannot stat `%s'", reference); + if (ischown) + uid = st.st_uid; + gid = st.st_gid; + } + + if ((ftsp = fts_open(argv, fts_options, NULL)) == NULL) + err(EXIT_FAILURE, "fts_open"); + + for (rval = EXIT_SUCCESS; (p = fts_read(ftsp)) != NULL;) { + change_owner = chown; + switch (p->fts_info) { + case FTS_D: + if (!Rflag) /* Change it at FTS_DP. */ + fts_set(ftsp, p, FTS_SKIP); + continue; + case FTS_DNR: /* Warn, chown, continue. */ + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = EXIT_FAILURE; + break; + case FTS_ERR: /* Warn, continue. */ + case FTS_NS: + warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); + rval = EXIT_FAILURE; + continue; + case FTS_SL: /* Ignore unless -h. */ + /* + * All symlinks we found while doing a physical + * walk end up here. + */ + if (!hflag) + continue; + /* + * Note that if we follow a symlink, fts_info is + * not FTS_SL but FTS_F or whatever. And we should + * use lchown only for FTS_SL and should use chown + * for others. + */ + change_owner = lchown; + break; + case FTS_SLNONE: /* Ignore. */ + /* + * The only symlinks that end up here are ones that + * don't point to anything. Note that if we are + * doing a phisycal walk, we never reach here unless + * we asked to follow explicitly. + */ + continue; + default: + break; + } + + if ((*change_owner)(p->fts_accpath, uid, gid) && !fflag) { + warn("%s", p->fts_path); + rval = EXIT_FAILURE; + } else { + if (vflag) + printf("%s\n", p->fts_path); + } + } + if (errno) + err(EXIT_FAILURE, "fts_read"); + exit(rval); + /* NOTREACHED */ +} + +static void +a_gid(const char *s) +{ + struct group *gr; + + if (*s == '\0') /* Argument was "uid[:.]". */ + return; + gr = *s == '#' ? NULL : getgrnam(s); + if (gr == NULL) + gid = id(s, "group"); + else + gid = gr->gr_gid; + return; +} + +static void +a_uid(const char *s) +{ + if (*s == '\0') /* Argument was "[:.]gid". */ + return; + if (*s == '#' || uid_from_user(s, &uid) == -1) { + uid = id(s, "user"); + } + return; +} + +static id_t +id(const char *name, const char *type) +{ + id_t val; + char *ep; + + errno = 0; + if (*name == '#') + name++; + val = (id_t)strtoul(name, &ep, 10); + if (errno) + err(EXIT_FAILURE, "%s", name); + if (*ep != '\0') + errx(EXIT_FAILURE, "%s: invalid %s name", name, type); + return (val); +} + +static void +usage(void) +{ + + (void)fprintf(stderr, + "Usage: %s [-R [-H | -L | -P]] [-fhv] %s file ...\n" + "\t%s [-R [-H | -L | -P]] [-fhv] --reference=rfile file ...\n", + myname, ischown ? "owner:group|owner|:group" : "group", + myname); + exit(EXIT_FAILURE); } diff --git a/toolbox/uid_from_user.c b/toolbox/uid_from_user.c new file mode 100644 index 0000000..d70f410 --- /dev/null +++ b/toolbox/uid_from_user.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014, The Android Open Source Project + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 THE + * COPYRIGHT OWNER 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 <limits.h> +#include <pwd.h> +#include <stdlib.h> +#include <sys/types.h> + +int uid_from_user(const char* name, uid_t* uid) { + struct passwd* pw = getpwnam(name); + if (pw != NULL) { + *uid = pw->pw_uid; + return 0; + } + // Try to parse as an integer. + char* end_ptr; + unsigned long number = strtoul(name, &end_ptr, 0); + if (end_ptr == name || *end_ptr != '\0' || number > INT_MAX) { + return -1; + } + *uid = (int) number; + return 0; +} |