+static int lfs_join(int argc, char **argv)
+{
+ fprintf(stderr, "join two lustre files into one.\n"
+ "obsolete, HEAD does not support it anymore.\n");
+ return 0;
+}
+
+#ifdef HAVE_SYS_QUOTA_H
+static int lfs_quotachown(int argc, char **argv)
+{
+
+ int c,rc;
+ int flag = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "i")) != -1) {
+ switch (c) {
+ case 'i':
+ flag++;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+ if (optind == argc)
+ return CMD_HELP;
+ rc = llapi_quotachown(argv[optind], flag);
+ if(rc)
+ fprintf(stderr,"error: change file owner/group failed.\n");
+ return rc;
+}
+
+static int lfs_quotacheck(int argc, char **argv)
+{
+ int c, check_type = 0;
+ char *mnt;
+ struct if_quotacheck qchk;
+ struct if_quotactl qctl;
+ char *obd_type = (char *)qchk.obd_type;
+ int rc;
+
+ memset(&qchk, 0, sizeof(qchk));
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ug")) != -1) {
+ switch (c) {
+ case 'u':
+ check_type |= 0x01;
+ break;
+ case 'g':
+ check_type |= 0x02;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (check_type)
+ check_type--;
+ else /* do quotacheck for both user & group quota by default */
+ check_type = 0x02;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotacheck(mnt, check_type);
+ if (rc) {
+ fprintf(stderr, "quotacheck failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ rc = llapi_poll_quotacheck(mnt, &qchk);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qchk.obd_uuid));
+ fprintf(stderr, "quota check failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_QUOTAON;
+ qctl.qc_type = check_type;
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc && errno != EALREADY) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", (char *)qctl.obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "%s turn on quota failed: %s\n",
+ argv[0], strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static int lfs_quotaon(int argc, char **argv)
+{
+ int c;
+ char *mnt;
+ struct if_quotactl qctl;
+ char *obd_type = (char *)qctl.obd_type;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_QUOTAON;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ugf")) != -1) {
+ switch (c) {
+ case 'u':
+ qctl.qc_type |= 0x01;
+ break;
+ case 'g':
+ qctl.qc_type |= 0x02;
+ break;
+ case 'f':
+ qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type)
+ qctl.qc_type--;
+ else /* by default, enable quota for both user & group */
+ qctl.qc_type = 0x02;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (errno == EALREADY) {
+ rc = 0;
+ } else if (errno == ENOENT) {
+ fprintf(stderr, "error: cannot find quota database, "
+ "make sure you have run quotacheck\n");
+ } else {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "%s failed: %s\n", argv[0],
+ strerror(errno));
+ }
+ }
+
+ return rc;
+}
+
+static int lfs_quotaoff(int argc, char **argv)
+{
+ int c;
+ char *mnt;
+ struct if_quotactl qctl;
+ char *obd_type = (char *)qctl.obd_type;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ug")) != -1) {
+ switch (c) {
+ case 'u':
+ qctl.qc_type |= 0x01;
+ break;
+ case 'g':
+ qctl.qc_type |= 0x02;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type)
+ qctl.qc_type--;
+ else /* by default, disable quota for both user & group */
+ qctl.qc_type = 0x02;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (errno == EALREADY) {
+ rc = 0;
+ } else {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "quotaoff failed: %s\n",
+ strerror(errno));
+ }
+ }
+
+ return rc;
+}
+
+static int lfs_quotainv(int argc, char **argv)
+{
+ int c;
+ char *mnt;
+ struct if_quotactl qctl;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_INVALIDATE;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ugf")) != -1) {
+ switch (c) {
+ case 'u':
+ qctl.qc_type |= 0x01;
+ break;
+ case 'g':
+ qctl.qc_type |= 0x02;
+ break;
+ case 'f':
+ qctl.qc_cmd = LUSTRE_Q_FINVALIDATE;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type)
+ qctl.qc_type--;
+ else /* by default, invalidate quota for both user & group */
+ qctl.qc_type = 0x02;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ fprintf(stderr, "quotainv failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+#define ARG2INT(nr, str, msg) \
+do { \
+ char *endp; \
+ nr = strtol(str, &endp, 0); \
+ if (*endp) { \
+ fprintf(stderr, "error: bad %s: %s\n", msg, str); \
+ return CMD_HELP; \
+ } \
+} while (0)
+
+#define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
+
+/* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
+ * returns the value or ULONG_MAX on integer overflow or incorrect format
+ * Notes:
+ * 1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
+ * 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};
+ unsigned long val = 0;
+ char *tail;
+
+ if (strpbrk(timestr, spec) == NULL) {
+ /* no specifiers inside the time string,
+ should treat it as an integer value */
+ val = strtoul(timestr, &tail, 10);
+ return *tail ? ULONG_MAX : val;
+ }
+
+ /* format string is XXwXXdXXhXXmXXs */
+ while (*timestr) {
+ unsigned long v;
+ int ind;
+ char* ptr;
+
+ v = strtoul(timestr, &tail, 10);
+ if (v == ULONG_MAX || *tail == '\0')
+ /* value too large (ULONG_MAX or more)
+ or missing specifier */
+ goto error;
+
+ ptr = strchr(spec, *tail);
+ if (ptr == NULL)
+ /* unknown specifier */
+ goto error;
+
+ ind = ptr - spec;
+
+ /* check if product will overflow the type */
+ if (!(v < ULONG_MAX / mult[ind]))
+ goto error;
+
+ ADD_OVERFLOW(val, mult[ind] * v);
+ if (val == ULONG_MAX)
+ goto error;
+
+ timestr = tail + 1;
+ }
+
+ return val;
+
+error:
+ return ULONG_MAX;
+}
+
+#define ARG2ULL(nr, str, defscale) \
+do { \
+ unsigned long long limit, units = 0; \
+ int rc; \
+ \
+ rc = parse_size(str, &limit, &units, 1); \
+ if (rc < 0) { \
+ fprintf(stderr, "error: bad limit value %s\n", str); \
+ return CMD_HELP; \
+ } \
+ nr = ((units == 0) ? (defscale) : 1) * limit; \
+} while (0)
+
+static inline int has_times_option(int argc, char **argv)
+{
+ int i;
+
+ for (i = 1; i < argc; i++)
+ if (!strcmp(argv[i], "-t"))
+ return 1;
+
+ return 0;
+}
+
+int lfs_setquota_times(int argc, char **argv)
+{
+ int c, rc;
+ struct if_quotactl qctl;
+ char *mnt, *obd_type = (char *)qctl.obd_type;
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
+ struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
+ struct option long_opts[] = {
+ {"user", no_argument, 0, 'u'},
+ {"group", no_argument, 0, 'g'},
+ {"block-grace", required_argument, 0, 'b'},
+ {"inode-grace", required_argument, 0, 'i'},
+ {"times", no_argument, 0, 't'},
+ {0, 0, 0, 0}
+ };
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_SETINFO;
+ qctl.qc_type = UGQUOTA;
+
+ optind = 0;
+ while ((c = getopt_long(argc, argv, "b:i:gtu", long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'u':
+ case 'g':
+ if (qctl.qc_type != UGQUOTA) {
+ fprintf(stderr, "error: -u and -g can't be used "
+ "more than once\n");
+ return CMD_HELP;
+ }
+ qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
+ break;
+ case 'b':
+ if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
+ fprintf(stderr, "error: bad block-grace: %s\n",
+ optarg);
+ return CMD_HELP;
+ }
+ dqb->dqb_valid |= QIF_BTIME;
+ break;
+ case 'i':
+ if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
+ fprintf(stderr, "error: bad inode-grace: %s\n",
+ optarg);
+ return CMD_HELP;
+ }
+ dqb->dqb_valid |= QIF_ITIME;
+ break;
+ case 't': /* Yes, of course! */
+ break;
+ default: /* getopt prints error message for us when opterr != 0 */
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: neither -u nor -g specified\n");
+ return CMD_HELP;
+ }
+
+ if (optind != argc - 1) {
+ fprintf(stderr, "error: unexpected parameters encountered\n");
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "setquota failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+#define BSLIMIT (1 << 0)
+#define BHLIMIT (1 << 1)
+#define ISLIMIT (1 << 2)
+#define IHLIMIT (1 << 3)
+
+int lfs_setquota(int argc, char **argv)
+{
+ int c, rc;
+ struct if_quotactl qctl;
+ char *mnt, *obd_type = (char *)qctl.obd_type;
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
+ struct option long_opts[] = {
+ {"user", required_argument, 0, 'u'},
+ {"group", required_argument, 0, 'g'},
+ {"block-softlimit", required_argument, 0, 'b'},
+ {"block-hardlimit", required_argument, 0, 'B'},
+ {"inode-softlimit", required_argument, 0, 'i'},
+ {"inode-hardlimit", required_argument, 0, 'I'},
+ {0, 0, 0, 0}
+ };
+ unsigned limit_mask = 0;
+ char *endptr;
+
+ if (has_times_option(argc, argv))
+ return lfs_setquota_times(argc, argv);
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
+ qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
+ * so it can be used as a marker that qc_type
+ * isn't reinitialized from command line */
+
+ optind = 0;
+ while ((c = getopt_long(argc, argv, "b:B:i:I:g:u:", long_opts, NULL)) != -1) {
+ switch (c) {
+ case 'u':
+ case 'g':
+ if (qctl.qc_type != UGQUOTA) {
+ fprintf(stderr, "error: -u and -g can't be used"
+ " more than once\n");
+ return CMD_HELP;
+ }
+ qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
+ rc = name2id(&qctl.qc_id, optarg,
+ (qctl.qc_type == USRQUOTA) ? USER : GROUP);
+ if (rc) {
+ qctl.qc_id = strtoul(optarg, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: can't find id "
+ "for name %s\n", optarg);
+ return CMD_HELP;
+ }
+ }
+ break;
+ case 'b':
+ ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
+ dqb->dqb_bsoftlimit >>= 10;
+ limit_mask |= BSLIMIT;
+ break;
+ case 'B':
+ ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
+ dqb->dqb_bhardlimit >>= 10;
+ limit_mask |= BHLIMIT;
+ break;
+ case 'i':
+ ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
+ limit_mask |= ISLIMIT;
+ break;
+ case 'I':
+ ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
+ limit_mask |= IHLIMIT;
+ break;
+ default: /* getopt prints error message for us when opterr != 0 */
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: neither -u nor -g was specified\n");
+ return CMD_HELP;
+ }
+
+ if (limit_mask == 0) {
+ fprintf(stderr, "error: at least one limit must be specified\n");
+ return CMD_HELP;
+ }
+
+ if (optind != argc - 1) {
+ fprintf(stderr, "error: unexpected parameters encountered\n");
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+
+ if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
+ (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
+ /* sigh, we can't just set blimits/ilimits */
+ struct if_quotactl tmp_qctl = {.qc_cmd = LUSTRE_Q_GETQUOTA,
+ .qc_type = qctl.qc_type,
+ .qc_id = qctl.qc_id};
+
+ rc = llapi_quotactl(mnt, &tmp_qctl);
+ if (rc < 0) {
+ fprintf(stderr, "error: setquota failed while retrieving"
+ " current quota settings (%s)\n",
+ strerror(errno));
+ return rc;
+ }
+
+ if (!(limit_mask & BHLIMIT))
+ dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
+ if (!(limit_mask & BSLIMIT))
+ dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
+ if (!(limit_mask & IHLIMIT))
+ dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
+ if (!(limit_mask & ISLIMIT))
+ dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
+
+ /* Keep grace times if we have got no softlimit arguments */
+ if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
+ dqb->dqb_valid |= QIF_BTIME;
+ dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
+ }
+
+ if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
+ dqb->dqb_valid |= QIF_ITIME;
+ dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
+ }
+ }
+
+ dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
+ dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type,
+ obd_uuid2str(&qctl.obd_uuid));
+ fprintf(stderr, "setquota failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static inline char *type2name(int check_type)
+{
+ if (check_type == USRQUOTA)
+ return "user";
+ else if (check_type == GRPQUOTA)
+ return "group";
+ else
+ return "unknown";
+}
+
+/* Converts seconds value into format string
+ * result is returned in buf
+ * Notes:
+ * 1. result is in descenting order: 1w2d3h4m5s
+ * 2. zero fields are not filled (except for p. 3): 5d1s
+ * 3. zero seconds value is presented as "0s"
+ */
+static char * __sec2str(time_t seconds, char *buf)
+{
+ const char spec[] = "smhdw";
+ const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
+ unsigned long c;
+ char *tail = buf;
+ int i;
+
+ for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
+ c = seconds / mult[i];
+
+ if (c > 0 || (i == 0 && buf == tail))
+ tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
+
+ seconds %= mult[i];
+ }
+
+ return tail;
+}
+
+static void sec2str(time_t seconds, char *buf, int rc)
+{
+ char *tail = buf;
+
+ if (rc)
+ *tail++ = '[';
+
+ tail = __sec2str(seconds, tail);
+
+ if (rc && tail - buf < 39) {
+ *tail++ = ']';
+ *tail++ = 0;
+ }
+}
+
+static void diff2str(time_t seconds, char *buf, time_t now)
+{
+
+ buf[0] = 0;
+ if (!seconds)
+ return;
+ if (seconds <= now) {
+ strcpy(buf, "none");
+ return;
+ }
+ __sec2str(seconds - now, buf);
+}
+
+static void print_quota_title(char *name, struct if_quotactl *qctl)
+{
+ printf("Disk quotas for %s %s (%cid %u):\n",
+ type2name(qctl->qc_type), name,
+ *type2name(qctl->qc_type), qctl->qc_id);
+ printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
+ "Filesystem",
+ "kbytes", "quota", "limit", "grace",
+ "files", "quota", "limit", "grace");
+}
+
+static void print_quota(char *mnt, struct if_quotactl *qctl, int type, int rc)
+{
+ time_t now;
+
+ time(&now);
+
+ if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
+ int bover = 0, iover = 0;
+ struct obd_dqblk *dqb = &qctl->qc_dqblk;
+
+ if (dqb->dqb_bhardlimit &&
+ toqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
+ bover = 1;
+ } else if (dqb->dqb_bsoftlimit &&
+ toqb(dqb->dqb_curspace) >= dqb->dqb_bsoftlimit) {
+ if (dqb->dqb_btime > now) {
+ bover = 2;
+ } else {
+ bover = 3;
+ }
+ }
+
+ if (dqb->dqb_ihardlimit &&
+ dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
+ iover = 1;
+ } else if (dqb->dqb_isoftlimit &&
+ dqb->dqb_curinodes >= dqb->dqb_isoftlimit) {
+ if (dqb->dqb_btime > now) {
+ iover = 2;
+ } else {
+ iover = 3;
+ }
+ }
+
+#if 0 /* XXX: always print quotas even when no usages */
+ if (dqb->dqb_curspace || dqb->dqb_curinodes)
+#endif
+ {
+ char numbuf[3][32];
+ char timebuf[40];
+
+ if (strlen(mnt) > 15)
+ printf("%s\n%15s", mnt, "");
+ else
+ printf("%15s", mnt);
+
+ if (bover)
+ diff2str(dqb->dqb_btime, timebuf, now);
+ if (rc == -1 && errno == EREMOTEIO)
+ sprintf(numbuf[0], LPU64"*",
+ toqb(dqb->dqb_curspace));
+ else
+ sprintf(numbuf[0],
+ (dqb->dqb_valid & QIF_SPACE) ?
+ LPU64 : "["LPU64"]",
+ toqb(dqb->dqb_curspace));
+ if (type == QC_GENERAL)
+ sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS)
+ ? LPU64 : "["LPU64"]",
+ dqb->dqb_bsoftlimit);
+ else
+ sprintf(numbuf[1], "%s", "-");
+ sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS)
+ ? LPU64 : "["LPU64"]", dqb->dqb_bhardlimit);
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], bover ? '*' : ' ', numbuf[1],
+ numbuf[2], bover > 1 ? timebuf : "-");
+
+ if (iover)
+ diff2str(dqb->dqb_itime, timebuf, now);
+
+ sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
+ LPU64 : "["LPU64"]", dqb->dqb_curinodes);
+ if (type == QC_GENERAL)
+ sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS)
+ ? LPU64 : "["LPU64"]",
+ dqb->dqb_isoftlimit);
+ else
+ sprintf(numbuf[1], "%s", "-");
+ sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
+ LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
+ if (type != QC_OSTIDX)
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], iover ? '*' : ' ', numbuf[1],
+ numbuf[2], iover > 1 ? timebuf : "-");
+ else
+ printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
+ printf("\n");
+ }
+ } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
+ qctl->qc_cmd == Q_GETOINFO) {
+ char bgtimebuf[40];
+ char igtimebuf[40];
+
+ sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
+ sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
+ printf("Block grace time: %s; Inode grace time: %s\n",
+ bgtimebuf, igtimebuf);
+ }
+}
+
+static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt)
+{
+ int rc = 0, rc1 = 0, count = 0;
+ __u32 valid = qctl->qc_valid;
+
+ rc = llapi_get_obd_count(mnt, &count, is_mdt);
+ if (rc) {
+ fprintf(stderr, "can not get %s count: %s\n",
+ is_mdt ? "mdt": "ost", strerror(errno));
+ return rc;
+ }
+
+ for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
+ qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ /* It is remote client case. */
+ if (errno == EOPNOTSUPP) {
+ rc = 0;
+ goto out;
+ }
+
+ if (!rc1)
+ rc1 = rc;
+ fprintf(stderr, "quotactl %s%d failed.\n",
+ is_mdt ? "mdt": "ost", qctl->qc_idx);
+ continue;
+ }
+
+ print_quota(obd_uuid2str(&qctl->obd_uuid), qctl, qctl->qc_valid, 0);
+ }
+
+out:
+ qctl->qc_valid = valid;
+ return rc ? : rc1;
+}
+
+static int lfs_quota(int argc, char **argv)
+{
+ int c;
+ char *mnt, *name = NULL;
+ struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
+ .qc_type = UGQUOTA };
+ char *obd_type = (char *)qctl.obd_type;
+ char *obd_uuid = (char *)qctl.obd_uuid.uuid;
+ int rc, rc1 = 0, rc2 = 0, rc3 = 0,
+ verbose = 0, pass = 0, quiet = 0, inacc;
+ char *endptr;
+ __u32 valid = QC_GENERAL, idx = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ugto:i:I:qv")) != -1) {
+ switch (c) {
+ case 'u':
+ if (qctl.qc_type != UGQUOTA) {
+ fprintf(stderr, "error: use either -u or -g\n");
+ return CMD_HELP;
+ }
+ qctl.qc_type = USRQUOTA;
+ break;
+ case 'g':
+ if (qctl.qc_type != UGQUOTA) {
+ fprintf(stderr, "error: use either -u or -g\n");
+ return CMD_HELP;
+ }
+ qctl.qc_type = GRPQUOTA;
+ break;
+ case 't':
+ qctl.qc_cmd = LUSTRE_Q_GETINFO;
+ break;
+ case 'o':
+ valid = qctl.qc_valid = QC_UUID;
+ strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
+ break;
+ case 'i':
+ valid = qctl.qc_valid = QC_MDTIDX;
+ idx = qctl.qc_idx = atoi(optarg);
+ break;
+ case 'I':
+ valid = qctl.qc_valid = QC_OSTIDX;
+ idx = qctl.qc_idx = atoi(optarg);
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
+ if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
+ optind == argc - 1) {
+ug_output:
+ memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
+ qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
+ qctl.qc_valid = valid;
+ qctl.qc_idx = idx;
+ if (pass++ == 0) {
+ qctl.qc_type = USRQUOTA;
+ qctl.qc_id = geteuid();
+ } else {
+ qctl.qc_type = GRPQUOTA;
+ qctl.qc_id = getegid();
+ }
+ rc = id2name(&name, qctl.qc_id,
+ (qctl.qc_type == USRQUOTA) ? USER : GROUP);
+ if (rc)
+ name = "<unknown>";
+ /* lfs quota -u username /path/to/lustre/mount */
+ } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
+ /* options should be followed by u/g-name and mntpoint */
+ if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: missing quota argument(s)\n");
+ return CMD_HELP;
+ }
+
+ name = argv[optind++];
+ rc = name2id(&qctl.qc_id, name,
+ (qctl.qc_type == USRQUOTA) ? USER : GROUP);
+ if (rc) {
+ qctl.qc_id = strtoul(name, &endptr, 10);
+ if (*endptr != '\0') {
+ fprintf(stderr, "error: can't find id for name "
+ "%s\n", name);
+ return CMD_HELP;
+ }
+ }
+ } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: missing quota info argument(s)\n");
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+
+ rc1 = llapi_quotactl(mnt, &qctl);
+ if (rc1 == -1) {
+ switch (errno) {
+ case ESRCH:
+ fprintf(stderr, "%s quotas are not enabled.\n",
+ qctl.qc_type == USRQUOTA ? "user" : "group");
+ goto out;
+ case EPERM:
+ fprintf(stderr, "Permission denied.\n");
+ case ENOENT:
+ /* We already got a "No such file..." message. */
+ goto out;
+ default:
+ fprintf(stderr, "Unexpected quotactl error: %s\n",
+ strerror(errno));
+ }
+ }
+
+ if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
+ print_quota_title(name, &qctl);
+
+ if (rc1 && *obd_type)
+ fprintf(stderr, "%s %s ", obd_type, obd_uuid);
+
+ if (qctl.qc_valid != QC_GENERAL)
+ mnt = "";
+
+ inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
+ ((qctl.qc_dqblk.dqb_valid&(QIF_LIMITS|QIF_USAGE))!=(QIF_LIMITS|QIF_USAGE));
+
+ print_quota(mnt, &qctl, QC_GENERAL, rc1);
+
+ if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO && verbose) {
+ rc2 = print_obd_quota(mnt, &qctl, 1);
+ rc3 = print_obd_quota(mnt, &qctl, 0);
+ }
+
+ if (rc1 || rc2 || rc3 || inacc)
+ printf("Some errors happened when getting quota info. "
+ "Some devices may be not working or deactivated. "
+ "The data in \"[]\" is inaccurate.\n");
+
+out:
+ if (pass == 1)
+ goto ug_output;
+
+ return rc1;
+}
+#endif /* HAVE_SYS_QUOTA_H! */
+
+static int flushctx_ioctl(char *mp)
+{
+ int fd, rc;
+
+ fd = open(mp, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "flushctx: error open %s: %s\n",
+ mp, strerror(errno));
+ return -1;
+ }
+
+ rc = ioctl(fd, LL_IOC_FLUSHCTX);
+ if (rc == -1)
+ fprintf(stderr, "flushctx: error ioctl %s: %s\n",
+ mp, strerror(errno));
+
+ close(fd);
+ return rc;
+}
+
+static int lfs_flushctx(int argc, char **argv)
+{
+ int kdestroy = 0, c;
+ FILE *proc;
+ char procline[PATH_MAX], *line;
+ int rc = 0;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "k")) != -1) {
+ switch (c) {
+ case 'k':
+ kdestroy = 1;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (kdestroy) {
+ int rc;
+ if ((rc = system("kdestroy > /dev/null")) != 0) {
+ rc = WEXITSTATUS(rc);
+ fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
+ }
+ }
+
+ if (optind >= argc) {
+ /* flush for all mounted lustre fs. */
+ proc = fopen("/proc/mounts", "r");
+ if (!proc) {
+ fprintf(stderr, "error: %s: can't open /proc/mounts\n",
+ argv[0]);
+ return -1;
+ }
+
+ while ((line = fgets(procline, PATH_MAX, proc)) != NULL) {
+ char dev[PATH_MAX];
+ char mp[PATH_MAX];
+ char fs[PATH_MAX];
+
+ if (sscanf(line, "%s %s %s", dev, mp, fs) != 3) {
+ fprintf(stderr, "%s: unexpected format in "
+ "/proc/mounts\n",
+ argv[0]);
+ return -1;
+ }
+
+ if (strcmp(fs, "lustre") != 0)
+ continue;
+ /* we use '@' to determine it's a client. are there
+ * any other better way?
+ */
+ if (strchr(dev, '@') == NULL)
+ continue;
+
+ if (flushctx_ioctl(mp))
+ rc = -1;
+ }
+ } else {
+ /* flush fs as specified */
+ while (optind < argc) {
+ if (flushctx_ioctl(argv[optind++]))
+ rc = -1;
+ }
+ }
+
+ return rc;
+}
+
+static int lfs_lsetfacl(int argc, char **argv)
+{
+ argv[0]++;
+ return(llapi_lsetfacl(argc, argv));
+}
+
+static int lfs_lgetfacl(int argc, char **argv)
+{
+ argv[0]++;
+ return(llapi_lgetfacl(argc, argv));
+}
+
+static int lfs_rsetfacl(int argc, char **argv)
+{
+ argv[0]++;
+ return(llapi_rsetfacl(argc, argv));
+}
+
+static int lfs_rgetfacl(int argc, char **argv)
+{
+ argv[0]++;
+ return(llapi_rgetfacl(argc, argv));
+}
+
+static int lfs_cp(int argc, char **argv)
+{
+ return(llapi_cp(argc, argv));
+}
+
+static int lfs_ls(int argc, char **argv)
+{
+ return(llapi_ls(argc, argv));
+}
+
+static int lfs_changelog(int argc, char **argv)
+{
+ void *changelog_priv;
+ struct changelog_rec *rec;
+ long long startrec = 0, endrec = 0;
+ char *mdd;
+ struct option long_opts[] = {
+ {"follow", no_argument, 0, 'f'},
+ {0, 0, 0, 0}
+ };
+ char short_opts[] = "f";
+ int rc, follow = 0;
+
+ optind = 0;
+ while ((rc = getopt_long(argc, argv, short_opts,
+ long_opts, NULL)) != -1) {
+ switch (rc) {
+ case 'f':
+ follow++;
+ break;
+ case '?':
+ return CMD_HELP;
+ default:
+ fprintf(stderr, "error: %s: option '%s' unrecognized\n",
+ argv[0], argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+ if (optind >= argc)
+ return CMD_HELP;
+
+ mdd = argv[optind++];
+ if (argc > optind)
+ startrec = strtoll(argv[optind++], NULL, 10);
+ if (argc > optind)
+ endrec = strtoll(argv[optind++], NULL, 10);
+
+ rc = llapi_changelog_start(&changelog_priv,
+ CHANGELOG_FLAG_BLOCK |
+ (follow ? CHANGELOG_FLAG_FOLLOW : 0),
+ mdd, startrec);
+ if (rc < 0) {
+ fprintf(stderr, "Can't start changelog: %s\n",
+ strerror(errno = -rc));
+ return rc;
+ }
+
+ while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
+ time_t secs;
+ struct tm ts;
+
+ if (endrec && rec->cr_index > endrec) {
+ llapi_changelog_free(&rec);
+ break;
+ }
+ if (rec->cr_index < startrec) {
+ llapi_changelog_free(&rec);
+ continue;
+ }
+
+ secs = rec->cr_time >> 30;
+ gmtime_r(&secs, &ts);
+ printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
+ "0x%x t="DFID, rec->cr_index, rec->cr_type,
+ changelog_type2str(rec->cr_type),
+ ts.tm_hour, ts.tm_min, ts.tm_sec,
+ (int)(rec->cr_time & ((1<<30) - 1)),
+ ts.tm_year+1900, ts.tm_mon+1, ts.tm_mday,
+ rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
+ if (rec->cr_namelen)
+ /* namespace rec includes parent and filename */
+ printf(" p="DFID" %.*s\n", PFID(&rec->cr_pfid),
+ rec->cr_namelen, rec->cr_name);
+ else
+ printf("\n");
+
+ llapi_changelog_free(&rec);
+ }
+
+ llapi_changelog_fini(&changelog_priv);
+
+ if (rc < 0)
+ fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
+
+ return (rc == 1 ? 0 : rc);
+}
+
+static int lfs_changelog_clear(int argc, char **argv)
+{
+ long long endrec;
+ int rc;
+
+ if (argc != 4)
+ return CMD_HELP;
+
+ endrec = strtoll(argv[3], NULL, 10);
+
+ rc = llapi_changelog_clear(argv[1], argv[2], endrec);
+ if (rc)
+ fprintf(stderr, "%s error: %s\n", argv[0],
+ strerror(errno = -rc));
+ return rc;
+}
+
+static int lfs_fid2path(int argc, char **argv)
+{
+ struct option long_opts[] = {
+ {"cur", no_argument, 0, 'c'},
+ {"link", required_argument, 0, 'l'},
+ {"rec", required_argument, 0, 'r'},
+ {0, 0, 0, 0}
+ };
+ char short_opts[] = "cl:r:";
+ char *device, *fid, *path;
+ long long recno = -1;
+ int linkno = -1;
+ int lnktmp;
+ int printcur = 0;
+ int rc;
+
+ optind = 0;
+
+ while ((rc = getopt_long(argc, argv, short_opts,
+ long_opts, NULL)) != -1) {
+ switch (rc) {
+ case 'c':
+ printcur++;
+ break;
+ case 'l':
+ linkno = strtol(optarg, NULL, 10);
+ break;
+ case 'r':
+ recno = strtoll(optarg, NULL, 10);
+ break;
+ case '?':
+ return CMD_HELP;
+ default:
+ fprintf(stderr, "error: %s: option '%s' unrecognized\n",
+ argv[0], argv[optind - 1]);
+ return CMD_HELP;
+ }
+ }
+ device = argv[optind++];
+ fid = argv[optind++];
+ if (optind != argc)
+ return CMD_HELP;
+
+ path = calloc(1, PATH_MAX);
+
+ lnktmp = (linkno >= 0) ? linkno : 0;
+ while (1) {
+ int oldtmp = lnktmp;
+ long long rectmp = recno;
+ rc = llapi_fid2path(device, fid, path, PATH_MAX, &rectmp,
+ &lnktmp);
+ if (rc < 0) {
+ fprintf(stderr, "%s error: %s\n", argv[0],
+ strerror(errno = -rc));
+ break;
+ }
+
+ if (printcur)
+ fprintf(stdout, "%lld ", rectmp);
+ if (device[0] == '/') {
+ fprintf(stdout, "%s", device);
+ if (device[strlen(device) - 1] != '/')
+ fprintf(stdout, "/");
+ } else if (path[0] == '\0') {
+ fprintf(stdout, "/");
+ }
+ fprintf(stdout, "%s\n", path);
+
+ if (linkno >= 0)
+ /* specified linkno */
+ break;
+ if (oldtmp == lnktmp)
+ /* no more links */
+ break;
+ }
+
+ free(path);
+ return rc;
+}
+
+static int lfs_path2fid(int argc, char **argv)
+{
+ char *path;
+ lustre_fid fid;
+ int rc;
+
+ if (argc != 2)
+ return CMD_HELP;
+
+ path = argv[1];
+ rc = llapi_path2fid(path, &fid);
+ if (rc) {
+ fprintf(stderr, "can't get fid for %s: %s\n", path,
+ strerror(errno = -rc));
+ return rc;
+ }
+
+ printf(DFID"\n", PFID(&fid));
+
+ return 0;
+}
+
+int main(int argc, char **argv)