2 * Main functions of the program.
4 * Copyright (C) 2007 David Härdeman <david@hardeman.nu>
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation version 2 of the License.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include <sys/types.h>
27 #include <attr/xattr.h>
32 #include "metastore.h"
34 #include "metaentry.h"
36 /* Used to signal whether mtimes should be corrected */
40 * Prints differences between stored and actual metadata
41 * - for use in mentries_compare
44 compare_print(struct metaentry
*left
, struct metaentry
*right
, int cmp
)
47 msg(MSG_QUIET
, "%s:\tremoved\n", right
->path
);
52 msg(MSG_QUIET
, "%s:\tadded\n", left
->path
);
56 if (cmp
== DIFF_NONE
) {
57 msg(MSG_DEBUG
, "%s:\tno difference\n", left
->path
);
61 msg(MSG_QUIET
, "%s:\t", left
->path
);
63 msg(MSG_QUIET
, "owner ");
65 msg(MSG_QUIET
, "group ");
67 msg(MSG_QUIET
, "mode ");
69 msg(MSG_QUIET
, "type ");
71 msg(MSG_QUIET
, "mtime ");
73 msg(MSG_QUIET
, "xattr ");
78 * Tries to change the real metadata to match the stored one
79 * - for use in mentries_compare
82 compare_fix(struct metaentry
*left
, struct metaentry
*right
, int cmp
)
91 if (!left
&& !right
) {
92 msg(MSG_ERROR
, "%s called with incorrect arguments\n",
98 msg(MSG_NORMAL
, "%s:\tremoved\n", right
->path
);
103 msg(MSG_NORMAL
, "%s:\tadded\n", left
->path
);
107 if (cmp
== DIFF_NONE
) {
108 msg(MSG_DEBUG
, "%s:\tno difference\n", left
->path
);
112 if (cmp
& DIFF_TYPE
) {
113 msg(MSG_NORMAL
, "%s:\tnew type, will not change metadata\n",
118 msg(MSG_QUIET
, "%s:\tchanging metadata\n", left
->path
);
120 while (cmp
& (DIFF_OWNER
| DIFF_GROUP
)) {
121 if (cmp
& DIFF_OWNER
) {
122 msg(MSG_NORMAL
, "\tchanging owner from %s to %s\n",
123 left
->path
, left
->group
, right
->group
);
124 owner
= getpwnam(right
->owner
);
126 msg(MSG_DEBUG
, "\tgetpwnam failed: %s\n",
133 if (cmp
& DIFF_GROUP
) {
134 msg(MSG_NORMAL
, "\tchanging group from %s to %s\n",
135 left
->path
, left
->group
, right
->group
);
136 group
= getgrnam(right
->group
);
138 msg(MSG_DEBUG
, "\tgetgrnam failed: %s\n",
145 if (lchown(left
->path
, uid
, gid
)) {
146 msg(MSG_DEBUG
, "\tlchown failed: %s\n",
153 if (cmp
& DIFF_MODE
) {
154 msg(MSG_NORMAL
, "%s:\tchanging mode from 0%o to 0%o\n",
155 left
->path
, left
->mode
, right
->mode
);
156 if (chmod(left
->path
, left
->mode
))
157 msg(MSG_DEBUG
, "\tchmod failed: %s\n", strerror(errno
));
160 if (cmp
& DIFF_MTIME
) {
161 msg(MSG_NORMAL
, "%s:\tchanging mtime from %ld to %ld\n",
162 left
->path
, left
->mtime
, right
->mtime
);
163 /* FIXME: Use utimensat here */
164 tbuf
.actime
= right
->mtime
;
165 tbuf
.modtime
= right
->mtime
;
166 if (utime(left
->path
, &tbuf
)) {
167 msg(MSG_DEBUG
, "\tutime failed: %s\n", strerror(errno
));
172 if (cmp
& DIFF_XATTR
) {
173 for (i
= 0; i
< left
->xattrs
; i
++) {
174 /* Any attrs to remove? */
175 if (mentry_find_xattr(right
, left
, i
) >= 0)
178 msg(MSG_NORMAL
, "%s:\tremoving xattr %s\n",
179 left
->path
, left
->xattr_names
[i
]);
180 if (lremovexattr(left
->path
, left
->xattr_names
[i
]))
181 msg(MSG_DEBUG
, "\tlremovexattr failed: %s\n",
185 for (i
= 0; i
< right
->xattrs
; i
++) {
186 /* Any xattrs to add? (on change they are removed above) */
187 if (mentry_find_xattr(left
, right
, i
) >= 0)
190 msg(MSG_NORMAL
, "%s:\tadding xattr %s\n",
191 right
->path
, right
->xattr_names
[i
]);
192 if (lsetxattr(right
->path
, right
->xattr_names
[i
],
193 right
->xattr_values
[i
],
194 right
->xattr_lvalues
[i
], XATTR_CREATE
))
195 msg(MSG_DEBUG
, "\tlsetxattr failed: %s\n",
201 /* Prints usage message and exits */
203 usage(const char *arg0
, const char *message
)
206 msg(MSG_CRITICAL
, "%s: %s\n\n", arg0
, msg
);
207 msg(MSG_CRITICAL
, "Usage: %s ACTION [OPTIONS] [PATH]...\n\n", arg0
);
208 msg(MSG_CRITICAL
, "Where ACTION is one of:\n"
209 " -d, --diff\tShow differences between stored and real metadata\n"
210 " -s, --save\tSave current metadata\n"
211 " -a, --apply\tApply stored metadata\n"
212 " -h, --help\tHelp message (this text)\n\n"
213 "Valid OPTIONS are (can be given more than once):\n"
214 " -v, --verbose\tPrint more verbose messages\n"
215 " -q, --quiet\tPrint less verbose messages\n");
217 exit(message
? EXIT_FAILURE
: EXIT_SUCCESS
);
221 static struct option long_options
[] = {
222 {"compare", 0, 0, 0},
226 {"verbose", 0, 0, 0},
234 main(int argc
, char **argv
, char **envp
)
237 struct metaentry
*mhead
= NULL
;
238 struct metaentry
*mfhead
= NULL
;
244 int option_index
= 0;
245 c
= getopt_long(argc
, argv
, "csahvqm",
246 long_options
, &option_index
);
251 if (!strcmp("verbose", long_options
[option_index
].name
)) {
253 } else if (!strcmp("quiet",
254 long_options
[option_index
].name
)) {
256 } else if (!strcmp("mtime",
257 long_options
[option_index
].name
)) {
260 action
|= (1 << option_index
);
265 action
|= ACTION_DIFF
;
269 action
|= ACTION_SAVE
;
273 action
|= ACTION_APPLY
;
277 action
|= ACTION_HELP
;
290 usage(argv
[0], "unknown option");
294 /* Make sure only one action is specified */
296 usage(argv
[0], "incorrect option(s)");
301 mentries_fromfile(&mfhead
, METAFILE
);
303 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
309 while (optind
< argc
)
310 mentries_recurse_path(argv
[optind
++], &mhead
);
312 mentries_recurse_path(".", &mhead
);
317 "Failed to load metadata from file system\n");
321 mentries_compare(mhead
, mfhead
, compare_print
);
326 while (optind
< argc
)
327 mentries_recurse_path(argv
[optind
++], &mhead
);
329 mentries_recurse_path(".", &mhead
);
334 "Failed to load metadata from file system\n");
338 mentries_tofile(mhead
, METAFILE
);
342 mentries_fromfile(&mfhead
, METAFILE
);
344 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
350 while (optind
< argc
)
351 mentries_recurse_path(argv
[optind
++], &mhead
);
353 mentries_recurse_path(".", &mhead
);
358 "Failed to load metadata from file system\n");
362 mentries_compare(mhead
, mfhead
, compare_fix
);
366 usage(argv
[0], NULL
);