Home | History | Annotate | Line # | Download | only in cpio
cmdline.c revision 1.1
      1  1.1  joerg /*-
      2  1.1  joerg  * Copyright (c) 2003-2007 Tim Kientzle
      3  1.1  joerg  * All rights reserved.
      4  1.1  joerg  *
      5  1.1  joerg  * Redistribution and use in source and binary forms, with or without
      6  1.1  joerg  * modification, are permitted provided that the following conditions
      7  1.1  joerg  * are met:
      8  1.1  joerg  * 1. Redistributions of source code must retain the above copyright
      9  1.1  joerg  *    notice, this list of conditions and the following disclaimer
     10  1.1  joerg  *    in this position and unchanged.
     11  1.1  joerg  * 2. Redistributions in binary form must reproduce the above copyright
     12  1.1  joerg  *    notice, this list of conditions and the following disclaimer in the
     13  1.1  joerg  *    documentation and/or other materials provided with the distribution.
     14  1.1  joerg  *
     15  1.1  joerg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
     16  1.1  joerg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  1.1  joerg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  1.1  joerg  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  1.1  joerg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  1.1  joerg  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  1.1  joerg  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  1.1  joerg  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  1.1  joerg  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  1.1  joerg  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  1.1  joerg  */
     26  1.1  joerg 
     27  1.1  joerg 
     28  1.1  joerg #include "cpio_platform.h"
     29  1.1  joerg __FBSDID("$FreeBSD: src/usr.bin/cpio/cmdline.c,v 1.3 2008/06/21 02:20:20 kientzle Exp $");
     30  1.1  joerg 
     31  1.1  joerg #ifdef HAVE_ERRNO_H
     32  1.1  joerg #include <errno.h>
     33  1.1  joerg #endif
     34  1.1  joerg #ifdef HAVE_GETOPT_LONG
     35  1.1  joerg #include <getopt.h>
     36  1.1  joerg #else
     37  1.1  joerg struct option {
     38  1.1  joerg 	const char *name;
     39  1.1  joerg 	int has_arg;
     40  1.1  joerg 	int *flag;
     41  1.1  joerg 	int val;
     42  1.1  joerg };
     43  1.1  joerg #define	no_argument 0
     44  1.1  joerg #define	required_argument 1
     45  1.1  joerg #endif
     46  1.1  joerg #ifdef HAVE_GRP_H
     47  1.1  joerg #include <grp.h>
     48  1.1  joerg #endif
     49  1.1  joerg #ifdef HAVE_PWD_H
     50  1.1  joerg #include <pwd.h>
     51  1.1  joerg #endif
     52  1.1  joerg #include <stdio.h>
     53  1.1  joerg #ifdef HAVE_STDLIB_H
     54  1.1  joerg #include <stdlib.h>
     55  1.1  joerg #endif
     56  1.1  joerg #ifdef HAVE_STRING_H
     57  1.1  joerg #include <string.h>
     58  1.1  joerg #endif
     59  1.1  joerg 
     60  1.1  joerg #include "cpio.h"
     61  1.1  joerg 
     62  1.1  joerg /*
     63  1.1  joerg  *
     64  1.1  joerg  * Option parsing routines for bsdcpio.
     65  1.1  joerg  *
     66  1.1  joerg  */
     67  1.1  joerg 
     68  1.1  joerg 
     69  1.1  joerg static const char *cpio_opts = "0AaBC:F:O:cdE:f:H:hijLlmopR:rtuvW:yZz";
     70  1.1  joerg 
     71  1.1  joerg /*
     72  1.1  joerg  * On systems that lack getopt_long, long options can be specified
     73  1.1  joerg  * using -W longopt and -W longopt=value, e.g. "-W version" is the
     74  1.1  joerg  * same as "--version" and "-W format=ustar" is the same as "--format
     75  1.1  joerg  * ustar".  This does not rely the GNU getopt() "W;" extension, so
     76  1.1  joerg  * should work correctly on any system with a POSIX-compliant
     77  1.1  joerg  * getopt().
     78  1.1  joerg  */
     79  1.1  joerg 
     80  1.1  joerg /*
     81  1.1  joerg  * If you add anything, be very careful to keep this list properly
     82  1.1  joerg  * sorted, as the -W logic below relies on it.
     83  1.1  joerg  */
     84  1.1  joerg static const struct option cpio_longopts[] = {
     85  1.1  joerg 	{ "create",		no_argument,	   NULL, 'o' },
     86  1.1  joerg 	{ "extract",		no_argument,       NULL, 'i' },
     87  1.1  joerg 	{ "file",		required_argument, NULL, 'F' },
     88  1.1  joerg 	{ "format",             required_argument, NULL, 'H' },
     89  1.1  joerg 	{ "help",		no_argument,	   NULL, 'h' },
     90  1.1  joerg 	{ "insecure",		no_argument,	   NULL, OPTION_INSECURE },
     91  1.1  joerg 	{ "link",		no_argument,	   NULL, 'l' },
     92  1.1  joerg 	{ "list",		no_argument,	   NULL, 't' },
     93  1.1  joerg 	{ "make-directories",	no_argument,	   NULL, 'd' },
     94  1.1  joerg 	{ "null",		no_argument,	   NULL, '0' },
     95  1.1  joerg 	{ "owner",		required_argument, NULL, 'R' },
     96  1.1  joerg 	{ "pass-through",	no_argument,	   NULL, 'p' },
     97  1.1  joerg 	{ "preserve-modification-time", no_argument, NULL, 'm' },
     98  1.1  joerg 	{ "quiet",		no_argument,	   NULL, OPTION_QUIET },
     99  1.1  joerg 	{ "unconditional",	no_argument,	   NULL, 'u' },
    100  1.1  joerg 	{ "verbose",            no_argument,       NULL, 'v' },
    101  1.1  joerg 	{ "version",            no_argument,       NULL, OPTION_VERSION },
    102  1.1  joerg 	{ NULL, 0, NULL, 0 }
    103  1.1  joerg };
    104  1.1  joerg 
    105  1.1  joerg /*
    106  1.1  joerg  * Parse command-line options using system-provided getopt() or getopt_long().
    107  1.1  joerg  * If option is -W, then parse argument as a long option.
    108  1.1  joerg  */
    109  1.1  joerg int
    110  1.1  joerg cpio_getopt(struct cpio *cpio)
    111  1.1  joerg {
    112  1.1  joerg 	char *p, *q;
    113  1.1  joerg 	const struct option *option, *option2;
    114  1.1  joerg 	int opt;
    115  1.1  joerg 	int option_index;
    116  1.1  joerg 	size_t option_length;
    117  1.1  joerg 
    118  1.1  joerg 	option_index = -1;
    119  1.1  joerg 
    120  1.1  joerg #ifdef HAVE_GETOPT_LONG
    121  1.1  joerg 	opt = getopt_long(cpio->argc, cpio->argv, cpio_opts,
    122  1.1  joerg 	    cpio_longopts, &option_index);
    123  1.1  joerg #else
    124  1.1  joerg 	opt = getopt(cpio->argc, cpio->argv, cpio_opts);
    125  1.1  joerg #endif
    126  1.1  joerg 
    127  1.1  joerg 	/* Support long options through -W longopt=value */
    128  1.1  joerg 	if (opt == 'W') {
    129  1.1  joerg 		p = optarg;
    130  1.1  joerg 		q = strchr(optarg, '=');
    131  1.1  joerg 		if (q != NULL) {
    132  1.1  joerg 			option_length = (size_t)(q - p);
    133  1.1  joerg 			optarg = q + 1;
    134  1.1  joerg 		} else {
    135  1.1  joerg 			option_length = strlen(p);
    136  1.1  joerg 			optarg = NULL;
    137  1.1  joerg 		}
    138  1.1  joerg 		option = cpio_longopts;
    139  1.1  joerg 		while (option->name != NULL &&
    140  1.1  joerg 		    (strlen(option->name) < option_length ||
    141  1.1  joerg 		    strncmp(p, option->name, option_length) != 0 )) {
    142  1.1  joerg 			option++;
    143  1.1  joerg 		}
    144  1.1  joerg 
    145  1.1  joerg 		if (option->name != NULL) {
    146  1.1  joerg 			option2 = option;
    147  1.1  joerg 			opt = option->val;
    148  1.1  joerg 
    149  1.1  joerg 			/* If the first match was exact, we're done. */
    150  1.1  joerg 			if (strncmp(p, option->name, strlen(option->name)) == 0) {
    151  1.1  joerg 				while (option->name != NULL)
    152  1.1  joerg 					option++;
    153  1.1  joerg 			} else {
    154  1.1  joerg 				/* Check if there's another match. */
    155  1.1  joerg 				option++;
    156  1.1  joerg 				while (option->name != NULL &&
    157  1.1  joerg 				    (strlen(option->name) < option_length ||
    158  1.1  joerg 				    strncmp(p, option->name, option_length) != 0)) {
    159  1.1  joerg 					option++;
    160  1.1  joerg 				}
    161  1.1  joerg 			}
    162  1.1  joerg 			if (option->name != NULL)
    163  1.1  joerg 				cpio_errc(1, 0,
    164  1.1  joerg 				    "Ambiguous option %s "
    165  1.1  joerg 				    "(matches both %s and %s)",
    166  1.1  joerg 				    p, option2->name, option->name);
    167  1.1  joerg 
    168  1.1  joerg 			if (option2->has_arg == required_argument
    169  1.1  joerg 			    && optarg == NULL)
    170  1.1  joerg 				cpio_errc(1, 0,
    171  1.1  joerg 				    "Option \"%s\" requires argument", p);
    172  1.1  joerg 		} else {
    173  1.1  joerg 			opt = '?';
    174  1.1  joerg 		}
    175  1.1  joerg 	}
    176  1.1  joerg 
    177  1.1  joerg 	return (opt);
    178  1.1  joerg }
    179  1.1  joerg 
    180  1.1  joerg 
    181  1.1  joerg /*
    182  1.1  joerg  * Parse the argument to the -R or --owner flag.
    183  1.1  joerg  *
    184  1.1  joerg  * The format is one of the following:
    185  1.1  joerg  *   <user>    - Override user but not group
    186  1.1  joerg  *   <user>:   - Override both, group is user's default group
    187  1.1  joerg  *   <user>:<group> - Override both
    188  1.1  joerg  *   :<group>  - Override group but not user
    189  1.1  joerg  *
    190  1.1  joerg  * A period can be used instead of the colon.
    191  1.1  joerg  *
    192  1.1  joerg  * Sets uid/gid as appropriate, -1 indicates uid/gid not specified.
    193  1.1  joerg  *
    194  1.1  joerg  */
    195  1.1  joerg int
    196  1.1  joerg owner_parse(const char *spec, int *uid, int *gid)
    197  1.1  joerg {
    198  1.1  joerg 	const char *u, *ue, *g;
    199  1.1  joerg 
    200  1.1  joerg 	*uid = -1;
    201  1.1  joerg 	*gid = -1;
    202  1.1  joerg 
    203  1.1  joerg 	/*
    204  1.1  joerg 	 * Split spec into [user][:.][group]
    205  1.1  joerg 	 *  u -> first char of username, NULL if no username
    206  1.1  joerg 	 *  ue -> first char after username (colon, period, or \0)
    207  1.1  joerg 	 *  g -> first char of group name
    208  1.1  joerg 	 */
    209  1.1  joerg 	if (*spec == ':' || *spec == '.') {
    210  1.1  joerg 		/* If spec starts with ':' or '.', then just group. */
    211  1.1  joerg 		ue = u = NULL;
    212  1.1  joerg 		g = spec + 1;
    213  1.1  joerg 	} else {
    214  1.1  joerg 		/* Otherwise, [user] or [user][:] or [user][:][group] */
    215  1.1  joerg 		ue = u = spec;
    216  1.1  joerg 		while (*ue != ':' && *ue != '.' && *ue != '\0')
    217  1.1  joerg 			++ue;
    218  1.1  joerg 		g = ue;
    219  1.1  joerg 		if (*g != '\0') /* Skip : or . to find first char of group. */
    220  1.1  joerg 			++g;
    221  1.1  joerg 	}
    222  1.1  joerg 
    223  1.1  joerg 	if (u != NULL) {
    224  1.1  joerg 		/* Look up user: ue is first char after end of user. */
    225  1.1  joerg 		char *user;
    226  1.1  joerg 		struct passwd *pwent;
    227  1.1  joerg 
    228  1.1  joerg 		user = (char *)malloc(ue - u + 1);
    229  1.1  joerg 		if (user == NULL) {
    230  1.1  joerg 			cpio_warnc(errno, "Couldn't allocate memory");
    231  1.1  joerg 			return (1);
    232  1.1  joerg 		}
    233  1.1  joerg 		memcpy(user, u, ue - u);
    234  1.1  joerg 		user[ue - u] = '\0';
    235  1.1  joerg 		pwent = getpwnam(user);
    236  1.1  joerg 		if (pwent == NULL) {
    237  1.1  joerg 			cpio_warnc(errno, "Couldn't lookup user ``%s''", user);
    238  1.1  joerg 			return (1);
    239  1.1  joerg 		}
    240  1.1  joerg 		free(user);
    241  1.1  joerg 		*uid = pwent->pw_uid;
    242  1.1  joerg 		if (*ue != '\0' && *g == '\0')
    243  1.1  joerg 			*gid = pwent->pw_gid;
    244  1.1  joerg 	}
    245  1.1  joerg 	if (*g != '\0') {
    246  1.1  joerg 		struct group *grp;
    247  1.1  joerg 		grp = getgrnam(g);
    248  1.1  joerg 		if (grp != NULL)
    249  1.1  joerg 			*gid = grp->gr_gid;
    250  1.1  joerg 		else {
    251  1.1  joerg 			cpio_warnc(errno, "Couldn't look up group ``%s''", g);
    252  1.1  joerg 			return (1);
    253  1.1  joerg 		}
    254  1.1  joerg 	}
    255  1.1  joerg 	return (0);
    256  1.1  joerg }
    257