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 /* FIXME: Use utimensat here, or even better - lutimensat */
161 if ((cmp
& DIFF_MTIME
) && S_ISLNK(real
->mode
)) {
162 msg(MSG_NORMAL
, "%s:\tsymlink, not changing mtime", real
->path
);
163 } else if (cmp
& DIFF_MTIME
) {
164 msg(MSG_NORMAL
, "%s:\tchanging mtime from %ld to %ld\n",
165 real
->path
, real
->mtime
, stored
->mtime
);
166 tbuf
.actime
= stored
->mtime
;
167 tbuf
.modtime
= stored
->mtime
;
168 if (utime(real
->path
, &tbuf
)) {
169 msg(MSG_DEBUG
, "\tutime failed: %s\n", strerror(errno
));
174 if (cmp
& DIFF_XATTR
) {
175 for (i
= 0; i
< real
->xattrs
; i
++) {
176 /* Any attrs to remove? */
177 if (mentry_find_xattr(stored
, real
, i
) >= 0)
180 msg(MSG_NORMAL
, "%s:\tremoving xattr %s\n",
181 real
->path
, real
->xattr_names
[i
]);
182 if (lremovexattr(real
->path
, real
->xattr_names
[i
]))
183 msg(MSG_DEBUG
, "\tlremovexattr failed: %s\n",
187 for (i
= 0; i
< stored
->xattrs
; i
++) {
188 /* Any xattrs to add? (on change they are removed above) */
189 if (mentry_find_xattr(real
, stored
, i
) >= 0)
192 msg(MSG_NORMAL
, "%s:\tadding xattr %s\n",
193 stored
->path
, stored
->xattr_names
[i
]);
194 if (lsetxattr(stored
->path
, stored
->xattr_names
[i
],
195 stored
->xattr_values
[i
],
196 stored
->xattr_lvalues
[i
], XATTR_CREATE
))
197 msg(MSG_DEBUG
, "\tlsetxattr failed: %s\n",
203 /* Prints usage message and exits */
205 usage(const char *arg0
, const char *message
)
208 msg(MSG_CRITICAL
, "%s: %s\n\n", arg0
, msg
);
209 msg(MSG_CRITICAL
, "Usage: %s ACTION [OPTION...] [PATH...]\n\n", arg0
);
210 msg(MSG_CRITICAL
, "Where ACTION is one of:\n"
211 " -c, --compare\tShow differences between stored and real metadata\n"
212 " -s, --save\tSave current metadata\n"
213 " -a, --apply\tApply stored metadata\n"
214 " -h, --help\tHelp message (this text)\n\n"
215 "Valid OPTIONS are (can be given more than once):\n"
216 " -v, --verbose\tPrint more verbose messages\n"
217 " -q, --quiet\tPrint less verbose messages\n"
218 " -m, --mtime\tAlso take mtime into account for diff or apply\n");
220 exit(message
? EXIT_FAILURE
: EXIT_SUCCESS
);
224 static struct option long_options
[] = {
225 {"compare", 0, 0, 0},
229 {"verbose", 0, 0, 0},
237 main(int argc
, char **argv
, char **envp
)
240 struct metaentry
*lreal
= NULL
;
241 struct metaentry
*lstored
= NULL
;
247 int option_index
= 0;
248 c
= getopt_long(argc
, argv
, "csahvqm",
249 long_options
, &option_index
);
254 if (!strcmp("verbose",
255 long_options
[option_index
].name
)) {
257 } else if (!strcmp("quiet",
258 long_options
[option_index
].name
)) {
259 adjust_verbosity(-1);
260 } else if (!strcmp("mtime",
261 long_options
[option_index
].name
)) {
264 action
|= (1 << option_index
);
269 action
|= ACTION_DIFF
;
273 action
|= ACTION_SAVE
;
277 action
|= ACTION_APPLY
;
281 action
|= ACTION_HELP
;
288 adjust_verbosity(-1);
294 usage(argv
[0], "unknown option");
298 /* Make sure only one action is specified */
300 usage(argv
[0], "incorrect option(s)");
305 mentries_fromfile(&lstored
, METAFILE
);
307 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
313 while (optind
< argc
)
314 mentries_recurse_path(argv
[optind
++], &lreal
);
316 mentries_recurse_path(".", &lreal
);
321 "Failed to load metadata from file system\n");
325 mentries_compare(lreal
, lstored
, compare_print
, do_mtime
);
330 while (optind
< argc
)
331 mentries_recurse_path(argv
[optind
++], &lreal
);
333 mentries_recurse_path(".", &lreal
);
338 "Failed to load metadata from file system\n");
342 mentries_tofile(lreal
, METAFILE
);
346 mentries_fromfile(&lstored
, METAFILE
);
348 msg(MSG_CRITICAL
, "Failed to load metadata from %s\n",
354 while (optind
< argc
)
355 mentries_recurse_path(argv
[optind
++], &lreal
);
357 mentries_recurse_path(".", &lreal
);
362 "Failed to load metadata from file system\n");
366 mentries_compare(lreal
, lstored
, compare_fix
, do_mtime
);
370 usage(argv
[0], NULL
);