+ 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 */
+
+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)
+ system("kdestroy > /dev/null");
+
+ 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;
+}
+
+/*
+ * We assume one and only one filename is supplied as the
+ * last parameter.
+ */
+static int acl_cmd_parse(int argc, char **argv, char *fname, char *cmd)
+{
+ char *dname, *rpath = NULL;
+ char path[PATH_MAX], cwd[PATH_MAX];
+ FILE *fp;
+ struct mntent *mnt;
+ int i;
+
+ if (argc < 2)
+ return -1;
+
+ /* FIXME the premise is there is no sub-mounted filesystems under this
+ * mounted lustre tree. */
+ strncpy(fname, argv[argc - 1], PATH_MAX);
+
+ /* get path prefix */
+ dname = dirname(fname);
+
+ /* try to resolve the pathname into relative to the root of the mounted
+ * lustre filesystem.
+ */
+ if (getcwd(cwd, sizeof(cwd)) == NULL) {
+ fprintf(stderr, "getcwd %s failed: %s\n", cwd, strerror(errno));
+ return -1;
+ }
+
+ if (chdir(dname) == -1) {
+ fprintf(stderr, "chdir to %s failed: %s\n",
+ dname, strerror(errno));
+ return -1;
+ }
+
+ if (getcwd(path, sizeof(path)) == NULL) {
+ fprintf(stderr, "getcwd %s: %s\n", path, strerror(errno));
+ return -1;
+ }
+
+ if (chdir(cwd) == -1) {
+ fprintf(stderr, "chdir back to %s: %s\n",
+ cwd, strerror(errno));
+ return -1;
+ }
+
+ strncat(path, "/", PATH_MAX);
+ strncpy(fname, argv[argc - 1], PATH_MAX);
+ strncat(path, basename(fname), PATH_MAX);
+
+ fp = setmntent(MOUNTED, "r");
+ if (fp == NULL) {
+ fprintf(stderr, "setmntent %s failed: %s\n",
+ MOUNTED, strerror(errno));
+ return -1;
+ }
+
+ while (1) {
+ mnt = getmntent(fp);
+ if (!mnt)
+ break;
+
+ if (!llapi_is_lustre_mnttype(mnt->mnt_type))
+ continue;
+
+ if (!strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) {
+ rpath = path + strlen(mnt->mnt_dir);
+ break;
+ }
+ }
+ endmntent(fp);
+
+ /* remove char '/' from rpath to be a relative path */
+ while (rpath && *rpath == '/') rpath++;
+
+ if (!rpath) {
+ fprintf(stderr,
+ "%s: file %s doesn't belong to a lustre file system!\n",
+ argv[0], argv[argc - 1]);
+ return -1;
+ }
+
+ for (i = 0; i < argc - 1; i++) {
+ strncat(cmd, argv[i], PATH_MAX);
+ strncat(cmd, " ", PATH_MAX);
+ }
+ strncat(cmd, *rpath ? rpath : ".", PATH_MAX);
+ strncpy(fname, argv[argc - 1], sizeof(fname));
+
+ return 0;
+}
+
+static int lfs_getfacl(int argc, char **argv)
+{
+ char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
+
+ if (acl_cmd_parse(argc, argv, fname, cmd))
+ return CMD_HELP;
+
+ return llapi_getfacl(fname, cmd);
+}
+
+static int lfs_setfacl(int argc, char **argv)
+{
+ char fname[PATH_MAX] = "", cmd[PATH_MAX] = "";
+
+ if (acl_cmd_parse(argc, argv, fname, cmd))
+ return CMD_HELP;
+
+ return llapi_setfacl(fname, cmd);
+}
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ setlinebuf(stdout);
+
+ ptl_initialize(argc, argv);
+ if (obd_initialize(argc, argv) < 0)
+ exit(2);
+ if (dbg_initialize(argc, argv) < 0)
+ exit(3);
+