+int lfs_join(int argc, char **argv)
+{
+ char *name_head, *name_tail;
+ int fd, rc;
+ loff_t size;
+
+ if (argc != 3)
+ return CMD_HELP;
+ name_head = argv[1];
+ fd = open(name_head, O_WRONLY);
+ if (fd < 0) {
+ fprintf(stderr, "Can not open name_head %s rc=%d\n",
+ name_head, fd);
+ return fd;
+ }
+ size = lseek(fd, 0, SEEK_END);
+ if (size % JOIN_FILE_ALIGN) {
+ fprintf(stderr,"head file %s size %llu must be mutiple of %d\n",
+ name_head, (long long)size, JOIN_FILE_ALIGN);
+ rc = -EINVAL;
+ goto out;
+ }
+ name_tail = argv[2];
+ rc = ioctl(fd, LL_IOC_JOIN, name_tail);
+out:
+ close(fd);
+ if (rc) {
+ fprintf(stderr, "Lustre joining files: %s, %s, failed\n",
+ argv[1], argv[2]);
+ }
+ return rc;
+}
+
+#ifdef HAVE_QUOTA_SUPPORT
+static int lfs_quotachown(int argc, char **argv)
+{
+
+ int c,rc;
+ int flag = 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 = qchk.obd_type;
+ char *obd_uuid = qchk.obd_uuid.uuid;
+ 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];
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
+ qctl.qc_id = QFMT_LDISKFS;
+ qctl.qc_type = check_type;
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ fprintf(stderr, "quota off failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ 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_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_id = QFMT_LDISKFS;
+ qctl.qc_type = check_type;
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ",
+ qctl.obd_type, qctl.obd_uuid.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 = qctl.obd_type;
+ char *obd_uuid = qctl.obd_uuid.uuid;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_QUOTAON;
+ qctl.qc_id = QFMT_LDISKFS;
+
+ 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--;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type, obd_uuid);
+ fprintf(stderr, "%s failed: %s\n", argv[0], strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static int lfs_quotaoff(int argc, char **argv)
+{
+ int c;
+ char *mnt;
+ struct if_quotactl qctl;
+ char *obd_type = qctl.obd_type;
+ char *obd_uuid = qctl.obd_uuid.uuid;
+ 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--;
+
+ if (argc == optind)
+ return CMD_HELP;
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type, obd_uuid);
+ fprintf(stderr, "quotaoff failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static int name2id(unsigned int *id, char *name, int type)
+{
+ if (type == USRQUOTA) {
+ struct passwd *entry;
+
+ if (!(entry = getpwnam(name))) {
+ if (!errno)
+ errno = ENOENT;
+ return -1;
+ }
+
+ *id = entry->pw_uid;
+ } else {
+ struct group *entry;
+
+ if (!(entry = getgrnam(name))) {
+ if (!errno)
+ errno = ENOENT;
+ return -1;
+ }
+
+ *id = entry->gr_gid;
+ }
+
+ return 0;
+}
+
+static int id2name(char **name, unsigned int id, int type)
+{
+ if (type == USRQUOTA) {
+ struct passwd *entry;
+
+ if (!(entry = getpwuid(id))) {
+ if (!errno)
+ errno = ENOENT;
+ return -1;
+ }
+
+ *name = entry->pw_name;
+ } else {
+ struct group *entry;
+
+ if (!(entry = getgrgid(id))) {
+ if (!errno)
+ errno = ENOENT;
+ return -1;
+ }
+
+ *name = entry->gr_name;
+ }
+
+ 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)
+
+int lfs_setquota(int argc, char **argv)
+{
+ int c;
+ char *mnt;
+ struct if_quotactl qctl;
+ char *obd_type = qctl.obd_type;
+ char *obd_uuid = qctl.obd_uuid.uuid;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ugt")) != -1) {
+ switch (c) {
+ case 'u':
+ qctl.qc_type |= 0x01;
+ break;
+ case 'g':
+ qctl.qc_type |= 0x02;
+ break;
+ case 't':
+ qctl.qc_cmd = LUSTRE_Q_SETINFO;
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type)
+ qctl.qc_type--;
+
+ if (qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: user and group quotas can't be set "
+ "both\n");
+ return CMD_HELP;
+ }
+
+ if (qctl.qc_cmd == LUSTRE_Q_SETQUOTA) {
+ struct obd_dqblk *dqb = &qctl.qc_dqblk;
+
+ if (optind + 6 != argc)
+ return CMD_HELP;
+
+ rc = name2id(&qctl.qc_id, argv[optind++], qctl.qc_type);
+ if (rc) {
+ fprintf(stderr, "error: find id for name %s failed: %s\n",
+ argv[optind - 1], strerror(errno));
+ return CMD_HELP;
+ }
+
+ ARG2INT(dqb->dqb_bsoftlimit, argv[optind++], "block-softlimit");
+ ARG2INT(dqb->dqb_bhardlimit, argv[optind++], "block-hardlimit");
+ ARG2INT(dqb->dqb_isoftlimit, argv[optind++], "inode-softlimit");
+ ARG2INT(dqb->dqb_ihardlimit, argv[optind++], "inode-hardlimit");
+
+ dqb->dqb_valid = QIF_LIMITS;
+ } else {
+ struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
+
+ if (optind + 3 != argc)
+ return CMD_HELP;
+
+ ARG2INT(dqi->dqi_bgrace, argv[optind++], "block-grace");
+ ARG2INT(dqi->dqi_igrace, argv[optind++], "inode-grace");
+ }
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type, 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";
+}
+
+
+static void grace2str(time_t seconds,char *buf)
+{
+ uint minutes, hours, days;
+
+ minutes = (seconds + 30) / 60;
+ hours = minutes / 60;
+ minutes %= 60;
+ days = hours / 24;
+ hours %= 24;
+ if (days >= 2)
+ snprintf(buf, 40, "%ddays", days);
+ else
+ snprintf(buf, 40, "%02d:%02d", hours + days * 24, minutes);
+}
+
+
+static void diff2str(time_t seconds, char *buf, time_t now)
+{
+
+ buf[0] = 0;
+ if (!seconds)
+ return;
+ if (seconds <= now) {
+ strcpy(buf, "none");
+ return;
+ }
+ grace2str(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",
+ "blocks", "quota", "limit", "grace",
+ "files", "quota", "limit", "grace");
+}
+
+static void print_quota(char *mnt, struct if_quotactl *qctl, int ost_only)
+{
+ 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);
+
+ sprintf(numbuf[0], LPU64, toqb(dqb->dqb_curspace));
+ sprintf(numbuf[1], LPU64, dqb->dqb_bsoftlimit);
+ sprintf(numbuf[2], 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], LPU64, dqb->dqb_curinodes);
+ sprintf(numbuf[1], LPU64, dqb->dqb_isoftlimit);
+ sprintf(numbuf[2], LPU64, dqb->dqb_ihardlimit);
+ if (!ost_only)
+ printf(" %7s%c %6s %7s %7s",
+ numbuf[0], iover ? '*' : ' ', numbuf[1],
+ numbuf[2], iover > 1 ? timebuf : "");
+ printf("\n");
+ }
+ } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
+ qctl->qc_cmd == Q_GETOINFO) {
+ char bgtimebuf[40];
+ char igtimebuf[40];
+
+ grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
+ grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
+ printf("Block grace time: %s; Inode grace time: %s\n",
+ bgtimebuf, igtimebuf);
+ }
+}
+
+static void print_mds_quota(char *mnt, struct if_quotactl *qctl)
+{
+ int rc;
+
+ /* XXX: this is a flag to mark that only mds quota is wanted */
+ qctl->qc_dqblk.dqb_valid = 1;
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
+ return;
+ }
+ qctl->qc_dqblk.dqb_valid = 0;
+
+ print_quota(qctl->obd_uuid.uuid, qctl, 0);
+}
+
+static void print_lov_quota(char *mnt, struct if_quotactl *qctl)
+{
+ DIR *dir;
+ struct obd_uuid uuids[1024], *uuidp;
+ int obdcount = 1024;
+ int i, rc;
+
+ dir = opendir(mnt);
+ if (!dir) {
+ fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
+ return;
+ }
+
+ rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
+ if (rc != 0) {
+ fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
+ goto out;
+ }
+
+ for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
+ memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
+
+ /* XXX clear this flag to get quota from osts */
+ qctl->qc_dqblk.dqb_valid = 0;
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc) {
+ fprintf(stderr, "%s quotactl failed: %s\n",
+ uuidp->uuid, strerror(errno));
+ continue;
+ }
+
+ print_quota(uuidp->uuid, qctl, 1);
+ }
+
+out:
+ closedir(dir);
+ return;
+}
+
+static int lfs_quota(int argc, char **argv)
+{
+ int c;
+ char *name = NULL, *mnt;
+ struct if_quotactl qctl;
+ char *obd_type = qctl.obd_type;
+ char *obd_uuid = qctl.obd_uuid.uuid;
+ int rc;
+
+ memset(&qctl, 0, sizeof(qctl));
+ qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
+
+ optind = 0;
+ while ((c = getopt(argc, argv, "ugto:")) != -1) {
+ switch (c) {
+ case 'u':
+ qctl.qc_type |= 0x01;
+ break;
+ case 'g':
+ qctl.qc_type |= 0x02;
+ break;
+ case 't':
+ qctl.qc_cmd = LUSTRE_Q_GETINFO;
+ break;
+ case 'o':
+ strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
+ break;
+ default:
+ fprintf(stderr, "error: %s: option '-%c' "
+ "unrecognized\n", argv[0], c);
+ return CMD_HELP;
+ }
+ }
+
+ if (qctl.qc_type)
+ qctl.qc_type--;
+
+ if (qctl.qc_type == UGQUOTA) {
+ fprintf(stderr, "error: user or group can't be specified"
+ "both\n");
+ return CMD_HELP;
+ }
+
+ if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
+ if (optind + 2 != argc)
+ return CMD_HELP;
+
+ name = argv[optind++];
+ rc = name2id(&qctl.qc_id, name, qctl.qc_type);
+ if (rc) {
+ fprintf(stderr, "error: find id for name %s failed: %s\n",
+ name, strerror(errno));
+ return CMD_HELP;
+ }
+ print_quota_title(name, &qctl);
+ } else if (optind + 1 != argc) {
+ return CMD_HELP;
+ }
+
+ mnt = argv[optind];
+
+ rc = llapi_quotactl(mnt, &qctl);
+ if (rc) {
+ if (*obd_type)
+ fprintf(stderr, "%s %s ", obd_type, obd_uuid);
+ fprintf(stderr, "quota failed: %s\n", strerror(errno));
+ return rc;
+ }
+
+ if (!name)
+ rc = id2name(&name, getuid(), qctl.qc_type);
+
+ if (*obd_uuid) {
+ mnt = "";
+ name = obd_uuid;
+ }
+
+ print_quota(mnt, &qctl, 0);
+
+ if (!*obd_uuid && qctl.qc_cmd != LUSTRE_Q_GETINFO) {
+ print_mds_quota(mnt, &qctl);
+ print_lov_quota(mnt, &qctl);
+ }
+
+ return 0;
+}
+#endif /* HAVE_QUOTA_SUPPORT */
+