Line data Source code
1 : /*
2 : * This file is part of rmlint.
3 : *
4 : * rmlint is free software: you can redistribute it and/or modify
5 : * it under the terms of the GNU General Public License as published by
6 : * the Free Software Foundation, either version 3 of the License, or
7 : * (at your option) any later version.
8 : *
9 : * rmlint is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : * GNU General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU General Public License
15 : * along with rmlint. If not, see <http://www.gnu.org/licenses/>.
16 : *
17 : * Authors:
18 : *
19 : * - Christopher <sahib> Pahl 2010-2014 (https://github.com/sahib)
20 : * - Daniel <SeeSpotRun> T. 2014-2014 (https://github.com/SeeSpotRun)
21 : *
22 : * Hosted on http://github.com/sahib/rmlint
23 : *
24 : */
25 :
26 : #include "../formats.h"
27 : #include "../preprocess.h"
28 :
29 : #include <glib.h>
30 : #include <stdio.h>
31 : #include <string.h>
32 :
33 :
34 : typedef struct RmFmtHandlerShScript {
35 : RmFmtHandler parent;
36 : RmFile *last_original;
37 : RmSession *session;
38 :
39 : bool allow_user_cmd : 1;
40 : bool allow_clone : 1;
41 : bool allow_reflink : 1;
42 : bool allow_symlink : 1;
43 : bool allow_hardlink : 1;
44 : bool allow_remove : 1;
45 :
46 : const char *user_cmd;
47 :
48 : GByteArray *order;
49 : } RmFmtHandlerShScript;
50 :
51 : static const char *SH_SCRIPT_TEMPLATE_HEAD = "#!/bin/sh\n"
52 : "# This file was autowritten by rmlint\n"
53 : "# rmlint was executed from: %s\n"
54 : "# Your command line was: %s\n"
55 : "\n"
56 : "USER='%s'\n"
57 : "GROUP='%s'\n"
58 : "\n"
59 : "# Set to true on -n\n"
60 : "DO_DRY_RUN=\n"
61 : "\n"
62 : "# Set to true on -p\n"
63 : "DO_PARANOID_CHECK=\n"
64 : "\n"
65 : "##################################\n"
66 : "# GENERAL LINT HANDLER FUNCTIONS #\n"
67 : "##################################\n"
68 : "\n"
69 : "\n"
70 : "handle_emptyfile() {\n"
71 : " echo 'Deleting empty file:' \"$1\"\n"
72 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
73 : " rm -f \"$1\"\n"
74 : " fi\n"
75 : "}\n"
76 : "\n"
77 : "handle_emptydir() {\n"
78 : " echo 'Deleting empty directory:' \"$1\"\n"
79 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
80 : " rmdir \"$1\"\n"
81 : " fi\n"
82 : "}\n"
83 : "\n"
84 : "handle_bad_symlink() {\n"
85 : " echo 'Deleting symlink pointing nowhere:' \"$1\"\n"
86 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
87 : " rm -f \"$1\"\n"
88 : " fi\n"
89 : "}\n"
90 : "\n"
91 : "handle_unstripped_binary() {\n"
92 : " echo 'Stripping debug symbols of:' \"$1\"\n"
93 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
94 : " strip -s \"$1\"\n"
95 : " fi\n"
96 : "}\n"
97 : "\n"
98 : "handle_bad_user_id() {\n"
99 : " echo 'chown' \"$USER\" \"$1\"\n"
100 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
101 : " chown \"$USER\" \"$1\"\n"
102 : " fi\n"
103 : "}\n"
104 : "\n"
105 : "handle_bad_group_id() {\n"
106 : " echo 'chgrp' \"$GROUP\" \"$1\"\n"
107 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
108 : " chgrp \"$GROUP\" \"$1\"\n"
109 : " fi\n"
110 : "}\n"
111 : "\n"
112 : "handle_bad_user_and_group_id() {\n"
113 : " echo 'chown' \"$USER:$GROUP\" \"$1\"\n"
114 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
115 : " chown \"$USER:$GROUP\" \"$1\"\n"
116 : " fi\n"
117 : "}\n"
118 : "\n"
119 : "###############################\n"
120 : "# DUPLICATE HANDLER FUNCTIONS #\n"
121 : "###############################\n"
122 : "\n"
123 : "original_check() {\n"
124 : " if [ ! -e \"$2\" ]; then\n"
125 : " echo \"^^^^^^ Error: original has disappeared - cancelling.....\"\n"
126 : " return 1\n"
127 : " fi\n"
128 : "\n"
129 : " if [ ! -e \"$1\" ]; then\n"
130 : " echo \"^^^^^^ Error: duplicate has disappeared - cancelling.....\"\n"
131 : " return 1\n"
132 : " fi\n"
133 : "\n"
134 : " # Check they are not the exact same file (hardlinks allowed):\n"
135 : " if [ \"$1\" = \"$2\" ]; then\n"
136 : " echo \"^^^^^^ Error: original and duplicate point to the *same* path - cancelling.....\"\n"
137 : " return 1\n"
138 : " fi\n"
139 : "\n"
140 : " # Do double-check if requested:\n"
141 : " if [ -z \"$DO_PARANOID_CHECK\" ]; then\n"
142 : " return 0\n"
143 : " else\n"
144 : " if cmp -s \"$1\" \"$2\"; then\n"
145 : " return 0\n"
146 : " else\n"
147 : " echo \"^^^^^^ Error: files no longer identical - cancelling.....\"\n"
148 : " return 1\n"
149 : " fi\n"
150 : " fi\n"
151 : "}\n"
152 : "\n"
153 : "cp_hardlink() {\n"
154 : " echo 'Hardlinking to original:' \"$1\"\n"
155 : " if original_check \"$1\" \"$2\"; then\n"
156 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
157 : " cp --remove-destination --archive --link \"$2\" \"$1\"\n"
158 : " fi\n"
159 : " fi\n"
160 : "}\n"
161 : "\n"
162 : "cp_symlink() {\n"
163 : " echo 'Symlinking to original:' \"$1\"\n"
164 : " if original_check \"$1\" \"$2\"; then\n"
165 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
166 : " touch -mr \"$1\" \"$0\"\n"
167 : " cp --remove-destination --archive --symbolic-link \"$2\" \"$1\"\n"
168 : " touch -mr \"$0\" \"$1\"\n"
169 : " fi\n"
170 : " fi\n"
171 : "}\n"
172 : "\n"
173 : "cp_reflink() {\n"
174 : " # reflink $1 to $2's data, preserving $1's mtime\n"
175 : " echo 'Reflinking to original:' \"$1\"\n"
176 : " if original_check \"$1\" \"$2\"; then\n"
177 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
178 : " touch -mr \"$1\" \"$0\"\n"
179 : " cp --reflink=always \"$2\" \"$1\"\n"
180 : " touch -mr \"$0\" \"$1\"\n"
181 : " fi\n"
182 : " fi\n"
183 : "}\n"
184 : "\n"
185 : "clone() {\n"
186 : " # clone $1 from $2's data\n"
187 : " echo 'Cloning to: ' \"$1\"\n"
188 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
189 : " rmlint --btrfs-clone \"$2\" \"$1\"\n"
190 : " fi\n"
191 : "}\n"
192 : "\n"
193 : "skip_hardlink() {\n"
194 : " echo 'Leaving as-is (already hardlinked to original):' \"$1\"\n"
195 : "}\n"
196 : "\n"
197 : "skip_reflink() {\n"
198 : " echo 'Leaving as-is (already reflinked to original):' \"$1\"\n"
199 : "}\n"
200 : "\n"
201 : "user_command() {\n"
202 : " # You can define this function to do what you want:\n"
203 : " %s\n"
204 : "}\n"
205 : "\n"
206 : "remove_cmd() {\n"
207 : " echo 'Deleting:' \"$1\"\n"
208 : " if original_check \"$1\" \"$2\"; then\n"
209 : " if [ -z \"$DO_DRY_RUN\" ]; then\n"
210 : " rm -rf \"$1\"\n"
211 : " fi\n"
212 : " fi\n"
213 : "}\n"
214 : "\n"
215 : "##################\n"
216 : "# OPTION PARSING #\n"
217 : "##################\n"
218 : "\n"
219 : "ask() {\n"
220 : " cat << EOF\n"
221 : "\n"
222 : "This script will delete certain files rmlint found.\n"
223 : "It is highly advisable to view the script first!\n"
224 : "\n"
225 : "Rmlint was executed in the following way:\n"
226 : "\n"
227 : " $ %s\n"
228 : "\n"
229 : "Execute this script with -d to disable this informational message.\n"
230 : "Type any string to continue; CTRL-C, Enter or CTRL-D to abort immediately\n"
231 : "EOF\n"
232 : " read eof_check\n"
233 : " if [ -z \"$eof_check\" ]\n"
234 : " then\n"
235 : " # Count Ctrl-D and Enter as aborted too.\n"
236 : " echo \"Aborted on behalf of the user.\"\n"
237 : " exit 1;\n"
238 : " fi\n"
239 : "}\n"
240 : "\n"
241 : "usage() {\n"
242 : " cat << EOF\n"
243 : "usage: $0 OPTIONS\n"
244 : "\n"
245 : "OPTIONS:\n"
246 : "\n"
247 : " -h Show this message.\n"
248 : " -d Do not ask before running.\n"
249 : " -x Keep rmlint.sh; do not autodelete it.\n"
250 : " -p Recheck that files are still identical before removing duplicates.\n"
251 : " -n Do not perform any modifications, just print what would be done.\n"
252 : "EOF\n"
253 : "}\n"
254 : "\n"
255 : "DO_REMOVE=\n"
256 : "DO_ASK=\n"
257 : "\n"
258 : "while getopts \"dhxnp\" OPTION\n"
259 : "do\n"
260 : " case $OPTION in\n"
261 : " h)\n"
262 : " usage\n"
263 : " exit 1\n"
264 : " ;;\n"
265 : " d)\n"
266 : " DO_ASK=false\n"
267 : " ;;\n"
268 : " x)\n"
269 : " DO_REMOVE=false\n"
270 : " ;;\n"
271 : " n)\n"
272 : " DO_DRY_RUN=true\n"
273 : " ;;\n"
274 : " p)\n"
275 : " DO_PARANOID_CHECK=true\n"
276 : " esac\n"
277 : "done\n"
278 : "\n"
279 : "if [ -z $DO_ASK ]\n"
280 : "then\n"
281 : " usage\n"
282 : " ask\n"
283 : "fi\n"
284 : "\n"
285 : "######### START OF AUTOGENERATED OUTPUT #########\n"
286 : "\n"
287 : "";
288 : static const char *SH_SCRIPT_TEMPLATE_FOOT =
289 : " \n"
290 : "######### END OF AUTOGENERATED OUTPUT #########\n"
291 : " \n"
292 : "if [ -z $DO_REMOVE ] && [ -z $DO_DRY_RUN ] \n"
293 : "then \n"
294 : " echo \"Deleting script \" \"$0\" \n"
295 : " %s '%s'; \n"
296 : "fi \n"
297 : ;
298 :
299 : typedef bool (* RmShOrderEmitFunc)(RmFmtHandlerShScript *self, char **out, RmFile *file, char *path, char *orig_path);
300 :
301 :
302 176 : static bool rm_sh_emit_handler_user(RmFmtHandlerShScript *self, char **out, _U RmFile *file, char *path, char *orig_path) {
303 176 : if(self->user_cmd == NULL || !self->allow_user_cmd) {
304 176 : return false;
305 : }
306 :
307 0 : *out = g_strdup_printf("user_command '%s' '%s'", path, orig_path);
308 0 : return true;
309 : }
310 :
311 0 : static bool rm_sh_emit_handler_clone(RmFmtHandlerShScript *self, char **out, RmFile *file, char *path, char *orig_path) {
312 0 : if(!self->allow_clone) {
313 0 : return false;
314 : }
315 :
316 : /* Needs to have at least kernel 4.2 */
317 0 : if(!rm_session_check_kernel_version(self->session, 4, 2)) {
318 0 : return false;
319 : }
320 :
321 0 : bool offsets_match = rm_offsets_match(path, orig_path);
322 0 : char *reflink_type = g_hash_table_lookup(
323 0 : self->session->mounts->reflinkfs_table,
324 0 : GUINT_TO_POINTER(file->dev)
325 : );
326 :
327 0 : if (offsets_match) {
328 0 : *out = g_strdup_printf("skip_reflink '%s' '%s'", path, orig_path);
329 0 : } else if(!g_strcmp0("btrfs", reflink_type)) {
330 0 : *out = g_strdup_printf("clone '%s' '%s'", path, orig_path);
331 : } else {
332 0 : return false;
333 : }
334 :
335 0 : return true;
336 : }
337 :
338 0 : static bool rm_sh_emit_handler_reflink(RmFmtHandlerShScript *self, char **out, RmFile *file, char *path, char *orig_path) {
339 0 : if(!self->allow_reflink || !rm_mounts_can_reflink(self->session->mounts, self->last_original->dev, file->dev)) {
340 0 : return false;
341 : }
342 :
343 0 : if (rm_offsets_match(path, orig_path)) {
344 0 : *out = g_strdup_printf("skip_reflink '%s' '%s'", path, orig_path);
345 : } else {
346 0 : *out = g_strdup_printf("cp_reflink '%s' '%s'", path, orig_path);
347 : }
348 0 : return true;
349 : }
350 :
351 0 : static bool rm_sh_emit_handler_symlink(RmFmtHandlerShScript *self, char **out, RmFile *file, char *path, char *orig_path) {
352 0 : if(!self->allow_symlink || self->last_original->dev != file->dev) {
353 0 : return false;
354 : }
355 :
356 0 : *out = g_strdup_printf("cp_symlink '%s' '%s'", path, orig_path);
357 0 : return true;
358 : }
359 :
360 0 : static bool rm_sh_emit_handler_hardlink(RmFmtHandlerShScript *self, char **out, _U RmFile *file, char *path, char *orig_path) {
361 0 : if(!self->allow_hardlink) {
362 0 : return false;
363 : }
364 :
365 0 : if (self->last_original && file->hardlinks.hardlink_head == self->last_original) {
366 0 : *out = g_strdup_printf("skip_hardlink '%s' '%s'", path, orig_path);
367 : } else {
368 0 : *out = g_strdup_printf("cp_hardlink '%s' '%s'", path, orig_path);
369 : }
370 0 : return true;
371 : }
372 :
373 176 : static bool rm_sh_emit_handler_remove(RmFmtHandlerShScript *self, char **out, _U RmFile *file, char *path, char *orig_path) {
374 176 : if(!self->allow_remove) {
375 0 : return false;
376 : }
377 :
378 176 : *out = g_strdup_printf("remove_cmd '%s' '%s'", path, orig_path);
379 176 : return true;
380 : }
381 :
382 : typedef enum RmShHandler {
383 : RM_SH_HANDLER_UNKNOWN = 0,
384 : RM_SH_HANDLER_USER_COMMAND,
385 : RM_SH_HANDLER_CLONE,
386 : RM_SH_HANDLER_REFLINK,
387 : RM_SH_HANDLER_SYMLINK,
388 : RM_SH_HANDLER_HARDLINK,
389 : RM_SH_HANDLER_REMOVE,
390 : RM_SH_HANDLER_N
391 : } RmShHandler;
392 :
393 : static const char *ORDER_TO_STRING[] = {
394 : [RM_SH_HANDLER_UNKNOWN] = NULL,
395 : [RM_SH_HANDLER_USER_COMMAND] = "cmd",
396 : [RM_SH_HANDLER_CLONE] = "clone",
397 : [RM_SH_HANDLER_REFLINK] = "reflink",
398 : [RM_SH_HANDLER_SYMLINK] = "symlink",
399 : [RM_SH_HANDLER_HARDLINK] = "hardlink",
400 : [RM_SH_HANDLER_REMOVE] = "remove",
401 : [RM_SH_HANDLER_N] = NULL
402 : };
403 :
404 : static const RmShOrderEmitFunc ORDER_TO_FUNC[] = {
405 : [RM_SH_HANDLER_UNKNOWN] = NULL,
406 : [RM_SH_HANDLER_USER_COMMAND] = rm_sh_emit_handler_user,
407 : [RM_SH_HANDLER_CLONE] = rm_sh_emit_handler_clone,
408 : [RM_SH_HANDLER_REFLINK] = rm_sh_emit_handler_reflink,
409 : [RM_SH_HANDLER_SYMLINK] = rm_sh_emit_handler_symlink,
410 : [RM_SH_HANDLER_HARDLINK] = rm_sh_emit_handler_hardlink,
411 : [RM_SH_HANDLER_REMOVE] = rm_sh_emit_handler_remove
412 : };
413 :
414 124 : static void rm_sh_parse_handlers(RmFmtHandlerShScript *self, const char *handler_cfg) {
415 124 : self->order = g_byte_array_new();
416 :
417 124 : char **order_vec = g_strsplit(handler_cfg, ",", -1);
418 372 : for(int i = 0; order_vec && order_vec[i]; ++i) {
419 248 : bool found = false;
420 1116 : for(RmShHandler n = 0; n < RM_SH_HANDLER_N; ++n) {
421 1116 : if(ORDER_TO_STRING[n] == NULL) {
422 248 : continue;
423 : }
424 :
425 868 : if(strcasecmp(order_vec[i], ORDER_TO_STRING[n]) == 0) {
426 248 : switch(n) {
427 : case RM_SH_HANDLER_USER_COMMAND:
428 124 : self->allow_user_cmd = true;
429 124 : break;
430 : case RM_SH_HANDLER_CLONE:
431 0 : self->allow_clone = true;
432 0 : break;
433 : case RM_SH_HANDLER_REFLINK:
434 0 : self->allow_reflink = true;
435 0 : break;
436 : case RM_SH_HANDLER_SYMLINK:
437 0 : self->allow_symlink = true;
438 0 : break;
439 : case RM_SH_HANDLER_HARDLINK:
440 0 : self->allow_hardlink = true;
441 0 : break;
442 : case RM_SH_HANDLER_REMOVE:
443 124 : self->allow_remove = true;
444 124 : break;
445 : default:
446 0 : g_assert_not_reached();
447 : }
448 :
449 : /* we found the id */
450 248 : g_byte_array_append(self->order, (guint8 *)&n, 1);
451 248 : found = true;
452 248 : break;
453 : }
454 : }
455 :
456 248 : if(!found) {
457 0 : rm_log_error_line(_("%s is an invalid handler."), order_vec[i]);
458 : }
459 : }
460 :
461 124 : g_strfreev(order_vec);
462 124 : }
463 :
464 124 : static void rm_fmt_head(RmSession *session, RmFmtHandler *parent, FILE *out) {
465 124 : RmFmtHandlerShScript *self = (RmFmtHandlerShScript *)parent;
466 124 : char *script_header = NULL;
467 :
468 124 : self->session = session;
469 124 : self->user_cmd = rm_fmt_get_config_value(session->formats, "sh", "cmd");
470 :
471 124 : const char *handler_cfg = rm_fmt_get_config_value(session->formats, "sh", "handler");
472 124 : if(handler_cfg != NULL) {
473 : /* user specified handlers */
474 0 : rm_sh_parse_handlers(self, handler_cfg);
475 124 : } else if(rm_fmt_get_config_value(session->formats, "sh", "link") != NULL) {
476 : /* Preset: try reflinks, then symlinks then hardlinks */
477 0 : rm_sh_parse_handlers(self, "clone,reflink,hardlink,symlink");
478 124 : } else if(rm_fmt_get_config_value(session->formats, "sh", "hardlink") != NULL) {
479 : /* Preset: try symlinks before using hardlinks */
480 0 : rm_sh_parse_handlers(self, "hardlink,symlink");
481 124 : } else if(rm_fmt_get_config_value(session->formats, "sh", "symlink") != NULL) {
482 : /* Preset: only do hardlinks */
483 0 : rm_sh_parse_handlers(self, "symlink");
484 : } else {
485 : /* Default: remove the file */
486 124 : rm_sh_parse_handlers(self, "cmd,remove");
487 : }
488 :
489 124 : if(fchmod(fileno(out), S_IRUSR | S_IWUSR | S_IXUSR) == -1) {
490 0 : rm_log_perror("Could not chmod +x sh script");
491 : }
492 :
493 : /* Fill in all placeholders in the script template */
494 744 : fprintf(
495 : out, SH_SCRIPT_TEMPLATE_HEAD,
496 124 : session->cfg->iwd,
497 248 : (session->cfg->joined_argv) ? (session->cfg->joined_argv) : "[unknown]",
498 : rm_util_get_username(),
499 : rm_util_get_groupname(),
500 124 : (self->user_cmd) ? self->user_cmd : "echo 'no user command defined.'",
501 248 : (session->cfg->joined_argv) ? (session->cfg->joined_argv) : "unknown_commandline"
502 : );
503 :
504 124 : g_free(script_header);
505 124 : }
506 :
507 948 : static char *rm_fmt_sh_escape_path(char *path) {
508 : /* See http://stackoverflow.com/questions/1250079/bash-escaping-single-quotes-inside-of-single-quoted-strings
509 : * for more info on this
510 : * */
511 948 : return rm_util_strsub(path, "'", "'\"'\"'");
512 : }
513 :
514 296 : static void rm_fmt_write_duplicate(RmFmtHandlerShScript *self, FILE *out, RmFile *file) {
515 296 : bool is_dir = (file->lint_type == RM_LINT_TYPE_DUPE_DIR_CANDIDATE);
516 :
517 296 : RM_DEFINE_PATH(file);
518 :
519 296 : char *path = rm_fmt_sh_escape_path(file_path);
520 296 : char *prefix = NULL;
521 296 : const char *comment = NULL;
522 :
523 296 : if(file->is_original) {
524 120 : if(is_dir) {
525 28 : comment = "# original directory";
526 : } else {
527 92 : comment = "# original";
528 : }
529 :
530 120 : prefix = g_strdup_printf("echo 'Keeping: ' '%s'", path);
531 120 : self->last_original = file;
532 176 : } else if(self->last_original) {
533 :
534 176 : RmFile *last_original = self->last_original;
535 176 : RM_DEFINE_PATH(last_original);
536 :
537 176 : char *orig_path = rm_fmt_sh_escape_path(last_original_path);
538 176 : if(is_dir) {
539 28 : comment = "# duplicate directory";
540 : } else {
541 148 : comment = "# duplicate";
542 : }
543 :
544 352 : for(gsize n = 0; n < self->order->len; ++n) {
545 352 : RmShOrderEmitFunc func = ORDER_TO_FUNC[self->order->data[n]];
546 352 : if(func == NULL) {
547 0 : rm_log_error_line("null-func in sh formatter. Should not happen.");
548 0 : continue;
549 : }
550 :
551 352 : if(func(self, &prefix, file, path, orig_path) && prefix) {
552 176 : break;
553 : }
554 : }
555 :
556 176 : g_free(orig_path);
557 : }
558 :
559 296 : if(prefix != NULL) {
560 296 : fprintf(out, "%s %s\n", prefix, comment);
561 296 : g_free(prefix);
562 : }
563 :
564 296 : g_free(path);
565 296 : }
566 :
567 352 : static void rm_fmt_elem(_U RmSession *session, _U RmFmtHandler *parent, FILE *out, RmFile *file) {
568 352 : RmFmtHandlerShScript *self = (RmFmtHandlerShScript *)parent;
569 352 : if(file->lint_type == RM_LINT_TYPE_UNFINISHED_CKSUM) {
570 0 : return;
571 : }
572 :
573 352 : RM_DEFINE_PATH(file);
574 352 : char *path = rm_fmt_sh_escape_path(file_path);
575 :
576 352 : switch(file->lint_type) {
577 : case RM_LINT_TYPE_EMPTY_DIR:
578 0 : fprintf(out, "handle_emptydir '%s' # empty folder\n", path);
579 0 : break;
580 : case RM_LINT_TYPE_EMPTY_FILE:
581 28 : fprintf(out, "handle_emptyfile '%s' # empty file\n", path);
582 28 : break;
583 : case RM_LINT_TYPE_BADLINK:
584 28 : fprintf(out, "handle_bad_symlink '%s' # bad symlink pointing nowhere\n", path);
585 28 : break;
586 : case RM_LINT_TYPE_NONSTRIPPED:
587 0 : fprintf(out, "handle_unstripped_binary '%s' # binary with debugsymbols\n", path);
588 0 : break;
589 : case RM_LINT_TYPE_BADUID:
590 0 : fprintf(out, "handle_bad_user_id '%s' # bad uid\n", path);
591 0 : break;
592 : case RM_LINT_TYPE_BADGID:
593 0 : fprintf(out, "handle_bad_group_id '%s' # bad gid\n", path);
594 0 : break;
595 : case RM_LINT_TYPE_BADUGID:
596 0 : fprintf(out, "handle_bad_user_and_group_id '%s' # bad gid\n", path);
597 0 : break;
598 : case RM_LINT_TYPE_DUPE_DIR_CANDIDATE:
599 : case RM_LINT_TYPE_DUPE_CANDIDATE:
600 296 : rm_fmt_write_duplicate(self, out, file);
601 296 : break;
602 : default:
603 0 : rm_log_warning("Warning: unknown type in encountered: %d\n", file->lint_type);
604 0 : break;
605 : }
606 :
607 352 : g_free(path);
608 : }
609 :
610 124 : static void rm_fmt_foot(_U RmSession *session, RmFmtHandler *parent, FILE *out) {
611 124 : RmFmtHandlerShScript *self = (RmFmtHandlerShScript *)parent;
612 124 : g_byte_array_free(self->order, true);
613 :
614 124 : if(rm_fmt_is_stream(session->formats, parent)) {
615 : /* You will have a hard time deleting standard streams. */
616 0 : return;
617 : }
618 :
619 124 : char *escaped_path = rm_fmt_sh_escape_path(parent->path);
620 124 : fprintf(out, SH_SCRIPT_TEMPLATE_FOOT, "rm -f", escaped_path);
621 124 : g_free(escaped_path);
622 : }
623 :
624 : static RmFmtHandlerShScript SH_SCRIPT_HANDLER_IMPL = {
625 : .parent = {
626 : .size = sizeof(SH_SCRIPT_HANDLER_IMPL),
627 : .name = "sh",
628 : .head = rm_fmt_head,
629 : .elem = rm_fmt_elem,
630 : .prog = NULL,
631 : .foot = rm_fmt_foot,
632 : .valid_keys = {"handler", "cmd", "link", "hardlink", "symlink", NULL},
633 : },
634 : .last_original = NULL
635 : };
636 :
637 : RmFmtHandler *SH_SCRIPT_HANDLER = (RmFmtHandler *) &SH_SCRIPT_HANDLER_IMPL;
|