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 */
37 static int do_mtime
= 0;
40 * Prints differences between real and stored actual metadata
41 * - for use in mentries_compare
44 compare_print(struct metaentry
*real
, struct metaentry
*stored
, int cmp
)
47 msg(MSG_QUIET
, "%s:\tremoved\n", stored
->path
);
52 msg(MSG_QUIET
, "%s:\tadded\n", real
->path
);
56 if (cmp
== DIFF_NONE
) {
57 msg(MSG_DEBUG
, "%s:\tno difference\n", real
->path
);
61 msg(MSG_QUIET
, "%s:\t", real
->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
*real
, struct metaentry
*stored
, int cmp
)
91 if (!real
&& !stored
) {
92 msg(MSG_ERROR
, "%s called with incorrect arguments\n",
98 msg(MSG_NORMAL
, "%s:\tremoved\n", stored
->path
);
103 msg(MSG_NORMAL
, "%s:\tadded\n", real
->path
);
107 if (cmp
== DIFF_NONE
) {
108 msg(MSG_DEBUG
, "%s:\tno difference\n", real
->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", real
->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 real
->path
, real
->group
, stored
->group
);
124 owner
= getpwnam(stored
->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 real
->path
, real
->group
, stored
->group
);
136 group
= getgrnam(stored
->group
);
138 msg(MSG_DEBUG
, "\tgetgrnam failed: %s\n",
145 if (lchown(real
->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 real
->path
, real
->mode
& 07777, stored
->mode
& 07777);
156 if (chmod(real
->path
, stored
->mode
& 07777))
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 real
->path
, real
->mtime
, stored
->mtime
);
163 /* FIXME: Use utimensat here */
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
, msg
);
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 metaentry
*lreal
= NULL
;
239 struct metaentry
*lstored
= 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(&lstored
, METAFILE
);
305 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
311 while (optind
< argc
)
312 mentries_recurse_path(argv
[optind
++], &lreal
);
314 mentries_recurse_path(".", &lreal
);
319 "Failed to load metadata from file system\n");
323 mentries_compare(lreal
, lstored
, compare_print
, do_mtime
);
328 while (optind
< argc
)
329 mentries_recurse_path(argv
[optind
++], &lreal
);
331 mentries_recurse_path(".", &lreal
);
336 "Failed to load metadata from file system\n");
340 mentries_tofile(lreal
, METAFILE
);
344 mentries_fromfile(&lstored
, METAFILE
);
346 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
352 while (optind
< argc
)
353 mentries_recurse_path(argv
[optind
++], &lreal
);
355 mentries_recurse_path(".", &lreal
);
360 "Failed to load metadata from file system\n");
364 mentries_compare(lreal
, lstored
, compare_fix
, do_mtime
);
368 usage(argv
[0], NULL
);