4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or https://opensource.org/licenses/CDDL-1.0.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2017, Intle Corporation. All rights reserved.
37 #include <sys/types.h>
39 #include <sys/zfs_project.h>
42 #include "zfs_projectutil.h"
44 typedef struct zfs_project_item
{
50 zfs_project_item_alloc(list_t
*head
, const char *name
)
52 zfs_project_item_t
*zpi
;
54 zpi
= safe_malloc(sizeof (zfs_project_item_t
) + strlen(name
) + 1);
55 strcpy(zpi
->zpi_name
, name
);
56 list_insert_tail(head
, zpi
);
60 zfs_project_sanity_check(const char *name
, zfs_project_control_t
*zpc
,
67 (void) fprintf(stderr
, gettext("failed to stat %s: %s\n"),
68 name
, strerror(errno
));
72 if (!S_ISREG(st
->st_mode
) && !S_ISDIR(st
->st_mode
)) {
73 (void) fprintf(stderr
, gettext("only support project quota on "
74 "regular file or directory\n"));
78 if (!S_ISDIR(st
->st_mode
)) {
79 if (zpc
->zpc_dironly
) {
80 (void) fprintf(stderr
, gettext(
81 "'-d' option on non-dir target %s\n"), name
);
85 if (zpc
->zpc_recursive
) {
86 (void) fprintf(stderr
, gettext(
87 "'-r' option on non-dir target %s\n"), name
);
96 zfs_project_load_projid(const char *name
, zfs_project_control_t
*zpc
)
101 fd
= open(name
, O_RDONLY
| O_NOCTTY
);
103 (void) fprintf(stderr
, gettext("failed to open %s: %s\n"),
104 name
, strerror(errno
));
108 ret
= ioctl(fd
, ZFS_IOC_FSGETXATTR
, &fsx
);
110 (void) fprintf(stderr
,
111 gettext("failed to get xattr for %s: %s\n"),
112 name
, strerror(errno
));
114 zpc
->zpc_expected_projid
= fsx
.fsx_projid
;
121 zfs_project_handle_one(const char *name
, zfs_project_control_t
*zpc
)
126 fd
= open(name
, O_RDONLY
| O_NOCTTY
);
128 if (errno
== ENOENT
&& zpc
->zpc_ignore_noent
)
131 (void) fprintf(stderr
, gettext("failed to open %s: %s\n"),
132 name
, strerror(errno
));
136 ret
= ioctl(fd
, ZFS_IOC_FSGETXATTR
, &fsx
);
138 (void) fprintf(stderr
,
139 gettext("failed to get xattr for %s: %s\n"),
140 name
, strerror(errno
));
144 switch (zpc
->zpc_op
) {
145 case ZFS_PROJECT_OP_LIST
:
146 (void) printf("%5u %c %s\n", fsx
.fsx_projid
,
147 (fsx
.fsx_xflags
& ZFS_PROJINHERIT_FL
) ? 'P' : '-', name
);
149 case ZFS_PROJECT_OP_CHECK
:
150 if (fsx
.fsx_projid
== zpc
->zpc_expected_projid
&&
151 fsx
.fsx_xflags
& ZFS_PROJINHERIT_FL
)
154 if (!zpc
->zpc_newline
) {
157 (void) printf("%s%c", name
, c
);
161 if (fsx
.fsx_projid
!= zpc
->zpc_expected_projid
)
162 (void) printf("%s - project ID is not set properly "
163 "(%u/%u)\n", name
, fsx
.fsx_projid
,
164 (uint32_t)zpc
->zpc_expected_projid
);
166 if (!(fsx
.fsx_xflags
& ZFS_PROJINHERIT_FL
))
167 (void) printf("%s - project inherit flag is not set\n",
171 case ZFS_PROJECT_OP_CLEAR
:
172 if (!(fsx
.fsx_xflags
& ZFS_PROJINHERIT_FL
) &&
173 (zpc
->zpc_keep_projid
||
174 fsx
.fsx_projid
== ZFS_DEFAULT_PROJID
))
177 fsx
.fsx_xflags
&= ~ZFS_PROJINHERIT_FL
;
178 if (!zpc
->zpc_keep_projid
)
179 fsx
.fsx_projid
= ZFS_DEFAULT_PROJID
;
181 case ZFS_PROJECT_OP_SET
:
182 if (fsx
.fsx_projid
== zpc
->zpc_expected_projid
&&
183 (!zpc
->zpc_set_flag
|| fsx
.fsx_xflags
& ZFS_PROJINHERIT_FL
))
186 fsx
.fsx_projid
= zpc
->zpc_expected_projid
;
187 if (zpc
->zpc_set_flag
)
188 fsx
.fsx_xflags
|= ZFS_PROJINHERIT_FL
;
195 ret
= ioctl(fd
, ZFS_IOC_FSSETXATTR
, &fsx
);
197 (void) fprintf(stderr
,
198 gettext("failed to set xattr for %s: %s\n"),
199 name
, strerror(errno
));
207 zfs_project_handle_dir(const char *name
, zfs_project_control_t
*zpc
,
216 if (errno
== ENOENT
&& zpc
->zpc_ignore_noent
)
220 (void) fprintf(stderr
, gettext("failed to opendir %s: %s\n"),
221 name
, strerror(errno
));
225 /* Non-top item, ignore the case of being removed or renamed by race. */
226 zpc
->zpc_ignore_noent
= B_TRUE
;
228 while (!ret
&& (ent
= readdir(dir
)) != NULL
) {
231 /* skip "." and ".." */
232 if (strcmp(ent
->d_name
, ".") == 0 ||
233 strcmp(ent
->d_name
, "..") == 0)
236 if (strlen(ent
->d_name
) + strlen(name
) + 1 >= PATH_MAX
) {
237 errno
= ENAMETOOLONG
;
241 if (asprintf(&fullname
, "%s/%s", name
, ent
->d_name
) == -1) {
246 ret
= zfs_project_handle_one(fullname
, zpc
);
247 if (!ret
&& zpc
->zpc_recursive
&& ent
->d_type
== DT_DIR
)
248 zfs_project_item_alloc(head
, fullname
);
255 (void) fprintf(stderr
, gettext("failed to readdir %s: %s\n"),
256 name
, strerror(errno
));
264 zfs_project_handle(const char *name
, zfs_project_control_t
*zpc
)
266 zfs_project_item_t
*zpi
;
271 ret
= zfs_project_sanity_check(name
, zpc
, &st
);
275 if ((zpc
->zpc_op
== ZFS_PROJECT_OP_SET
||
276 zpc
->zpc_op
== ZFS_PROJECT_OP_CHECK
) &&
277 zpc
->zpc_expected_projid
== ZFS_INVALID_PROJID
) {
278 ret
= zfs_project_load_projid(name
, zpc
);
283 zpc
->zpc_ignore_noent
= B_FALSE
;
284 ret
= zfs_project_handle_one(name
, zpc
);
285 if (ret
|| !S_ISDIR(st
.st_mode
) || zpc
->zpc_dironly
||
286 (!zpc
->zpc_recursive
&&
287 zpc
->zpc_op
!= ZFS_PROJECT_OP_LIST
&&
288 zpc
->zpc_op
!= ZFS_PROJECT_OP_CHECK
))
291 list_create(&head
, sizeof (zfs_project_item_t
),
292 offsetof(zfs_project_item_t
, zpi_list
));
293 zfs_project_item_alloc(&head
, name
);
294 while ((zpi
= list_remove_head(&head
)) != NULL
) {
296 ret
= zfs_project_handle_dir(zpi
->zpi_name
, zpc
, &head
);