/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
* vim:expandtab:shiftwidth=8:tabstop=8:
*
- * Copyright (C) 2002 Cluster File Systems, Inc.
- * Author: Peter J. Braam <braam@clusterfs.com>
- * Author: Phil Schwan <phil@clusterfs.com>
- * Author: Robert Read <rread@clusterfs.com>
+ * GPL HEADER START
*
- * This file is part of Lustre, http://www.lustre.org.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
- * Lustre is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU General Public
- * License as published by the Free Software Foundation.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 only,
+ * as published by the Free Software Foundation.
*
- * Lustre is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License version 2 for more details (a copy is included
+ * in the LICENSE file that accompanied this code).
*
- * You should have received a copy of the GNU General Public License
- * along with Lustre; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License
+ * version 2 along with this program; If not, see
+ * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
*
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ *
+ * GPL HEADER END
+ */
+/*
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved
+ * Use is subject to license terms.
+ */
+/*
+ * This file is part of Lustre, http://www.lustre.org/
+ * Lustre is a trademark of Sun Microsystems, Inc.
+ *
+ * lustre/utils/lfs.c
+ *
+ * Author: Peter J. Braam <braam@clusterfs.com>
+ * Author: Phil Schwan <phil@clusterfs.com>
+ * Author: Robert Read <rread@clusterfs.com>
*/
+/* for O_DIRECTORY */
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <lustre/liblustreapi.h>
#include <lustre/lustre_user.h>
-#include "parser.h"
+#include <libcfs/libcfsutil.h>
#include "obdctl.h"
unsigned int libcfs_subsystem_debug = 0;
static int lfs_rgetfacl(int argc, char **argv);
static int lfs_cp(int argc, char **argv);
static int lfs_ls(int argc, char **argv);
+static int lfs_poollist(int argc, char **argv);
/* all avaialable commands */
command_t cmdlist[] = {
"Create a new file with a specific striping pattern or\n"
"set the default striping pattern on an existing directory or\n"
"delete the default striping pattern from an existing directory\n"
- "usage: setstripe <filename|dirname> <stripe_size> <stripe_index> <stripe_count>\n"
- " or \n"
- " setstripe <filename|dirname> [--size|-s stripe_size]\n"
- " [--index|-i stripe_index]\n"
- " [--count|-c stripe_count]\n"
+ "usage: setstripe [--size|-s stripe_size] [--offset|-o start_ost]\n"
+ " [--count|-c stripe_count] [--pool|-p pool_name]\n"
+ " <dir|filename>\n"
" or \n"
- " setstripe -d <dirname> (to delete default striping)\n"
+ " setstripe -d <dir> (to delete default striping)\n"
"\tstripe_size: Number of bytes on each OST (0 filesystem default)\n"
- "\t Can be specified with k, m or g (in KB, MB and GB respectively)\n"
- "\tstripe_index: OST index of first stripe (-1 filesystem default)\n"
- "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)"},
+ "\t Can be specified with k, m or g (in KB, MB and GB\n"
+ "\t respectively)\n"
+ "\tstart_ost: OST index of first stripe (-1 filesystem default)\n"
+ "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n"
+ "\tpool_name: Name of OST pool"},
{"getstripe", lfs_getstripe, 0,
- "To list the striping info for a given filename or files in a\n"
+ "To list the striping info for a given file or files in a\n"
"directory or recursively for all files in a directory tree.\n"
"usage: getstripe [--obd|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
" [--recursive | -r] <dir|file> ..."},
+ {"poollist", lfs_poollist, 0,
+ "List pools or pool OSTs\n"
+ "usage: poollist <fsname>[.<poolname>] | <pathname>\n"},
{"find", lfs_find, 0,
"To find files that match given parameters recursively in a directory tree.\n"
- "usage: find <dir/file> ... \n"
+ "usage: find <dir|file> ... \n"
" [[!] --atime|-A [+-]N] [[!] --mtime|-M [+-]N] [[!] --ctime|-C [+-]N]\n"
" [--maxdepth|-D N] [[!] --name|-n <pattern>] [--print0|-P]\n"
" [--print|-p] [--obd|-O <uuid[s]>] [[!] --size|-s [+-]N[bkMGTP]]\n"
" [[!] --type|-t <filetype>] [[!] --gid|-g N] [[!] --group|-G <name>]\n"
" [[!] --uid|-u N] [[!] --user|-U <name>]\n"
+ " [[!] --pool <name>]\n"
"\t !: used before an option indicates 'NOT' the requested attribute\n"
"\t -: used before an value indicates 'AT MOST' the requested value\n"
"\t +: used before an option indicates 'AT LEAST' the requested value\n"},
{ 0, 0, 0, NULL }
};
+static int isnumber(const char *str)
+{
+ const char *ptr;
+
+ if (str[0] != '-' && !isdigit(str[0]))
+ return 0;
+
+ for (ptr = str + 1; *ptr != '\0'; ptr++) {
+ if (!isdigit(*ptr))
+ return 0;
+ }
+
+ return 1;
+}
+
/* functions */
static int lfs_setstripe(int argc, char **argv)
{
char *stripe_size_arg = NULL;
char *stripe_off_arg = NULL;
char *stripe_count_arg = NULL;
+ char *pool_name_arg = NULL;
unsigned long long size_units;
struct option long_opts[] = {
{"size", required_argument, 0, 's'},
{"count", required_argument, 0, 'c'},
{"index", required_argument, 0, 'i'},
+ {"offset", required_argument, 0, 'o'},
+ {"pool", required_argument, 0, 'p'},
{"delete", no_argument, 0, 'd'},
{0, 0, 0, 0}
};
st_size = 0;
st_offset = -1;
st_count = 0;
- if (argc == 3 && strcmp(argv[1], "-d") == 0) {
- /* for compatibility with the existing positional parameter
- * usage */
- fname = argv[2];
- optind = 2;
- } else if (argc == 5 &&
- (argv[2][0] != '-' || isdigit(argv[2][1])) &&
- (argv[3][0] != '-' || isdigit(argv[3][1])) &&
- (argv[4][0] != '-' || isdigit(argv[4][1])) ) {
+
+#if LUSTRE_VERSION < OBD_OCD_VERSION(2,1,0,0)
+ if (argc == 5 && argv[1][0] != '-' &&
+ isnumber(argv[2]) && isnumber(argv[3]) && isnumber(argv[4])) {
+ fprintf(stderr, "warning: deprecated usage of setstripe "
+ "positional parameters. Use -c, -i, -s instead.\n");
/* for compatibility with the existing positional parameter
* usage */
fname = argv[1];
stripe_off_arg = argv[3];
stripe_count_arg = argv[4];
optind = 4;
- } else {
+ } else
+#else
+#warning "remove obsolete positional parameter code"
+#endif
+ {
optind = 0;
- while ((c = getopt_long(argc, argv, "c:di:s:",
+ while ((c = getopt_long(argc, argv, "c:di:o:s:p:",
long_opts, NULL)) >= 0) {
switch (c) {
case 0:
delete = 1;
break;
case 'i':
+ case 'o':
stripe_off_arg = optarg;
break;
case 's':
stripe_size_arg = optarg;
break;
+ case 'p':
+ pool_name_arg = optarg;
+ break;
case '?':
return CMD_HELP;
default:
return CMD_HELP;
}
}
- if (optind < argc)
- fname = argv[optind];
- else
- return CMD_HELP;
+ fname = argv[optind];
- if (delete &&
- (stripe_size_arg != NULL || stripe_off_arg != NULL ||
- stripe_count_arg != NULL)) {
+ if (delete &&
+ (stripe_size_arg != NULL || stripe_off_arg != NULL ||
+ stripe_count_arg != NULL || pool_name_arg != NULL)) {
fprintf(stderr, "error: %s: cannot specify -d with "
- "-s, -c or -i options\n",
+ "-s, -c -o or -p options\n",
argv[0]);
return CMD_HELP;
}
}
- if (optind != argc - 1) {
- fprintf(stderr, "error: %s: only 1 filename|dirname can be "
- "specified: '%s'\n",
- argv[0], argv[argc - 1]);
+
+ if (optind == argc) {
+ fprintf(stderr, "error: %s: missing filename|dirname\n",
+ argv[0]);
return CMD_HELP;
}
if (stripe_size_arg != NULL) {
result = parse_size(stripe_size_arg, &st_size, &size_units);
if (result) {
- fprintf(stderr,"error: bad size '%s'\n",
- stripe_size_arg);
+ fprintf(stderr, "error: %s: bad size '%s'\n",
+ argv[0], stripe_size_arg);
return result;
}
}
}
}
- result = llapi_file_create(fname, st_size, st_offset, st_count, 0);
- if (result)
- fprintf(stderr, "error: %s: create stripe file failed\n",
- argv[0]);
+ do {
+ result = llapi_file_create_pool(fname, st_size, st_offset,
+ st_count, 0, pool_name_arg);
+ if (result) {
+ fprintf(stderr,"error: %s: create stripe file '%s' "
+ "failed\n", argv[0], fname);
+ break;
+ }
+ fname = argv[++optind];
+ } while (fname != NULL);
return result;
}
+static int lfs_poollist(int argc, char **argv)
+{
+ if (argc != 2)
+ return CMD_HELP;
+
+ return llapi_poollist(argv[1]);
+}
+
static int set_time(time_t *time, time_t *set, char *str)
{
time_t t;
int res = 0;
-
+
if (str[0] == '+')
res = 1;
else if (str[0] == '-')
return 0;
}
+#define FIND_POOL_OPT 3
static int lfs_find(int argc, char **argv)
{
int new_fashion = 1;
{"uid", required_argument, 0, 'u'},
{"user", required_argument, 0, 'U'},
{"name", required_argument, 0, 'n'},
+ /* no short option for pool, p/P already used */
+ {"pool", required_argument, 0, FIND_POOL_OPT},
/* --obd is considered as a new option. */
{"obd", required_argument, 0, 'O'},
{"ost", required_argument, 0, 'O'},
time(&t);
optind = 0;
+ /* when getopt_long_only() hits '!' it returns 1 and puts "!" in optarg */
while ((c = getopt_long_only(argc, argv, "-A:C:D:g:G:M:n:PpO:qrs:t:u:U:v",
long_opts, NULL)) >= 0) {
xtime = NULL;
if (neg_opt)
--neg_opt;
/* '!' is part of option */
+ /* when getopt_long_only() finds a string which is not
+ * an option nor a known option argument it returns 1
+ * in that case if we already have found pathstart and pathend
+ * (i.e. we have the list of pathnames),
+ * the only supported value is "!"
+ */
isoption = (c != 1) || (strcmp(optarg, "!") == 0);
if (!isoption && pathend != -1) {
fprintf(stderr, "err: %s: filename|dirname must either "
/* Long options. */
break;
case 1:
+ /* unknown; opt is "!" or path component,
+ * checking done above.
+ */
if (strcmp(optarg, "!") == 0)
neg_opt = 2;
break;
new_fashion = 1;
param.gid = strtol(optarg, &endptr, 10);
if (optarg == endptr) {
- ret = name2id(¶m.gid, optarg, GRPQUOTA);
- if (ret != 0) {
+ ret = name2id(¶m.gid, optarg, GRPQUOTA);
+ if (ret != 0) {
fprintf(stderr, "Group/GID: %s cannot "
"be found.\n", optarg);
return -1;
new_fashion = 1;
param.uid = strtol(optarg, &endptr, 10);
if (optarg == endptr) {
- ret = name2id(¶m.uid, optarg, USRQUOTA);
- if (ret != 0) {
+ ret = name2id(¶m.uid, optarg, USRQUOTA);
+ if (ret != 0) {
fprintf(stderr, "User/UID: %s cannot "
"be found.\n", optarg);
return -1;
param.exclude_uid = !!neg_opt;
param.check_uid = 1;
break;
+ case FIND_POOL_OPT:
+ new_fashion = 1;
+ if (strlen(optarg) > MAXPOOLNAME) {
+ fprintf(stderr,
+ "Pool name %s is too long"
+ " (max is %d)\n", optarg,
+ MAXPOOLNAME);
+ return -1;
+ }
+ /* we do check for empty pool because empty pool
+ * is used to find V1 lov attributes */
+ strncpy(param.poolname, optarg, MAXPOOLNAME);
+ param.poolname[MAXPOOLNAME] = '\0';
+ param.exclude_pool = !!neg_opt;
+ param.check_pool = 1;
+ break;
case 'n':
new_fashion = 1;
param.pattern = (char *)optarg;
strcpy(buf, (char *)optarg);
if (param.num_alloc_obds == 0) {
- param.obduuid = (struct obd_uuid *)malloc(FIND_MAX_OSTS *
+ param.obduuid = malloc(FIND_MAX_OSTS *
sizeof(struct obd_uuid));
if (param.obduuid == NULL)
return -ENOMEM;
return CMD_HELP;
};
}
-
+
if (pathstart == -1) {
fprintf(stderr, "error: %s: no filename|pathname\n",
argv[0]);
if (!param.recursive && param.maxdepth == -1)
param.maxdepth = 1;
}
-
+
do {
if (new_fashion)
ret = llapi_find(argv[pathstart], ¶m);
} while (++optind < argc && !rc);
if (rc)
- fprintf(stderr, "error: %s failed for %s.\n",
+ fprintf(stderr, "error: %s failed for %s.\n",
argv[0], argv[optind - 1]);
return rc;
}
* 2. specifiers may be encountered multiple times (2s3s is 5 seconds)
* 3. empty integer value is interpreted as 0
*/
-
+
static unsigned long str2sec(const char* timestr) {
const char spec[] = "smhdw";
const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
v = strtoul(timestr, &tail, 10);
if (v == ULONG_MAX || *tail == '\0')
- /* value too large (ULONG_MAX or more)
+ /* value too large (ULONG_MAX or more)
or missing specifier */
goto error;