]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - quota/project.c
Cleanup fsxattr interace use, now that IRIX also supports projid via this mechanism.
[thirdparty/xfsprogs-dev.git] / quota / project.c
CommitLineData
5aead01d
NS
1/*
2 * Copyright (c) 2005 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
31 */
32
33#include <xfs/command.h>
34#include <xfs/input.h>
35#include "init.h"
36#include "quota.h"
37
38static cmdinfo_t project_cmd;
39static prid_t prid;
40
41enum {
42 CHECK_PROJECT = 0x1,
43 SETUP_PROJECT = 0x2,
44 CLEAR_PROJECT = 0x4,
45};
46
47static void
48project_help(void)
49{
50 printf(_(
51"\n"
52" list projects or setup a project tree for tree quota management\n"
53"\n"
54" Example:\n"
55" 'project -c logfiles'\n"
56" (match project 'logfiles' to a directory, and setup the directory tree)\n"
57"\n"
58" Without arguments, report all projects found in the /etc/projects file.\n"
59" The project quota mechanism in XFS can be used to implement a form of\n"
60" directory tree quota, where a specified directory and all of the files\n"
61" and subdirectories below it (i.e. a tree) can be restricted to using a\n"
62" subset of the available space in the filesystem.\n"
63"\n"
64" A managed tree must be setup initially using the -c option with a project.\n"
65" The specified project name or identifier is matched to one or more trees\n"
66" defined in /etc/projects, and these trees are then recursively descended\n"
67" to mark the affected inodes as being part of that tree - which sets inode\n"
68" flags and the project identifier on every file.\n"
69" Once this has been done, new files created in the tree will automatically\n"
70" be accounted to the tree based on their project identifier. An attempt to\n"
71" create a hard link to a file in the tree will only succeed if the project\n"
72" identifier matches the project identifer for the tree. The xfs_io utility\n"
73" can be used to set the project ID for an arbitrary file, but this can only\n"
74" be done by a privileged user.\n"
75"\n"
76" A previously setup tree can be cleared from project quota control through\n"
77" use of the -C option, which will recursively descend the tree, clearing\n"
78" the affected inodes from project quota control.\n"
79"\n"
80" The -c option can be used to check whether a tree is setup, it reports\n"
81" nothing if the tree is correct, otherwise it reports the paths of inodes\n"
82" which do not have the project ID of the rest of the tree, or if the inode\n"
83" flag is not set.\n"
84"\n"
85" The /etc/projid and /etc/projects file formats are simple, and described\n"
86" on the xfs_quota man page.\n"
87"\n"));
88}
89
90static int
91check_project(
92 const char *path,
93 const struct stat *stat,
94 int status,
95 struct FTW *data)
96{
97 struct fsxattr fsx;
5aead01d
NS
98 int fd;
99
100 if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1)
101 fprintf(stderr, _("%s: cannot open %s: %s\n"),
102 progname, path, strerror(errno));
103 else if ((xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx)) < 0)
104 fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
105 progname, path, strerror(errno));
5aead01d 106 else {
764b1982 107 if (fsx.fsx_projid != prid)
5aead01d
NS
108 printf(_("%s - project identifier is not set"
109 " (inode=%u, tree=%u)\n"),
764b1982 110 path, fsx.fsx_projid, prid);
5aead01d
NS
111 if (!(fsx.fsx_xflags & XFS_XFLAG_PROJINHERIT))
112 printf(_("%s - project inheritance flag is not set\n"),
113 path);
114 }
115 if (fd != -1)
116 close(fd);
117 return 0;
118}
119
120static int
121clear_project(
122 const char *path,
123 const struct stat *stat,
124 int status,
125 struct FTW *data)
126{
127 struct fsxattr fsx;
128 int fd;
129
130 if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) {
131 fprintf(stderr, _("%s: cannot open %s: %s\n"),
132 progname, path, strerror(errno));
133 return 0;
134 } else if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx) < 0) {
135 fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
136 progname, path, strerror(errno));
137 close(fd);
138 return 0;
139 }
140
764b1982 141 fsx.fsx_projid = 0;
5aead01d 142 fsx.fsx_xflags &= ~XFS_XFLAG_PROJINHERIT;
764b1982
NS
143 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx) < 0)
144 fprintf(stderr, _("%s: cannot clear project on %s: %s\n"),
5aead01d
NS
145 progname, path, strerror(errno));
146 close(fd);
147 return 0;
148}
149
150static int
151setup_project(
152 const char *path,
153 const struct stat *stat,
154 int status,
155 struct FTW *data)
156{
157 struct fsxattr fsx;
158 int fd;
159
160 if ((fd = open(path, O_RDONLY|O_NOCTTY)) == -1) {
161 fprintf(stderr, _("%s: cannot open %s: %s\n"),
162 progname, path, strerror(errno));
163 return 0;
164 } else if (xfsctl(path, fd, XFS_IOC_FSGETXATTR, &fsx) < 0) {
165 fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
166 progname, path, strerror(errno));
167 close(fd);
168 return 0;
169 }
170
764b1982 171 fsx.fsx_projid = prid;
5aead01d 172 fsx.fsx_xflags |= XFS_XFLAG_PROJINHERIT;
5aead01d 173 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx) < 0)
764b1982 174 fprintf(stderr, _("%s: cannot set project on %s: %s\n"),
5aead01d
NS
175 progname, path, strerror(errno));
176 close(fd);
177 return 0;
178}
179
180static void
181project_operations(
182 char *project,
183 char *dir,
184 int type)
185{
186 switch (type) {
187 case CHECK_PROJECT:
188 printf(_("Checking project %s (path %s)...\n"), project, dir);
189 nftw(dir, check_project, 100, FTW_PHYS|FTW_MOUNT|FTW_DEPTH);
190 break;
191 case SETUP_PROJECT:
192 printf(_("Setting up project %s (path %s)...\n"), project, dir);
193 nftw(dir, setup_project, 100, FTW_PHYS|FTW_MOUNT|FTW_DEPTH);
194 break;
195 case CLEAR_PROJECT:
196 printf(_("Clearing project %s (path %s)...\n"), project, dir);
197 nftw(dir, clear_project, 100, FTW_PHYS|FTW_MOUNT|FTW_DEPTH);
198 break;
199 }
200}
201
202static void
203project(
204 char *project,
205 int type)
206{
207 fs_cursor_t cursor;
208 fs_path_t *path;
209 int count = 0;
210
211 fs_cursor_initialise(NULL, FS_PROJECT_PATH, &cursor);
212 while ((path = fs_cursor_next_entry(&cursor))) {
213 if (prid != path->fs_prid)
214 continue;
215 project_operations(project, path->fs_dir, type);
216 count++;
217 }
218
219 printf(_("Processed %d %s paths for project %s\n"),
220 count, projects_file, project);
221}
222
223static int
224project_f(
225 int argc,
226 char **argv)
227{
228 int c, type = 0;
229
230 while ((c = getopt(argc, argv, "csC")) != EOF) {
231 switch (c) {
232 case 'c':
233 type = CHECK_PROJECT;
234 break;
235 case 's':
236 type = SETUP_PROJECT;
237 break;
238 case 'C':
239 type = CLEAR_PROJECT;
240 break;
241 default:
242 return command_usage(&project_cmd);
243 }
244 }
245
246 if (argc == optind)
247 return command_usage(&project_cmd);
248
249 /* no options - just check the given projects */
250 if (!type)
251 type = CHECK_PROJECT;
252
253 setprfiles();
254 if (access(projects_file, F_OK) != 0) {
255 fprintf(stderr, _("projects file \"%s\" doesn't exist\n"),
256 projects_file);
257 return 0;
258 }
259
260 while (argc > optind) {
261 prid = prid_from_string(argv[optind]);
262 if (prid == -1)
263 fprintf(stderr, _("%s - no such project in %s\n"),
264 argv[optind], projects_file);
265 else
266 project(argv[optind], type);
267 optind++;
268 }
269
270 return 0;
271}
272
273void
274project_init(void)
275{
276 project_cmd.name = _("project");
277 project_cmd.altname = _("tree");
278 project_cmd.cfunc = project_f;
279 project_cmd.args = _("[-c|-s|-C] project ...");
280 project_cmd.argmin = 1;
281 project_cmd.argmax = -1;
282 project_cmd.oneline = _("check, setup or clear project quota trees");
283 project_cmd.help = project_help;
284
285 if (expert)
286 add_command(&project_cmd);
287}