+static int verify_pool_name(char *prog_name, char *pool_name)
+{
+ char *ptr;
+
+ if (pool_name == NULL)
+ return 0;
+
+ ptr = strchr(pool_name, '.');
+ if (ptr != NULL && ptr == pool_name) {
+ fprintf(stderr, "error: %s: fsname is empty in pool name '%s'\n",
+ prog_name, pool_name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct lfs_setstripe_args {
+ unsigned long long lsa_comp_end;
+ unsigned long long lsa_stripe_size;
+ int lsa_stripe_count;
+ int lsa_stripe_off;
+ __u32 lsa_comp_flags;
+ int lsa_nr_osts;
+ __u32 *lsa_osts;
+ char *lsa_pool_name;
+};
+
+static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
+{
+ memset(lsa, 0, sizeof(*lsa));
+ lsa->lsa_stripe_off = -1;
+}
+
+static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
+{
+ return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
+ lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
+ lsa->lsa_comp_end != 0);
+}
+
+static int comp_args_to_layout(struct llapi_layout **composite,
+ struct lfs_setstripe_args *lsa)
+{
+ struct llapi_layout *layout = *composite;
+ uint64_t prev_end = 0;
+ int i = 0, rc;
+
+ if (layout == NULL) {
+ layout = llapi_layout_alloc();
+ if (layout == NULL) {
+ fprintf(stderr, "Alloc llapi_layout failed. %s\n",
+ strerror(errno));
+ return -ENOMEM;
+ }
+ *composite = layout;
+ } else {
+ uint64_t start;
+
+ /* Get current component extent, current component
+ * must be the tail component. */
+ rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
+ if (rc) {
+ fprintf(stderr, "Get comp extent failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ rc = llapi_layout_comp_add(layout);
+ if (rc) {
+ fprintf(stderr, "Add component failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+ }
+
+ rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
+ if (rc) {
+ fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
+ prev_end, lsa->lsa_comp_end, strerror(errno));
+ return rc;
+ }
+
+ if (lsa->lsa_stripe_size != 0) {
+ rc = llapi_layout_stripe_size_set(layout,
+ lsa->lsa_stripe_size);
+ if (rc) {
+ fprintf(stderr, "Set stripe size %llu failed. %s\n",
+ lsa->lsa_stripe_size, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_stripe_count != 0) {
+ rc = llapi_layout_stripe_count_set(layout,
+ lsa->lsa_stripe_count == -1 ?
+ LLAPI_LAYOUT_WIDE :
+ lsa->lsa_stripe_count);
+ if (rc) {
+ fprintf(stderr, "Set stripe count %d failed. %s\n",
+ lsa->lsa_stripe_count, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_pool_name != NULL) {
+ rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
+ if (rc) {
+ fprintf(stderr, "Set pool name: %s failed. %s\n",
+ lsa->lsa_pool_name, strerror(errno));
+ return rc;
+ }
+ }
+
+ if (lsa->lsa_nr_osts > 0) {
+ if (lsa->lsa_stripe_count > 0 &&
+ lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
+ fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
+ lsa->lsa_stripe_count, lsa->lsa_nr_osts);
+ return -EINVAL;
+ }
+ for (i = 0; i < lsa->lsa_nr_osts; i++) {
+ rc = llapi_layout_ost_index_set(layout, i,
+ lsa->lsa_osts[i]);
+ if (rc)
+ break;
+ }
+ } else if (lsa->lsa_stripe_off != -1) {
+ rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
+ }
+ if (rc) {
+ fprintf(stderr, "Set ost index %d failed. %s\n",
+ i, strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+/* In 'lfs setstripe --component-add' mode, we need to fetch the extent
+ * end of the last component in the existing file, and adjust the
+ * first extent start of the components to be added accordingly. */
+static int adjust_first_extent(char *fname, struct llapi_layout *layout)
+{
+ struct llapi_layout *head;
+ uint64_t start, end, stripe_size, prev_end = 0;
+ int rc;
+
+ if (layout == NULL)
+ return -EINVAL;
+
+ errno = 0;
+ head = llapi_layout_get_by_path(fname, 0);
+ if (head == NULL) {
+ fprintf(stderr, "Read layout from %s failed. %s\n",
+ fname, strerror(errno));
+ return -EINVAL;
+ } else if (errno == ENODATA) {
+ /* file without LOVEA, this component-add will be turned
+ * into a component-create. */
+ llapi_layout_free(head);
+ return -ENODATA;
+ } else {
+ /* Current component of 'head' should be tail of component
+ * list by default, but we do an extra move cursor operation
+ * here to test if the layout is non-composite. */
+ rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
+ if (rc < 0) {
+ fprintf(stderr, "'%s' isn't a composite file?\n",
+ fname);
+ llapi_layout_free(head);
+ return rc;
+ }
+ }
+
+ rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
+ if (rc) {
+ fprintf(stderr, "Get prev extent failed. %s\n",
+ strerror(errno));
+ llapi_layout_free(head);
+ return rc;
+ }
+
+ llapi_layout_free(head);
+
+ /* Make sure we use the first component of the layout to be added. */
+ rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
+ if (rc < 0) {
+ fprintf(stderr, "Move component cursor failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ rc = llapi_layout_comp_extent_get(layout, &start, &end);
+ if (rc) {
+ fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
+ return rc;
+ }
+
+ if (start > prev_end || end <= prev_end) {
+ fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
+ "adjacent with the existing file extent end: %lu\n",
+ start, end, prev_end);
+ return -EINVAL;
+ }
+
+ rc = llapi_layout_stripe_size_get(layout, &stripe_size);
+ if (rc) {
+ fprintf(stderr, "Get stripe size failed. %s\n",
+ strerror(errno));
+ return rc;
+ }
+
+ if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
+ (prev_end & (stripe_size - 1))) {
+ fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
+ stripe_size, prev_end);
+ return -EINVAL;
+ }
+
+ rc = llapi_layout_comp_extent_set(layout, prev_end, end);
+ if (rc) {
+ fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
+ prev_end, end, strerror(errno));
+ return rc;
+ }
+
+ return 0;
+}
+
+static inline bool comp_flags_is_neg(__u32 flags)
+{
+ return flags & LCME_FL_NEG;
+}
+
+static inline void comp_flags_set_neg(__u32 *flags)
+{
+ *flags |= LCME_FL_NEG;
+}
+
+static inline void comp_flags_clear_neg(__u32 *flags)
+{
+ *flags &= ~LCME_FL_NEG;
+}
+
+static int comp_str2flags(__u32 *flags, char *string)
+{
+ char *name;
+ __u32 neg_flags = 0;
+
+ if (string == NULL)
+ return -EINVAL;
+
+ *flags = 0;
+ for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
+ bool found = false;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
+ __u32 comp_flag = comp_flags_table[i].cfn_flag;
+ const char *comp_name = comp_flags_table[i].cfn_name;
+
+ if (strcmp(name, comp_name) == 0) {
+ *flags |= comp_flag;
+ found = true;
+ } else if (strncmp(name, "^", 1) == 0 &&
+ strcmp(name + 1, comp_name) == 0) {
+ neg_flags |= comp_flag;
+ found = true;
+ }
+ }
+ if (!found) {
+ llapi_printf(LLAPI_MSG_ERROR, "Component flag "
+ "'%s' is not supported.\n", name);
+ return -EINVAL;
+ }
+ }
+
+ if (*flags == 0 && neg_flags == 0)
+ return -EINVAL;
+ /* don't support mixed flags for now */
+ if (*flags && neg_flags)
+ return -EINVAL;
+
+ if (neg_flags) {
+ *flags = neg_flags;
+ comp_flags_set_neg(flags);
+ }
+
+ return 0;
+}
+
+static inline bool arg_is_eof(char *arg)
+{
+ return !strncmp(arg, "-1", strlen("-1")) ||
+ !strncmp(arg, "EOF", strlen("EOF")) ||
+ !strncmp(arg, "eof", strlen("eof"));
+}
+
+enum {
+ LFS_POOL_OPT = 3,
+ LFS_COMP_COUNT_OPT,
+ LFS_COMP_START_OPT,
+ LFS_COMP_FLAGS_OPT,
+ LFS_COMP_DEL_OPT,
+ LFS_COMP_SET_OPT,
+ LFS_COMP_ADD_OPT,
+ LFS_PROJID_OPT,
+};
+