]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/project.c
2 * Copyright (c) 2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #include <xfs/command.h>
20 #include <xfs/input.h>
24 static cmdinfo_t project_cmd
;
26 static int recurse_depth
= -1;
34 #define EXCLUDED_FILE_TYPES(x) \
46 " list projects or setup a project tree for tree quota management\n"
49 " 'project -c logfiles'\n"
50 " (match project 'logfiles' to a directory, and setup the directory tree)\n"
52 " Without arguments, report all projects found in the /etc/projects file.\n"
53 " The project quota mechanism in XFS can be used to implement a form of\n"
54 " directory tree quota, where a specified directory and all of the files\n"
55 " and subdirectories below it (i.e. a tree) can be restricted to using a\n"
56 " subset of the available space in the filesystem.\n"
58 " A managed tree must be setup initially using the -c option with a project.\n"
59 " The specified project name or identifier is matched to one or more trees\n"
60 " defined in /etc/projects, and these trees are then recursively descended\n"
61 " to mark the affected inodes as being part of that tree - which sets inode\n"
62 " flags and the project identifier on every file.\n"
63 " Once this has been done, new files created in the tree will automatically\n"
64 " be accounted to the tree based on their project identifier. An attempt to\n"
65 " create a hard link to a file in the tree will only succeed if the project\n"
66 " identifier matches the project identifier for the tree. The xfs_io utility\n"
67 " can be used to set the project ID for an arbitrary file, but this can only\n"
68 " be done by a privileged user.\n"
70 " A previously setup tree can be cleared from project quota control through\n"
71 " use of the -C option, which will recursively descend the tree, clearing\n"
72 " the affected inodes from project quota control.\n"
74 " The -c option can be used to check whether a tree is setup, it reports\n"
75 " nothing if the tree is correct, otherwise it reports the paths of inodes\n"
76 " which do not have the project ID of the rest of the tree, or if the inode\n"
79 " The -p <path> option can be used to manually specify project path without\n"
80 " need to create /etc/projects file. This option can be used multiple times\n"
81 " to specify multiple paths. When using this option only one projid/name can\n"
82 " be specified at command line. Note that /etc/projects is also used if exists.\n"
84 " The -d <depth> option allows to descend at most <depth> levels of directories\n"
85 " below the command line arguments. -d 0 means only apply the actions\n"
86 " to the top level of the projects. -d -1 means no recursion limit (default).\n"
88 " The /etc/projid and /etc/projects file formats are simple, and described\n"
89 " on the xfs_quota man page.\n"
96 const struct stat
*stat
,
103 if (recurse_depth
>= 0 && data
->level
> recurse_depth
)
106 if (flag
== FTW_NS
){
108 fprintf(stderr
, _("%s: cannot stat file %s\n"), progname
, path
);
111 if (EXCLUDED_FILE_TYPES(stat
->st_mode
)) {
112 fprintf(stderr
, _("%s: skipping special file %s\n"), progname
, path
);
116 if ((fd
= open(path
, O_RDONLY
|O_NOCTTY
)) == -1) {
118 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
119 progname
, path
, strerror(errno
));
120 } else if ((xfsctl(path
, fd
, XFS_IOC_FSGETXATTR
, &fsx
)) < 0) {
122 fprintf(stderr
, _("%s: cannot get flags on %s: %s\n"),
123 progname
, path
, strerror(errno
));
125 if (fsx
.fsx_projid
!= prid
)
126 printf(_("%s - project identifier is not set"
127 " (inode=%u, tree=%u)\n"),
128 path
, fsx
.fsx_projid
, (unsigned int)prid
);
129 if (!(fsx
.fsx_xflags
& XFS_XFLAG_PROJINHERIT
))
130 printf(_("%s - project inheritance flag is not set\n"),
141 const struct stat
*stat
,
148 if (recurse_depth
>= 0 && data
->level
> recurse_depth
)
151 if (flag
== FTW_NS
){
153 fprintf(stderr
, _("%s: cannot stat file %s\n"), progname
, path
);
156 if (EXCLUDED_FILE_TYPES(stat
->st_mode
)) {
157 fprintf(stderr
, _("%s: skipping special file %s\n"), progname
, path
);
161 if ((fd
= open(path
, O_RDONLY
|O_NOCTTY
)) == -1) {
163 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
164 progname
, path
, strerror(errno
));
166 } else if (xfsctl(path
, fd
, XFS_IOC_FSGETXATTR
, &fsx
) < 0) {
168 fprintf(stderr
, _("%s: cannot get flags on %s: %s\n"),
169 progname
, path
, strerror(errno
));
175 fsx
.fsx_xflags
&= ~XFS_XFLAG_PROJINHERIT
;
176 if (xfsctl(path
, fd
, XFS_IOC_FSSETXATTR
, &fsx
) < 0) {
178 fprintf(stderr
, _("%s: cannot clear project on %s: %s\n"),
179 progname
, path
, strerror(errno
));
188 const struct stat
*stat
,
195 if (recurse_depth
>= 0 && data
->level
> recurse_depth
)
198 if (flag
== FTW_NS
){
200 fprintf(stderr
, _("%s: cannot stat file %s\n"), progname
, path
);
203 if (EXCLUDED_FILE_TYPES(stat
->st_mode
)) {
204 fprintf(stderr
, _("%s: skipping special file %s\n"), progname
, path
);
208 if ((fd
= open(path
, O_RDONLY
|O_NOCTTY
)) == -1) {
210 fprintf(stderr
, _("%s: cannot open %s: %s\n"),
211 progname
, path
, strerror(errno
));
213 } else if (xfsctl(path
, fd
, XFS_IOC_FSGETXATTR
, &fsx
) < 0) {
215 fprintf(stderr
, _("%s: cannot get flags on %s: %s\n"),
216 progname
, path
, strerror(errno
));
221 fsx
.fsx_projid
= prid
;
222 fsx
.fsx_xflags
|= XFS_XFLAG_PROJINHERIT
;
223 if (xfsctl(path
, fd
, XFS_IOC_FSSETXATTR
, &fsx
) < 0) {
225 fprintf(stderr
, _("%s: cannot set project on %s: %s\n"),
226 progname
, path
, strerror(errno
));
240 printf(_("Checking project %s (path %s)...\n"), project
, dir
);
241 nftw(dir
, check_project
, 100, FTW_PHYS
|FTW_MOUNT
);
244 printf(_("Setting up project %s (path %s)...\n"), project
, dir
);
245 nftw(dir
, setup_project
, 100, FTW_PHYS
|FTW_MOUNT
);
248 printf(_("Clearing project %s (path %s)...\n"), project
, dir
);
249 nftw(dir
, clear_project
, 100, FTW_PHYS
|FTW_MOUNT
);
263 fs_cursor_initialise(NULL
, FS_PROJECT_PATH
, &cursor
);
264 while ((path
= fs_cursor_next_entry(&cursor
))) {
265 if (prid
!= path
->fs_prid
&& path
->fs_prid
!= -1)
267 project_operations(project
, path
->fs_dir
, type
);
271 printf(_("Processed %d (%s and cmdline) paths for project %s with "
272 "recursion depth %s (%d).\n"),
273 count
, projects_file
, project
,
274 recurse_depth
< 0 ? _("infinite") : _("limited"), recurse_depth
);
282 int c
, type
= 0, ispath
= 0;
284 while ((c
= getopt(argc
, argv
, "cd:p:sC")) != EOF
) {
287 type
= CHECK_PROJECT
;
290 recurse_depth
= atoi(optarg
);
291 if (recurse_depth
< 0)
296 fs_table_insert_project_path(optarg
, -1);
299 type
= SETUP_PROJECT
;
302 type
= CLEAR_PROJECT
;
305 return command_usage(&project_cmd
);
310 return command_usage(&project_cmd
);
312 /* no options - just check the given projects */
314 type
= CHECK_PROJECT
;
317 if (!ispath
&& access(projects_file
, F_OK
) != 0) {
319 fprintf(stderr
, _("projects file \"%s\" doesn't exist\n"),
324 if (ispath
&& argc
- optind
> 1) {
326 fprintf(stderr
, _("%s: only one projid/name can be specified "
327 "when using -p <path>, %d found.\n"),
328 progname
, argc
- optind
);
332 while (argc
> optind
) {
333 prid
= prid_from_string(argv
[optind
]);
336 fprintf(stderr
, _("%s - no such project in %s "
337 "or invalid project number\n"),
338 argv
[optind
], projects_file
);
340 project(argv
[optind
], type
);
350 project_cmd
.name
= _("project");
351 project_cmd
.altname
= _("tree");
352 project_cmd
.cfunc
= project_f
;
353 project_cmd
.args
= _("[-c|-s|-C|-d <depth>|-p <path>] project ...");
354 project_cmd
.argmin
= 1;
355 project_cmd
.argmax
= -1;
356 project_cmd
.oneline
= _("check, setup or clear project quota trees");
357 project_cmd
.help
= project_help
;
360 add_command(&project_cmd
);