]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - quota/project.c
Cleanup fsxattr interace use, now that IRIX also supports projid via this mechanism.
[thirdparty/xfsprogs-dev.git] / quota / project.c
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
38 static cmdinfo_t project_cmd;
39 static prid_t prid;
40
41 enum {
42 CHECK_PROJECT = 0x1,
43 SETUP_PROJECT = 0x2,
44 CLEAR_PROJECT = 0x4,
45 };
46
47 static void
48 project_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
90 static int
91 check_project(
92 const char *path,
93 const struct stat *stat,
94 int status,
95 struct FTW *data)
96 {
97 struct fsxattr fsx;
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));
106 else {
107 if (fsx.fsx_projid != prid)
108 printf(_("%s - project identifier is not set"
109 " (inode=%u, tree=%u)\n"),
110 path, fsx.fsx_projid, prid);
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
120 static int
121 clear_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
141 fsx.fsx_projid = 0;
142 fsx.fsx_xflags &= ~XFS_XFLAG_PROJINHERIT;
143 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx) < 0)
144 fprintf(stderr, _("%s: cannot clear project on %s: %s\n"),
145 progname, path, strerror(errno));
146 close(fd);
147 return 0;
148 }
149
150 static int
151 setup_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
171 fsx.fsx_projid = prid;
172 fsx.fsx_xflags |= XFS_XFLAG_PROJINHERIT;
173 if (xfsctl(path, fd, XFS_IOC_FSSETXATTR, &fsx) < 0)
174 fprintf(stderr, _("%s: cannot set project on %s: %s\n"),
175 progname, path, strerror(errno));
176 close(fd);
177 return 0;
178 }
179
180 static void
181 project_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
202 static void
203 project(
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
223 static int
224 project_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
273 void
274 project_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 }