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>
25 #include <attr/xattr.h>
30 #include "metastore.h"
32 #include "metaentry.h"
34 /* Used to signal whether mtimes should be corrected */
35 static int do_mtime
= 0;
38 * Prints differences between real and stored actual metadata
39 * - for use in mentries_compare
42 compare_print(struct metaentry
*real
, struct metaentry
*stored
, int cmp
)
44 if (!real
&& !stored
) {
45 msg(MSG_ERROR
, "%s called with incorrect arguments\n", __FUNCTION__
);
49 if (cmp
== DIFF_NONE
) {
50 msg(MSG_DEBUG
, "%s:\tno difference\n", real
->path
);
54 msg(MSG_QUIET
, "%s:\t", real
? real
->path
: stored
->path
);
57 msg(MSG_QUIET
, "added ", real
->path
);
59 msg(MSG_QUIET
, "removed ", stored
->path
);
61 msg(MSG_QUIET
, "owner ");
63 msg(MSG_QUIET
, "group ");
65 msg(MSG_QUIET
, "mode ");
67 msg(MSG_QUIET
, "type ");
69 msg(MSG_QUIET
, "mtime ");
71 msg(MSG_QUIET
, "xattr ");
76 * Tries to change the real metadata to match the stored one
77 * - for use in mentries_compare
80 compare_fix(struct metaentry
*real
, struct metaentry
*stored
, int cmp
)
89 if (!real
&& !stored
) {
90 msg(MSG_ERROR
, "%s called with incorrect arguments\n",
96 msg(MSG_NORMAL
, "%s:\tremoved\n", stored
->path
);
101 msg(MSG_NORMAL
, "%s:\tadded\n", real
->path
);
105 if (cmp
== DIFF_NONE
) {
106 msg(MSG_DEBUG
, "%s:\tno difference\n", real
->path
);
110 if (cmp
& DIFF_TYPE
) {
111 msg(MSG_NORMAL
, "%s:\tnew type, will not change metadata\n",
116 msg(MSG_QUIET
, "%s:\tchanging metadata\n", real
->path
);
118 while (cmp
& (DIFF_OWNER
| DIFF_GROUP
)) {
119 if (cmp
& DIFF_OWNER
) {
120 msg(MSG_NORMAL
, "\tchanging owner from %s to %s\n",
121 real
->path
, real
->group
, stored
->group
);
122 owner
= xgetpwnam(stored
->owner
);
124 msg(MSG_DEBUG
, "\tgetpwnam failed: %s\n",
131 if (cmp
& DIFF_GROUP
) {
132 msg(MSG_NORMAL
, "\tchanging group from %s to %s\n",
133 real
->path
, real
->group
, stored
->group
);
134 group
= xgetgrnam(stored
->group
);
136 msg(MSG_DEBUG
, "\tgetgrnam failed: %s\n",
143 if (lchown(real
->path
, uid
, gid
)) {
144 msg(MSG_DEBUG
, "\tlchown failed: %s\n",
151 if (cmp
& DIFF_MODE
) {
152 msg(MSG_NORMAL
, "%s:\tchanging mode from 0%o to 0%o\n",
153 real
->path
, real
->mode
& 07777, stored
->mode
& 07777);
154 if (chmod(real
->path
, stored
->mode
& 07777))
155 msg(MSG_DEBUG
, "\tchmod failed: %s\n", strerror(errno
));
158 /* FIXME: Use utimensat here, or even better - lutimensat */
159 if ((cmp
& DIFF_MTIME
) && S_ISLNK(real
->mode
)) {
160 msg(MSG_NORMAL
, "%s:\tsymlink, not changing mtime\n", real
->path
);
161 } else if (cmp
& DIFF_MTIME
) {
162 msg(MSG_NORMAL
, "%s:\tchanging mtime from %ld to %ld\n",
163 real
->path
, real
->mtime
, stored
->mtime
);
164 tbuf
.actime
= stored
->mtime
;
165 tbuf
.modtime
= stored
->mtime
;
166 if (utime(real
->path
, &tbuf
)) {
167 msg(MSG_DEBUG
, "\tutime failed: %s\n", strerror(errno
));
172 if (cmp
& DIFF_XATTR
) {
173 for (i
= 0; i
< real
->xattrs
; i
++) {
174 /* Any attrs to remove? */
175 if (mentry_find_xattr(stored
, real
, i
) >= 0)
178 msg(MSG_NORMAL
, "%s:\tremoving xattr %s\n",
179 real
->path
, real
->xattr_names
[i
]);
180 if (lremovexattr(real
->path
, real
->xattr_names
[i
]))
181 msg(MSG_DEBUG
, "\tlremovexattr failed: %s\n",
185 for (i
= 0; i
< stored
->xattrs
; i
++) {
186 /* Any xattrs to add? (on change they are removed above) */
187 if (mentry_find_xattr(real
, stored
, i
) >= 0)
190 msg(MSG_NORMAL
, "%s:\tadding xattr %s\n",
191 stored
->path
, stored
->xattr_names
[i
]);
192 if (lsetxattr(stored
->path
, stored
->xattr_names
[i
],
193 stored
->xattr_values
[i
],
194 stored
->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
, message
);
207 msg(MSG_CRITICAL
, "Usage: %s ACTION [OPTION...] [PATH...]\n\n", arg0
);
208 msg(MSG_CRITICAL
, "Where ACTION is one of:\n"
209 " -c, --compare\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"
216 " -m, --mtime\tAlso take mtime into account for diff or apply\n");
218 exit(message
? EXIT_FAILURE
: EXIT_SUCCESS
);
222 static struct option long_options
[] = {
223 {"compare", 0, 0, 0},
227 {"verbose", 0, 0, 0},
235 main(int argc
, char **argv
, char **envp
)
238 struct metahash
*real
= NULL
;
239 struct metahash
*stored
= NULL
;
245 int option_index
= 0;
246 c
= getopt_long(argc
, argv
, "csahvqm",
247 long_options
, &option_index
);
252 if (!strcmp("verbose",
253 long_options
[option_index
].name
)) {
255 } else if (!strcmp("quiet",
256 long_options
[option_index
].name
)) {
257 adjust_verbosity(-1);
258 } else if (!strcmp("mtime",
259 long_options
[option_index
].name
)) {
262 action
|= (1 << option_index
);
267 action
|= ACTION_DIFF
;
271 action
|= ACTION_SAVE
;
275 action
|= ACTION_APPLY
;
279 action
|= ACTION_HELP
;
286 adjust_verbosity(-1);
292 usage(argv
[0], "unknown option");
296 /* Make sure only one action is specified */
298 usage(argv
[0], "incorrect option(s)");
303 mentries_fromfile(&stored
, METAFILE
);
305 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
311 while (optind
< argc
)
312 mentries_recurse_path(argv
[optind
++], &real
);
314 mentries_recurse_path(".", &real
);
319 "Failed to load metadata from file system\n");
323 mentries_compare(real
, stored
, compare_print
, do_mtime
);
328 while (optind
< argc
)
329 mentries_recurse_path(argv
[optind
++], &real
);
331 mentries_recurse_path(".", &real
);
336 "Failed to load metadata from file system\n");
340 mentries_tofile(real
, METAFILE
);
344 mentries_fromfile(&stored
, METAFILE
);
346 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
352 while (optind
< argc
)
353 mentries_recurse_path(argv
[optind
++], &real
);
355 mentries_recurse_path(".", &real
);
360 "Failed to load metadata from file system\n");
364 mentries_compare(real
, stored
, compare_fix
, do_mtime
);
368 usage(argv
[0], NULL
);