1 /* exec.c -- functions controlling the execution of programs */
2
3 /*
4 * This file is part of CliFM
5 *
6 * Copyright (C) 2016-2021, L. Abramovich <johndoe.arch@outlook.com>
7 * All rights reserved.
8
9 * CliFM is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * CliFM is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA.
23 */
24
25 #include "helpers.h"
26 #ifdef __OpenBSD__
27 #include <sys/dirent.h>
28 #endif
29 #include <dirent.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <sys/wait.h>
36 #include <unistd.h>
37 #include <readline/readline.h>
38 #include <limits.h>
39
40 #include "actions.h"
41 #ifndef _NO_ARCHIVING
42 #include "archives.h"
43 #endif
44 #include "aux.h"
45 #include "bookmarks.h"
46 #include "checks.h"
47 #include "colors.h"
48 #include "config.h"
49 #include "exec.h"
50 #include "file_operations.h"
51 #include "history.h"
52 #include "init.h"
53 #include "jump.h"
54 #include "keybinds.h"
55 #include "listing.h"
56 #include "mime.h"
57 #include "misc.h"
58 #include "navigation.h"
59 #include "profiles.h"
60 #include "properties.h"
61 #include "readline.h"
62 #include "remotes.h"
63 #include "search.h"
64 #include "selection.h"
65 #include "sort.h"
66 #include "strings.h"
67 #ifndef _NO_TRASH
68 #include "trash.h"
69 #endif
70 #include "messages.h"
71 #include "media.h"
72 #ifndef _NO_BLEACH
73 #include "name_cleaner.h"
74 #endif
75
76 char **_comm = (char **)NULL;
77
78 static char *
get_new_name(void)79 get_new_name(void)
80 {
81 char *input = (char *)NULL;
82
83 rl_nohist = 1;
84
85 char m[NAME_MAX];
86 sprintf(m, "Enter new name ('q' to quit)\n%s>%s ", mi_c, tx_c);
87 while (!input && _xrename) {
88 input = readline(m);
89 if (!input)
90 continue;
91 if (!*input || *input == ' ') {
92 free(input);
93 input = (char *)NULL;
94 continue;
95 }
96
97 if (*input == 'q' && !*(input + 1)) {
98 free(input);
99 input = (char *)NULL;
100 break;
101 }
102 }
103
104 rl_nohist = 0;
105 return input;
106 }
107
108 /* Run a command via execle() and refresh the screen in case of success */
109 int
run_and_refresh(char ** cmd)110 run_and_refresh(char **cmd)
111 {
112 if (!cmd)
113 return EXIT_FAILURE;
114
115 log_function(cmd);
116
117 size_t i = 0, total_len = 0;
118 for (; i <= args_n; i++)
119 total_len += strlen(cmd[i]);
120
121 char *tmp_cmd = (char *)NULL;
122 tmp_cmd = (char *)xcalloc(total_len + (i + 1) + 1, sizeof(char));
123
124 for (i = 0; i <= args_n; i++) {
125 strcat(tmp_cmd, cmd[i]);
126 strcat(tmp_cmd, " ");
127 }
128
129 if (xrename) {
130 /* If we have a number here, it was not expanded by parse_input_str,
131 * and thereby, we have an invalid ELN */
132 if (is_number(cmd[1])) {
133 fprintf(stderr, "%s: %s: Invalid ELN\n", PROGRAM_NAME, cmd[1]);
134 free(tmp_cmd);
135 xrename = 0;
136 return EXIT_FAILURE;
137 }
138 _xrename = 1;
139 char *new_name = get_new_name();
140 _xrename = 0;
141 if (!new_name) {
142 free(tmp_cmd);
143 return EXIT_SUCCESS;
144 }
145 char *enn = (char *)NULL;
146 if (!strchr(new_name, '\\')) {
147 enn = escape_str(new_name);
148 if (!enn) {
149 free(tmp_cmd);
150 fprintf(stderr, "%s: %s: Error escaping string\n", PROGRAM_NAME, new_name);
151 return EXIT_FAILURE;
152 }
153 }
154 tmp_cmd = (char *)xrealloc(tmp_cmd,
155 (total_len + (i + 1) + 1 + strlen(enn ? enn : new_name))
156 * sizeof(char));
157 strcat(tmp_cmd, enn ? enn : new_name);
158
159 free(new_name);
160 free(enn);
161 }
162
163 int ret = launch_execle(tmp_cmd);
164 free(tmp_cmd);
165
166 if (ret != EXIT_SUCCESS)
167 return EXIT_FAILURE;
168 /* Error messages will be printed by launch_execve() itself */
169
170 /* If 'rm sel' and command is successful, deselect everything */
171 if (is_sel && *cmd[0] == 'r' && cmd[0][1] == 'm' && (!cmd[0][2]
172 || cmd[0][2] == ' ')) {
173 int j = (int)sel_n;
174 while (--j >= 0)
175 free(sel_elements[j]);
176 sel_n = 0;
177 save_sel();
178 }
179
180 #ifdef __HAIKU__
181 if (autols && cmd[1] && strcmp(cmd[1], "--help") != 0
182 && strcmp(cmd[1], "--version") != 0) {
183 free_dirlist();
184 list_dir();
185 }
186 #endif
187
188 return EXIT_SUCCESS;
189 }
190
191 static int
run_in_foreground(pid_t pid)192 run_in_foreground(pid_t pid)
193 {
194 int status = 0;
195
196 /* The parent process calls waitpid() on the child */
197 if (waitpid(pid, &status, 0) > 0) {
198 if (WIFEXITED(status) && !WEXITSTATUS(status)) {
199 /* The program terminated normally and executed successfully
200 * (WEXITSTATUS(status) == 0) */
201 return EXIT_SUCCESS;
202 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
203 /* Program terminated normally, but returned a
204 * non-zero status. Error codes should be printed by the
205 * program itself */
206 return WEXITSTATUS(status);
207 } else {
208 /* The program didn't terminate normally. In this case too,
209 * error codes should be printed by the program */
210 return EXCRASHERR;
211 }
212 } else {
213 /* waitpid() failed */
214 fprintf(stderr, "%s: waitpid: %s\n", PROGRAM_NAME,
215 strerror(errno));
216 return errno;
217 }
218
219 return EXIT_FAILURE; /* Never reached */
220 }
221
222 static void
run_in_background(pid_t pid)223 run_in_background(pid_t pid)
224 {
225 int status = 0;
226 /* Keep it in the background */
227 waitpid(pid, &status, WNOHANG); /* or: kill(pid, SIGCONT); */
228 }
229
230 /* Execute a command using the system shell (/bin/sh), which takes care
231 * of special functions such as pipes and stream redirection, and special
232 * chars like wildcards, quotes, and escape sequences. Use only when the
233 * shell is needed; otherwise, launch_execve() should be used instead. */
234 int
launch_execle(const char * cmd)235 launch_execle(const char *cmd)
236 {
237 if (!cmd || !*cmd)
238 return EXNULLERR;
239
240 int ret = system(cmd);
241 if (WIFEXITED(ret) && !WEXITSTATUS(ret))
242 return EXIT_SUCCESS;
243 if (WIFEXITED(ret) && WEXITSTATUS(ret))
244 return WEXITSTATUS(ret);
245 return EXCRASHERR;
246 /*
247 // Reenable SIGCHLD, in case it was disabled. Otherwise, waitpid won't
248 // be able to catch error codes coming from the child
249 signal(SIGCHLD, SIG_DFL);
250
251 int status;
252 pid_t pid = fork();
253 if (pid < 0) {
254 fprintf(stderr, "%s: fork: %s\n", PROGRAM_NAME, strerror(errno));
255 return EXFORKERR;
256 } else if (pid == 0) {
257 // Reenable signals only for the child, in case they were
258 // disabled for the parent
259 signal(SIGHUP, SIG_DFL);
260 signal(SIGINT, SIG_DFL);
261 signal(SIGQUIT, SIG_DFL);
262 signal(SIGTERM, SIG_DFL);
263
264 // Get shell base name
265 char *name = strrchr(user.shell, '/');
266
267 execl(user.shell, name ? name + 1 : user.shell, "-c", cmd, NULL);
268 fprintf(stderr, "%s: %s: execle: %s\n", PROGRAM_NAME, user.shell,
269 strerror(errno));
270 _exit(errno);
271 }
272 // Get command status
273 else {
274 // The parent process calls waitpid() on the child
275 if (waitpid(pid, &status, 0) > 0) {
276 if (WIFEXITED(status) && !WEXITSTATUS(status)) {
277 // The program terminated normally and executed
278 // successfully
279 return EXIT_SUCCESS;
280 } else if (WIFEXITED(status) && WEXITSTATUS(status)) {
281 // Either "command not found" (WEXITSTATUS(status) == 127),
282 // "permission denied" (not executable) (WEXITSTATUS(status) ==
283 // 126) or the program terminated normally, but returned a
284 // non-zero status. These exit codes will be handled by the
285 // system shell itself, since we're using here execle()
286 return WEXITSTATUS(status);
287 } else {
288 // The program didn't terminate normally
289 return EXCRASHERR;
290 }
291 } else {
292 // Waitpid() failed
293 fprintf(stderr, "%s: waitpid: %s\n", PROGRAM_NAME,
294 strerror(errno));
295 return errno;
296 }
297 }
298
299 // Never reached
300 return EXIT_FAILURE; */
301 }
302
303 /* Execute a command and return the corresponding exit status. The exit
304 * status could be: zero, if everything went fine, or a non-zero value
305 * in case of error. The function takes as first arguement an array of
306 * strings containing the command name to be executed and its arguments
307 * (cmd), an integer (bg) specifying if the command should be
308 * backgrounded (1) or not (0), and a flag to control file descriptors */
309 int
launch_execve(char ** cmd,int bg,int xflags)310 launch_execve(char **cmd, int bg, int xflags)
311 {
312 if (!cmd)
313 return EXNULLERR;
314
315 /* Reenable SIGCHLD, in case it was disabled. Otherwise, waitpid
316 * won't be able to catch error codes coming from the child. */
317 signal(SIGCHLD, SIG_DFL);
318
319 pid_t pid = fork();
320 if (pid < 0) {
321 fprintf(stderr, "%s: fork: %s\n", PROGRAM_NAME, strerror(errno));
322 return errno;
323 } else if (pid == 0) {
324 if (!bg) {
325 /* If the program runs in the foreground, reenable signals
326 * only for the child, in case they were disabled for the
327 * parent */
328 signal(SIGHUP, SIG_DFL);
329 signal(SIGINT, SIG_DFL);
330 signal(SIGQUIT, SIG_DFL);
331 signal(SIGTERM, SIG_DFL);
332 }
333
334 if (xflags) {
335 int fd = open("/dev/null", O_WRONLY, 0200);
336
337 if (xflags & E_NOSTDIN)
338 dup2(fd, STDIN_FILENO);
339
340 if (xflags & E_NOSTDOUT)
341 dup2(fd, STDOUT_FILENO);
342
343 if (xflags & E_NOSTDERR)
344 dup2(fd, STDERR_FILENO);
345
346 close(fd);
347 }
348
349 execvp(cmd[0], cmd);
350 fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, cmd[0],
351 strerror(errno));
352 _exit(errno);
353 }
354
355 /* Get command status (pid > 0) */
356 else {
357 if (bg) {
358 run_in_background(pid);
359 return EXIT_SUCCESS;
360 } else {
361 return run_in_foreground(pid);
362 }
363 }
364
365 /* Never reached */
366 return EXIT_FAILURE;
367 }
368
369 static int
run_shell_cmd(char ** comm)370 run_shell_cmd(char **comm)
371 {
372 /* LOG EXTERNAL COMMANDS
373 * 'no_log' will be true when running profile or prompt commands */
374 if (!no_log)
375 log_function(comm);
376
377 /* PREVENT UNGRACEFUL EXIT */
378 /* Prevent the user from killing the program via the 'kill',
379 * 'pkill' or 'killall' commands, from within CliFM itself.
380 * Otherwise, the program will be forcefully terminated without
381 * freeing allocated memory */
382 if ((*comm[0] == 'k' || *comm[0] == 'p') && (strcmp(comm[0], "kill") == 0
383 || strcmp(comm[0], "killall") == 0 || strcmp(comm[0], "pkill") == 0)) {
384 size_t i;
385 for (i = 1; i <= args_n; i++) {
386 if ((strcmp(comm[0], "kill") == 0 && atoi(comm[i]) == (int)own_pid)
387 || ((strcmp(comm[0], "killall") == 0 || strcmp(comm[0], "pkill") == 0)
388 && strcmp(comm[i], argv_bk[0]) == 0)) {
389 fprintf(stderr, _("%s: To gracefully quit enter 'quit'\n"),
390 PROGRAM_NAME);
391 return EXIT_FAILURE;
392 }
393 }
394 }
395
396 /* CHECK WHETHER SHELL COMMANDS ARE ALLOWED */
397 if (!ext_cmd_ok) {
398 fprintf(stderr, _("%s: External commands are not allowed. "
399 "Run 'ext on' to enable them.\n"), PROGRAM_NAME);
400 return EXIT_FAILURE;
401 }
402
403 if (*comm[0] == *argv_bk[0] && strcmp(comm[0], argv_bk[0]) == 0) {
404 fprintf(stderr, "%s: Nested instances are not allowed\n",
405 PROGRAM_NAME);
406 return EXIT_FAILURE;
407 }
408
409 /*
410 * By making precede the command by a colon or a semicolon, the
411 * user can BYPASS CliFM parsing, expansions, and checks to be
412 * executed DIRECTLY by the system shell (execle). For example:
413 * if the amount of files listed on the screen (ELN's) is larger
414 * or equal than 644 and the user tries to issue this command:
415 * "chmod 644 filename", CLIFM will take 644 to be an ELN, and
416 * will thereby try to expand it into the corresponding file name,
417 * which is not what the user wants. To prevent this, simply run
418 * the command as follows: ";chmod 644 filename" */
419 char *first = comm[0];
420 if (*comm[0] == ':' || *comm[0] == ';')
421 first++;
422
423 /* #### RUN THE SHELL COMMAND #### */
424
425 /* Store the command and each argument into a single array to be
426 * executed by execle() using the system shell (/bin/sh -c) */
427 char *cmd = (char *)NULL;
428 size_t len = strlen(first) + 2;
429 cmd = (char *)xnmalloc(len + (bg_proc ? 2 : 0), sizeof(char));
430 strncpy(cmd, first, len);
431
432 size_t i;
433 for (i = 1; comm[i]; i++) {
434 cmd[len - 2] = ' ';
435 cmd[len - 1] = '\0';
436 len += strlen(comm[i]) + 1;
437 cmd = (char *)xrealloc(cmd, (len + 2 + (bg_proc ? 2 : 0))
438 * sizeof(char));
439 strncat(cmd, comm[i], len);
440 }
441
442 /* Append final ampersand if backgrounded */
443 if (bg_proc) {
444 cmd[len - 2] = '&';
445 cmd[len - 1] = '\0';
446 }
447 /*
448 // Since we modified LS_COLORS, store its current value and unset
449 // it. Some shell commands use LS_COLORS to display their outputs
450 // ("ls -l", for example, use the "no" value to print file
451 // properties). So, we unset it to prevent wrong color output
452 // for external commands. The disadvantage of this procedure is
453 // that if the user uses a customized LS_COLORS, unsetting it
454 // set its value to default, and the customization is lost.
455
456 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
457 char *my_ls_colors = (char *)NULL, *p = (char *)NULL;
458 // For some reason, when running on FreeBSD Valgrind complains
459 // about overlapping source and destiny in setenv() if I just
460 // copy the address returned by getenv() instead of the string
461 // itself. Not sure why, but this makes the error go away
462 p = getenv("LS_COLORS");
463 my_ls_colors = (char *)xnmalloc(strlen(p) + 1, sizeof(char *));
464 strcpy(my_ls_colors, p);
465 p = (char *)NULL;
466
467 #else
468 static char *my_ls_colors = (char *)NULL;
469 my_ls_colors = getenv("LS_COLORS");
470 #endif
471
472 if (ls_colors_bk && *ls_colors_bk != '\0')
473 setenv("LS_COLORS", ls_colors_bk, 1);
474 else
475 unsetenv("LS_COLORS"); */
476
477 /* if (launch_execle(cmd) != EXIT_SUCCESS)
478 exit_status = EXIT_FAILURE; */
479 int exit_status = launch_execle(cmd);
480 free(cmd);
481
482 /* Restore LS_COLORS value to use CliFM colors */
483 /* setenv("LS_COLORS", my_ls_colors, 1);
484
485 #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
486 free(my_ls_colors);
487 #endif */
488
489 /* Reload the list of available commands in PATH for TAB completion.
490 * Why? If this list is not updated, whenever some new program is
491 * installed, renamed, or removed from some of the paths in PATH
492 * while in CliFM, this latter needs to be restarted in order
493 * to be able to recognize the new program for TAB completion */
494 int j;
495 if (bin_commands) {
496 j = (int)path_progsn;
497 while (--j >= 0)
498 free(bin_commands[j]);
499 free(bin_commands);
500 bin_commands = (char **)NULL;
501 }
502
503 if (paths) {
504 j = (int)path_n;
505 while (--j >= 0)
506 free(paths[j]);
507 }
508
509 path_n = (size_t)get_path_env();
510 get_path_programs();
511
512 return exit_status;
513 }
514
515 static int
set_max_files(char ** args)516 set_max_files(char **args)
517 {
518 if (!args[1]) {
519 if (max_files == -1)
520 puts(_("Max files: unset"));
521 else
522 printf(_("Max files: %d\n"), max_files);
523 return EXIT_SUCCESS;
524 }
525
526 if (*args[1] == '-' && strcmp(args[1], "--help") == 0) {
527 puts(_(MF_USAGE));
528 return EXIT_SUCCESS;
529 }
530
531 if (*args[1] == 'u' && strcmp(args[1], "unset") == 0) {
532 max_files = -1;
533 puts(_("Max files: unset"));
534 return EXIT_SUCCESS;
535 }
536
537 if (*args[1] == '0' && !args[1][1]) {
538 max_files = 0;
539 printf(_("Max files set to %d\n"), max_files);
540 return EXIT_SUCCESS;
541 }
542
543 long inum = strtol(args[1], NULL, 10);
544 if (inum == LONG_MAX || inum == LONG_MIN || inum <= 0) {
545 fprintf(stderr, _("%s: %s: Invalid number\n"), PROGRAM_NAME, args[1]);
546 return (exit_code = EXIT_FAILURE);
547 }
548
549 max_files = (int)inum;
550 printf(_("Max files set to %d\n"), max_files);
551 return EXIT_SUCCESS;
552 }
553
554
555 /* Take the command entered by the user, already splitted into substrings
556 * by parse_input_str(), and call the corresponding function. Return zero
557 * in case of success and one in case of error */
558 int
exec_cmd(char ** comm)559 exec_cmd(char **comm)
560 {
561 fputs(df_c, stdout);
562
563 /* Exit flag. exit_code is zero (sucess) by default. In case of error
564 * in any of the functions below, it will be set to one (failure).
565 * This will be the value returned by this function. Used by the \z
566 * escape code in the prompt to print the exit status of the last
567 * executed command */
568 int old_exit_code = exit_code;
569 exit_code = EXIT_SUCCESS;
570
571 if (*comm[0] == '#')
572 return exit_code;
573
574 /* ##########################
575 * # AUTOJUMP #
576 * ########################## */
577
578 /* if (autojump) {
579 exit_code = run_autojump(comm);
580 if (exit_code != -1)
581 return exit_code;
582 } */
583
584 /* Warn when using the ',' keyword and there's no pinned file */
585 int k = (int)args_n + 1;
586 while (--k >= 0) {
587 if (*comm[k] == ',' && !comm[k][1]) {
588 fprintf(stderr, _("%s: No pinned file\n"), PROGRAM_NAME);
589 return (exit_code = EXIT_FAILURE);
590 }
591 }
592
593 /* User defined actions */
594 if (actions_n) {
595 int i = (int)actions_n;
596 while (--i >= 0) {
597 if (*comm[0] == *usr_actions[i].name
598 && strcmp(comm[0], usr_actions[i].name) == 0)
599 return (exit_code = run_action(usr_actions[i].value, comm));
600 }
601 }
602
603 /* User defined variables */
604 if (flags & IS_USRVAR_DEF) {
605 flags &= ~IS_USRVAR_DEF;
606 return (exit_code = create_usr_var(comm[0]));
607 }
608
609 if (comm[0][0] == ';' || comm[0][0] == ':') {
610 if (!comm[0][1]) {
611 /* If just ":" or ";", launch the default shell */
612 char *cmd[] = {user.shell, NULL};
613 if (launch_execve(cmd, FOREGROUND, E_NOFLAG) != EXIT_SUCCESS)
614 exit_code = EXIT_FAILURE;
615 return exit_code;
616 } else if (comm[0][1] == ';' || comm[0][1] == ':') {
617 /* If double semi colon or colon (or ";:" or ":;") */
618 fprintf(stderr, _("%s: '%s': Syntax error\n"), PROGRAM_NAME, comm[0]);
619 return (exit_code = EXIT_FAILURE);
620 }
621 }
622
623 /* ###############################
624 * # AUTOCD & AUTO-OPEN (1) #
625 * ############################### */
626
627 char *deq_str = (char *)NULL;
628 if (autocd || auto_open) {
629 /* Expand tilde */
630 if (*comm[0] == '~') {
631 char *exp_path = tilde_expand(comm[0]);
632 if (exp_path) {
633 comm[0] = (char *)xrealloc(comm[0], (strlen(exp_path) + 1) * sizeof(char));
634 strcpy(comm[0], exp_path);
635 free(exp_path);
636 }
637 }
638
639 /* Deescape the string (only if file name) */
640 if (strchr(comm[0], '\\')) {
641 deq_str = dequote_str(comm[0], 0);
642 /* if (deq_str) {
643 if (access(deq_str, F_OK) == 0)
644 strcpy(comm[0], deq_str);
645 free(deq_str);
646 } */
647 }
648 }
649
650 /* Only autocd or auto-open here if not absolute path and if there
651 * is no second argument or if second argument is "&" */
652 if (*comm[0] != '/' && (autocd || auto_open) && (!comm[1]
653 || (*comm[1] == '&' && !comm[1][1]))) {
654 char *tmp = deq_str ? deq_str : comm[0];
655 size_t tmp_len = strlen(tmp);
656 if (tmp[tmp_len - 1] == '/')
657 tmp[tmp_len - 1] = '\0';
658
659 if (autocd && cdpath_n && !comm[1]
660 && cd_function(comm[0], CD_NO_PRINT_ERROR) == EXIT_SUCCESS) {
661 free(deq_str);
662 return EXIT_SUCCESS;
663 }
664
665 int i = (int)files;
666 while (--i >= 0) {
667 if (*tmp != *file_info[i].name)
668 continue;
669
670 if (strcmp(tmp, file_info[i].name) != 0)
671 continue;
672
673 free(deq_str);
674 deq_str = (char *)NULL;
675
676 if (autocd && (file_info[i].type == DT_DIR || file_info[i].dir == 1))
677 return (exit_code = cd_function(comm[0], CD_PRINT_ERROR));
678
679 if (auto_open && (file_info[i].type == DT_REG
680 || file_info[i].type == DT_LNK)) {
681 char *cmd[] = {"open", comm[0],
682 comm[1] ? comm[1] : NULL, NULL};
683 return (exit_code = open_function(cmd));
684 } else {
685 break;
686 }
687 }
688 }
689
690 free(deq_str);
691
692 /* The more often a function is used, the more on top should it be
693 * in this if...else..if chain. It will be found faster this way. */
694
695 /* ####################################################
696 * # BUILTIN COMMANDS #
697 * ####################################################*/
698
699 /* ############### CD ################## */
700 if (*comm[0] == 'c' && comm[0][1] == 'd' && !comm[0][2]) {
701 if (!comm[1])
702 exit_code = cd_function(NULL, CD_PRINT_ERROR);
703 else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)
704 puts(_(CD_USAGE));
705 else
706 exit_code = cd_function(comm[1], CD_PRINT_ERROR);
707 return exit_code;
708 }
709
710 /* ############### OPEN ################## */
711 else if (*comm[0] == 'o' && (!comm[0][1] || strcmp(comm[0], "open") == 0)) {
712 if (!comm[1]) {
713 puts(_(OPEN_USAGE));
714 exit_code = EXIT_FAILURE;
715 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
716 puts(_(OPEN_USAGE));
717 } else {
718 exit_code = open_function(comm);
719 }
720 return exit_code;
721 }
722
723 /* ############### OPEN WITH ################## */
724 else if (*comm[0] == 'o' && comm[0][1] == 'w' && !comm[0][2]) {
725 #ifndef _NO_LIRA
726 if (comm[1]) {
727 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
728 puts(_(OW_USAGE));
729 return EXIT_SUCCESS;
730 }
731 return mime_open_with(comm[1], comm[2] ? comm + 2 : NULL);
732 }
733 puts(_(OW_USAGE));
734 return EXIT_SUCCESS;
735 #else
736 fprintf(stderr, "%s: %s\n", PROGRAM_NAME, _(NOT_AVAILABLE));
737 return EXIT_FAILURE;
738 #endif
739 }
740
741 /* ############## DIRECTORY JUMPER ################## */
742 else if (*comm[0] == 'j' && (!comm[0][1] || ((comm[0][1] == 'c'
743 || comm[0][1] == 'p' || comm[0][1] == 'e' || comm[0][1] == 'o'
744 || comm[0][1] == 'l') && !comm[0][2])))
745 return (exit_code = dirjump(comm, NO_SUG_JUMP));
746
747 /* ############### REFRESH ################## */
748 else if (*comm[0] == 'r' && ((comm[0][1] == 'f' && !comm[0][2])
749 || strcmp(comm[0], "refresh") == 0)) {
750 if (autols) {
751 free_dirlist();
752 list_dir();
753 }
754 return exit_code = old_exit_code;
755 }
756
757 /* ############### BOOKMARKS ################## */
758 else if (*comm[0] == 'b' && ((comm[0][1] == 'm' && !comm[0][2])
759 || strcmp(comm[0], "bookmarks") == 0)) {
760 if (comm[1] && strcmp(comm[1], "--help") == 0) {
761 puts(_(BOOKMARKS_USAGE));
762 return EXIT_SUCCESS;
763 }
764 /* Disable keyboard shortcuts. Otherwise, the function will
765 * still be waiting for input while the screen have been taken
766 * by another function */
767 kbind_busy = 1;
768 /* Disable TAB completion while in Bookmarks */
769 rl_attempted_completion_function = NULL;
770 exit_code = bookmarks_function(comm);
771 /* Reenable TAB completion */
772 rl_attempted_completion_function = my_rl_completion;
773 /* Reenable keyboard shortcuts */
774 kbind_busy = 0;
775 return exit_code;
776 }
777
778 /* ############### BACK AND FORTH ################## */
779 else if (*comm[0] == 'b' && (!comm[0][1] || strcmp(comm[0], "back") == 0))
780 return (exit_code = back_function(comm));
781
782 else if (*comm[0] == 'f' && (!comm[0][1] || strcmp(comm[0], "forth") == 0))
783 return (exit_code = forth_function(comm));
784
785 else if ((*comm[0] == 'b' && comm[0][1] == 'h' && !comm[0][2])
786 || (*comm[0] == 'f' && comm[0][1] == 'h' && !comm[0][2])) {
787 print_dirhist();
788 return EXIT_SUCCESS;
789 }
790
791
792 /* ################# NEW FILE ################## */
793 else if (*comm[0] == 'n' && (!comm[0][1] || strcmp(comm[0], "new") == 0))
794 exit_code = create_file(comm);
795
796 /* ############### DUPLICATE FILE ################## */
797 else if (*comm[0] == 'd' && (!comm[0][1] || strcmp(comm[0], "dup") == 0)) {
798 if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) {
799 puts(DUP_USAGE);
800 return EXIT_SUCCESS;
801 }
802 exit_code = dup_file(comm[1], comm[2] ? comm[2] : NULL);
803 }
804
805 #ifdef __HAIKU__
806 else if ((*comm[0] == 'c' || *comm[0] == 'r' || *comm[0] == 'm'
807 || *comm[0] == 't' || *comm[0] == 'u' || *comm[0] == 'l')
808 && (strcmp(comm[0], "cp") == 0 || strcmp(comm[0], "rm") == 0
809 || strcmp(comm[0], "mkdir") == 0 || strcmp(comm[0], "unlink") == 0
810 || strcmp(comm[0], "touch") == 0 || strcmp(comm[0], "ln") == 0
811 || strcmp(comm[0], "chmod") == 0))
812 return (exit_code = run_and_refresh(comm));
813 #endif
814
815 /* ############### COPY AND MOVE ################## */
816 else if ((*comm[0] == 'c' && (!comm[0][1] || (comm[0][1] == 'p'
817 && !comm[0][2])))
818
819 || (*comm[0] == 'm' && (!comm[0][1] || (comm[0][1] == 'v'
820 && !comm[0][2])))
821
822 || (*comm[0] == 'v' && (!comm[0][1] || (comm[0][1] == 'v'
823 && !comm[0][2])))
824
825 || (*comm[0] == 'p' && strcmp(comm[0], "paste") == 0)) {
826
827 if (((*comm[0] == 'c' || *comm[0] == 'v') && !comm[0][1])
828 || (*comm[0] == 'v' && comm[0][1] == 'v' && !comm[0][2])
829 || strcmp(comm[0], "paste") == 0) {
830
831 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
832 puts(_(WRAPPERS_USAGE));
833 return EXIT_SUCCESS;
834 }
835
836 if (*comm[0] == 'v' && comm[0][1] == 'v' && !comm[0][2])
837 copy_n_rename = 1;
838
839 comm[0] = (char *)xrealloc(comm[0], 12 * sizeof(char));
840 if (!copy_n_rename) {
841 if (cp_cmd == CP_CP)
842 strcpy(comm[0], "cp -iRp");
843 else if (cp_cmd == CP_ADVCP)
844 strcpy(comm[0], "advcp -giRp");
845 else
846 strcpy(comm[0], "wcp");
847 } else {
848 strcpy(comm[0], "cp");
849 }
850 } else if (*comm[0] == 'm' && !comm[0][1]) {
851 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
852 puts(_(WRAPPERS_USAGE));
853 return EXIT_SUCCESS;
854 }
855 if (!sel_is_last && comm[1] && !comm[2])
856 xrename = 1;
857
858 comm[0] = (char *)xrealloc(comm[0], 10 * sizeof(char));
859 if (mv_cmd == MV_MV)
860 strcpy(comm[0], "mv -i");
861 else
862 strcpy(comm[0], "advmv -gi");
863 }
864
865 kbind_busy = 1;
866 exit_code = copy_function(comm);
867 kbind_busy = 0;
868 }
869
870 /* ############### TRASH ################## */
871 else if (*comm[0] == 't' && (!comm[0][1] || strcmp(comm[0], "tr") == 0
872 || strcmp(comm[0], "trash") == 0)) {
873 #ifndef _NO_TRASH
874 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
875 puts(_(TRASH_USAGE));
876 return EXIT_SUCCESS;
877 }
878
879 exit_code = trash_function(comm);
880
881 if (is_sel) { /* If 'tr sel', deselect everything */
882 int i = (int)sel_n;
883 while (--i >= 0)
884 free(sel_elements[i]);
885 sel_n = 0;
886 if (save_sel() != 0)
887 exit_code = EXIT_FAILURE;
888 }
889 #else
890 fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
891 return EXIT_FAILURE;
892 #endif /* !_NO_TRASH */
893 }
894
895 else if (*comm[0] == 'u' && (!comm[0][1] || strcmp(comm[0], "undel") == 0
896 || strcmp(comm[0], "untrash") == 0)) {
897 #ifndef _NO_TRASH
898 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
899 puts(_(UNTRASH_USAGE));
900 return EXIT_SUCCESS;
901 }
902
903 kbind_busy = 1;
904 rl_attempted_completion_function = NULL;
905 exit_code = untrash_function(comm);
906 rl_attempted_completion_function = my_rl_completion;
907 kbind_busy = 0;
908 #else
909 fprintf(stderr, _("%s: trash: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
910 return EXIT_FAILURE;
911 #endif /* !_NO_TRASH */
912 }
913
914 /* ############### SELECTION ################## */
915 else if (*comm[0] == 's' && (!comm[0][1] || strcmp(comm[0], "sel") == 0))
916 return (exit_code = sel_function(comm));
917
918 else if (*comm[0] == 's' && (strcmp(comm[0], "sb") == 0
919 || strcmp(comm[0], "selbox") == 0)) {
920 show_sel_files();
921 return EXIT_SUCCESS;
922 }
923
924 else if (*comm[0] == 'd' && (strcmp(comm[0], "ds") == 0
925 || strcmp(comm[0], "desel") == 0)) {
926 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
927 puts(_(DESEL_USAGE));
928 return EXIT_SUCCESS;
929 }
930
931 kbind_busy = 1;
932 rl_attempted_completion_function = NULL;
933 exit_code = deselect(comm);
934 rl_attempted_completion_function = my_rl_completion;
935 kbind_busy = 0;
936 return exit_code;
937 }
938
939 /* ############# SOME SHELL CMD WRAPPERS ############### */
940
941 else if ((*comm[0] == 'r' || *comm[0] == 'm' || *comm[0] == 'l')
942 && (strcmp(comm[0], "r") == 0 || strcmp(comm[0], "l") == 0
943 || strcmp(comm[0], "md") == 0 || strcmp(comm[0], "le") == 0)) {
944 /* This help is only for c, l, le, m, r, t, and md commands */
945 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
946 puts(_(WRAPPERS_USAGE));
947 return EXIT_SUCCESS;
948 }
949
950 if (*comm[0] == 'l' && !comm[0][1]) {
951 comm[0] = (char *)xrealloc(comm[0], 7 * sizeof(char));
952 strcpy(comm[0], "ln -sn");
953
954 /* Make sure the symlink source is always an absolute path */
955 if (comm[1] && *comm[1] != '/' && *comm[1] != '~') {
956 size_t len = strlen(comm[1]);
957 char *tmp = (char *)xnmalloc(len + 1, sizeof(char));
958 xstrsncpy(tmp, comm[1], len);
959 comm[1] = (char *)xrealloc(comm[1], (len
960 + strlen(ws[cur_ws].path) + 2) * sizeof(char));
961 sprintf(comm[1], "%s/%s", ws[cur_ws].path, tmp);
962 free(tmp);
963 }
964 } else if (*comm[0] == 'r' && !comm[0][1]) {
965 exit_code = remove_file(comm);
966 goto CHECK_EVENTS;
967 } else if (*comm[0] == 'm' && comm[0][1] == 'd' && !comm[0][2]) {
968 comm[0] = (char *)xrealloc(comm[0], 9 * sizeof(char));
969 strcpy(comm[0], "mkdir -p");
970 }
971
972 if (*comm[0] == 'l' && comm[0][1] == 'e' && !comm[0][2]) {
973 if (!comm[1]) {
974 fprintf(stderr, "%s\n", _(LE_USAGE));
975 return (exit_code = EXIT_FAILURE);
976 }
977 exit_code = edit_link(comm[1]);
978 goto CHECK_EVENTS;
979 } else if (*comm[0] == 'l' && comm[0][1] == 'n' && !comm[0][2]) {
980 if (comm[1] && (strcmp(comm[1], "edit") == 0
981 || strcmp(comm[1], "e") == 0)) {
982 if (!comm[2]) {
983 fprintf(stderr, "%s\n", _(LE_USAGE));
984 return (exit_code = EXIT_FAILURE);
985 }
986 exit_code = edit_link(comm[2]);
987 goto CHECK_EVENTS;
988 }
989 }
990
991 kbind_busy = 1;
992 exit_code = run_and_refresh(comm);
993 kbind_busy = 0;
994 }
995
996 /* ############### TOGGLE EXEC ################## */
997 else if (*comm[0] == 't' && comm[0][1] == 'e' && !comm[0][2]) {
998 if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) {
999 puts(_(TE_USAGE));
1000 return EXIT_SUCCESS;
1001 }
1002
1003 size_t j;
1004 for (j = 1; comm[j]; j++) {
1005 struct stat attr;
1006 if (strchr(comm[j], '\\')) {
1007 char *tmp = dequote_str(comm[j], 0);
1008 if (tmp) {
1009 strcpy(comm[j], tmp);
1010 free(tmp);
1011 }
1012 }
1013
1014 if (lstat(comm[j], &attr) == -1) {
1015 fprintf(stderr, "stat: %s: %s\n", comm[j], strerror(errno));
1016 exit_code = EXIT_FAILURE;
1017 continue;
1018 }
1019
1020 if (xchmod(comm[j], attr.st_mode) == -1)
1021 exit_code = EXIT_FAILURE;
1022 }
1023
1024 if (exit_code == EXIT_SUCCESS)
1025 printf(_("%s: Toggled executable bit on %zu file(s)\n"),
1026 PROGRAM_NAME, args_n);
1027 }
1028
1029 /* ############### PINNED FILE ################## */
1030 else if (*comm[0] == 'p' && strcmp(comm[0], "pin") == 0) {
1031 if (comm[1]) {
1032 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)
1033 puts(PIN_USAGE);
1034 else
1035 exit_code = pin_directory(comm[1]);
1036 } else {
1037 if (pinned_dir)
1038 printf(_("pinned file: %s\n"), pinned_dir);
1039 else
1040 puts(_("No pinned file"));
1041 }
1042 return exit_code;
1043 }
1044
1045 else if (*comm[0] == 'u' && strcmp(comm[0], "unpin") == 0)
1046 return (exit_code = unpin_dir());
1047
1048 /* ############### PROPERTIES ################## */
1049 else if (*comm[0] == 'p' && (!comm[0][1] || strcmp(comm[0], "pr") == 0
1050 || strcmp(comm[0], "pp") == 0 || strcmp(comm[0], "prop") == 0)) {
1051 if (!comm[1]) {
1052 fprintf(stderr, "%s\n", _(PROP_USAGE));
1053 exit_code = EXIT_FAILURE;
1054 return EXIT_FAILURE;
1055 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1056 puts(_(PROP_USAGE));
1057 return EXIT_SUCCESS;
1058 }
1059
1060 return (exit_code = properties_function(comm));
1061 }
1062
1063 /* ############### SEARCH ################## */
1064 else if (*comm[0] == '/' && !strchr(comm[0], '\\')
1065 && access(comm[0], F_OK) != 0) {
1066 /* If not absolute path */
1067 /* Try first globbing, and if no result, try regex */
1068 if (search_glob(comm, (comm[0][1] == '!') ? 1 : 0) == EXIT_FAILURE)
1069 exit_code = search_regex(comm, (comm[0][1] == '!') ? 1 : 0,
1070 case_sens_search ? 1 : 0);
1071 else
1072 exit_code = EXIT_SUCCESS;
1073 return exit_code;
1074 }
1075
1076 /* ############## HISTORY ################## */
1077 else if (*comm[0] == '!' && comm[0][1] != ' ' && comm[0][1] != '\t'
1078 && comm[0][1] != '\n' && comm[0][1] != '=' && comm[0][1] != '(')
1079 exit_code = run_history_cmd(comm[0] + 1);
1080
1081 /* ############### BATCH LINK ################## */
1082 else if (*comm[0] == 'b' && comm[0][1] == 'l' && !comm[0][2])
1083 exit_code = batch_link(comm);
1084
1085 /* ############### BULK RENAME ################## */
1086 else if (*comm[0] == 'b' && ((comm[0][1] == 'r' && !comm[0][2])
1087 || strcmp(comm[0], "bulk") == 0)) {
1088 if (!comm[1]) {
1089 fprintf(stderr, "%s\n", _(BULK_USAGE));
1090 return (exit_code = EXIT_FAILURE);
1091 }
1092
1093 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1094 puts(_(BULK_USAGE));
1095 return EXIT_SUCCESS;
1096 }
1097 exit_code = bulk_rename(comm);
1098 }
1099
1100 /* ################ SORT ################## */
1101 else if (*comm[0] == 's' && ((comm[0][1] == 't' && !comm[0][2])
1102 || strcmp(comm[0], "sort") == 0)) {
1103 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1104 puts(_(SORT_USAGE));
1105 return EXIT_SUCCESS;
1106 }
1107 return (exit_code = sort_function(comm));
1108 }
1109
1110 /* ########## FILE NAMES CLEANER ############## */
1111 else if (*comm[0] == 'b' && ((comm[0][1] == 'b' && !comm[0][2])
1112 || strcmp(comm[0], "bleach") == 0)) {
1113 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1114 puts(_(BLEACH_USAGE));
1115 return EXIT_SUCCESS;
1116 }
1117 #ifndef _NO_BLEACH
1118 exit_code = bleach_files(comm);
1119 #else
1120 fprintf(stderr, _("%s: bleach: %s\n"), PROGRAM_NAME, NOT_AVAILABLE);
1121 return EXIT_FAILURE;
1122 #endif
1123 }
1124
1125 /* ################ ARCHIVER ################## */
1126 else if (*comm[0] == 'a' && ((comm[0][1] == 'c' || comm[0][1] == 'd')
1127 && !comm[0][2])) {
1128 #ifndef _NO_ARCHIVING
1129 if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) {
1130 puts(_(ARCHIVE_USAGE));
1131 return EXIT_SUCCESS;
1132 }
1133
1134 if (comm[0][1] == 'c')
1135 exit_code = archiver(comm, 'c');
1136 else
1137 exit_code = archiver(comm, 'd');
1138 #else
1139 fprintf(stderr, _("%s: archiving: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1140 return EXIT_FAILURE;
1141 #endif
1142 }
1143
1144 /* ##################################################
1145 * # MINOR FUNCTIONS #
1146 * ##################################################*/
1147
1148 else if (*comm[0] == 'w' && comm[0][1] == 's' && !comm[0][2])
1149 return (exit_code = workspaces(comm[1] ? comm[1] : NULL));
1150
1151 else if (*comm[0] == 'f' && ((comm[0][1] == 't' && !comm[0][2])
1152 || strcmp(comm[0], "filter") == 0))
1153 return (exit_code = filter_function(comm[1]));
1154
1155 else if (*comm[0] == 'c' && ((comm[0][1] == 'l' && !comm[0][2])
1156 || strcmp(comm[0], "columns") == 0)) {
1157 if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) {
1158 puts(_(COLUMNS_USAGE));
1159 return EXIT_SUCCESS;
1160 } else if (*comm[1] == 'o' && comm[1][1] == 'n' && !comm[1][2]) {
1161 columned = 1;
1162 if (autols) {
1163 free_dirlist();
1164 exit_code = list_dir();
1165 }
1166 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1167 columned = 0;
1168 if (autols) {
1169 free_dirlist();
1170 exit_code = list_dir();
1171 }
1172 } else {
1173 fprintf(stderr, "%s\n", _(COLUMNS_USAGE));
1174 exit_code = EXIT_FAILURE;
1175 return EXIT_FAILURE;
1176 }
1177 return exit_code;
1178 }
1179 else if (*comm[0] == 'i' && strcmp(comm[0], "icons") == 0) {
1180 #ifndef _NO_ICONS
1181 if (!comm[1] || (*comm[1] == '-' && strcmp(comm[1], "--help") == 0)) {
1182 puts(_(ICONS_USAGE));
1183 } else if (*comm[1] == 'o' && comm[1][1] == 'n' && !comm[1][2]) {
1184 icons = 1;
1185 if (autols) {
1186 free_dirlist();
1187 exit_code = list_dir();
1188 }
1189 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1190 icons = 0;
1191 if (autols) {
1192 free_dirlist();
1193 exit_code = list_dir();
1194 }
1195 } else {
1196 fprintf(stderr, "%s\n", _(ICONS_USAGE));
1197 exit_code = EXIT_FAILURE;
1198 return EXIT_FAILURE;
1199 }
1200
1201 return EXIT_SUCCESS;
1202 #else
1203 fprintf(stderr, _("%s: icons: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1204 return EXIT_SUCCESS;
1205 #endif /* _NO_ICONS */
1206 }
1207
1208 else if (*comm[0] == 'c' && ((comm[0][1] == 's' && !comm[0][2])
1209 || strcmp(comm[0], "colorschemes") == 0))
1210 return (exit_code = cschemes_function(comm));
1211
1212 else if (*comm[0] == 'k' && ((comm[0][1] == 'b' && !comm[0][2])
1213 || strcmp(comm[0], "keybinds") == 0))
1214 return (exit_code = kbinds_function(comm));
1215
1216 else if (*comm[0] == 'e' && strcmp(comm[0], "exp") == 0) {
1217 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1218 puts(_(EXPORT_USAGE));
1219 return EXIT_SUCCESS;
1220 }
1221
1222 char *ret = export(comm, 1);
1223 if (ret) {
1224 printf("Files exported to: %s\n", ret);
1225 free(ret);
1226 return EXIT_SUCCESS;
1227 }
1228
1229 return (exit_code = EXIT_FAILURE);
1230 }
1231
1232 else if (*comm[0] == 'o' && strcmp(comm[0], "opener") == 0) {
1233 if (!comm[1]) {
1234 printf("opener: %s\n", (opener) ? opener : "lira (built-in)");
1235 return EXIT_SUCCESS;
1236 }
1237 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1238 puts(_(OPENER_USAGE));
1239 return EXIT_SUCCESS;
1240 }
1241 if (opener) {
1242 free(opener);
1243 opener = (char *)NULL;
1244 }
1245 if (strcmp(comm[1], "default") != 0 && strcmp(comm[1], "lira") != 0) {
1246 opener = (char *)xnmalloc(strlen(comm[1]) + 1, sizeof(char));
1247 strcpy(opener, comm[1]);
1248 }
1249 printf(_("opener: Opener set to '%s'\n"), (opener) ? opener
1250 : "lira (built-in)");
1251 return EXIT_SUCCESS;
1252 }
1253
1254 /* #### TIPS #### */
1255 else if (*comm[0] == 't' && strcmp(comm[0], "tips") == 0) {
1256 print_tips(1);
1257 return EXIT_SUCCESS;
1258 }
1259
1260 /* #### ACTIONS #### */
1261 else if (*comm[0] == 'a' && strcmp(comm[0], "actions") == 0) {
1262 if (!comm[1]) {
1263 if (actions_n) {
1264 size_t i;
1265 for (i = 0; i < actions_n; i++)
1266 printf("%s %s->%s %s\n", usr_actions[i].name,
1267 mi_c, df_c, usr_actions[i].value);
1268 } else {
1269 puts(_("actions: No actions defined. Use the 'actions "
1270 "edit' command to add some"));
1271 }
1272 } else if (strcmp(comm[1], "edit") == 0) {
1273 return (exit_code = edit_actions());
1274 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1275 puts(_(ACTIONS_USAGE));
1276 } else {
1277 fprintf(stderr, "%s\n", _(ACTIONS_USAGE));
1278 exit_code = EXIT_FAILURE;
1279 return EXIT_FAILURE;
1280 }
1281 return exit_code;
1282 }
1283
1284 /* #### LIGHT MODE #### */
1285 else if (*comm[0] == 'l' && comm[0][1] == 'm' && !comm[0][2]) {
1286 if (comm[1]) {
1287 if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1288 light_mode = 1;
1289 puts(_("Light mode is on"));
1290 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1291 light_mode = 0;
1292 puts(_("Light mode is off"));
1293 } else {
1294 puts(_(LM_USAGE));
1295 exit_code = EXIT_FAILURE;
1296 }
1297 } else {
1298 fprintf(stderr, "%s\n", _(LM_USAGE));
1299 exit_code = EXIT_FAILURE;
1300 }
1301 return exit_code;
1302 }
1303
1304 /* ############### RELOAD ################## */
1305 else if (*comm[0] == 'r' && ((comm[0][1] == 'l' && !comm[0][2])
1306 || strcmp(comm[0], "reload") == 0)) {
1307 exit_code = reload_config();
1308 welcome_message = 0;
1309 if (autols) {
1310 free_dirlist();
1311 if (list_dir() != EXIT_SUCCESS)
1312 exit_code = EXIT_FAILURE;
1313 }
1314 return exit_code;
1315 }
1316
1317 /* #### NEW INSTANCE #### */
1318 else if ((*comm[0] == 'x' || *comm[0] == 'X') && !comm[0][1]) {
1319 if (comm[1]) {
1320 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1321 puts(_(X_USAGE));
1322 return EXIT_SUCCESS;
1323 } else if (*comm[0] == 'x') {
1324 exit_code = new_instance(comm[1], 0);
1325 } else { /* Run as root */
1326 exit_code = new_instance(comm[1], 1);
1327 }
1328 } else {
1329 /* Run new instance in CWD */
1330 if (*comm[0] == 'x')
1331 exit_code = new_instance(ws[cur_ws].path, 0);
1332 else
1333 exit_code = new_instance(ws[cur_ws].path, 1);
1334 }
1335
1336 return exit_code;
1337 }
1338
1339 /* #### NET #### */
1340 else if (*comm[0] == 'n' && (strcmp(comm[0], "net") == 0))
1341 return (exit_code = remotes_function(comm));
1342
1343 /* #### MIME #### */
1344 else if (*comm[0] == 'm' && ((comm[0][1] == 'm' && !comm[0][2])
1345 || strcmp(comm[0], "mime") == 0)) {
1346 #ifndef _NO_LIRA
1347 return (exit_code = mime_open(comm));
1348 #else
1349 fprintf(stderr, _("%s: Lira: %s\n"), PROGRAM_NAME, _(NOT_AVAILABLE));
1350 return EXIT_FAILURE;
1351 #endif
1352 }
1353
1354 else if (*comm[0] == 'l' && comm[0][1] == 's' && !comm[0][2] && !autols) {
1355 free_dirlist();
1356 exit_code = list_dir();
1357 if (get_sel_files() != EXIT_SUCCESS)
1358 exit_code = EXIT_FAILURE;
1359 return exit_code;
1360 }
1361
1362 /* #### PROFILE #### */
1363 else if (*comm[0] == 'p' && ((comm[0][1] == 'f' && !comm[0][2]) || strcmp(comm[0], "prof") == 0 || strcmp(comm[0], "profile") == 0))
1364 return (exit_code = profile_function(comm));
1365
1366 /* #### MOUNTPOINTS #### */
1367 else if (*comm[0] == 'm' && ((comm[0][1] == 'p' && !comm[0][2]) || strcmp(comm[0], "mountpoints") == 0)) {
1368 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1369 puts(_(MOUNPOINTS_USAGE));
1370 return EXIT_SUCCESS;
1371 } else {
1372 kbind_busy = 1;
1373 rl_attempted_completion_function = NULL;
1374 exit_code = media_menu(MEDIA_LIST);
1375 rl_attempted_completion_function = my_rl_completion;
1376 kbind_busy = 0;
1377 return exit_code;
1378 }
1379 }
1380
1381 /* #### MEDIA #### */
1382 else if (*comm[0] == 'm' && strcmp(comm[0], "media") == 0) {
1383 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1384 puts(_(MEDIA_USAGE));
1385 return EXIT_SUCCESS;
1386 } else {
1387 kbind_busy = 1;
1388 rl_attempted_completion_function = NULL;
1389 exit_code = media_menu(MEDIA_MOUNT);
1390 rl_attempted_completion_function = my_rl_completion;
1391 kbind_busy = 0;
1392 return exit_code;
1393 }
1394 }
1395
1396 /* #### MAX FILES #### */
1397 else if (*comm[0] == 'm' && comm[0][1] == 'f' && !comm[0][2])
1398 return set_max_files(comm);
1399
1400 /* #### EXT #### */
1401 else if (*comm[0] == 'e' && comm[0][1] == 'x' && comm[0][2] == 't'
1402 && !comm[0][3]) {
1403 if (!comm[1]) {
1404 puts(_(EXT_USAGE));
1405 return (exit_code = EXIT_FAILURE);
1406 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1407 puts(_(EXT_USAGE));
1408 } else {
1409 if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) {
1410 printf(_("%s: External commands %s\n"), PROGRAM_NAME,
1411 (ext_cmd_ok) ? _("enabled") : _("disabled"));
1412 } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1413 ext_cmd_ok = 1;
1414 printf(_("%s: External commands enabled\n"), PROGRAM_NAME);
1415 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1416 ext_cmd_ok = 0;
1417 printf(_("%s: External commands disabled\n"), PROGRAM_NAME);
1418 } else {
1419 fprintf(stderr, "%s\n", _(EXT_USAGE));
1420 exit_code = EXIT_FAILURE;
1421 }
1422 }
1423 return exit_code;
1424 }
1425
1426 /* #### PAGER #### */
1427 else if (*comm[0] == 'p' && ((comm[0][1] == 'g' && !comm[0][2])
1428 || strcmp(comm[0], "pager") == 0)) {
1429 if (!comm[1]) {
1430 puts(_(PAGER_USAGE));
1431 return (exit_code = EXIT_FAILURE);
1432 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1433 puts(_(PAGER_USAGE));
1434 return EXIT_SUCCESS;
1435 } else {
1436 if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) {
1437 printf(_("%s: Pager %s\n"), PROGRAM_NAME,
1438 (pager) ? _("enabled") : _("disabled"));
1439 } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1440 pager = 1;
1441 printf(_("%s: Pager enabled\n"), PROGRAM_NAME);
1442 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1443 pager = 0;
1444 printf(_("%s: Pager disabled\n"), PROGRAM_NAME);
1445 } else {
1446 fprintf(stderr, "%s\n", _(PAGER_USAGE));
1447 exit_code = EXIT_FAILURE;
1448 }
1449 }
1450 return exit_code;
1451 }
1452
1453 /* #### FILES COUNTER #### */
1454 else if (*comm[0] == 'f' && ((comm[0][1] == 'c' && !comm[0][2])
1455 || strcmp(comm[0], "filescounter") == 0)) {
1456 if (!comm[1]) {
1457 fprintf(stderr, "%s\n", _(FC_USAGE));
1458 return (exit_code = EXIT_FAILURE);
1459 }
1460
1461 if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1462 files_counter = 1;
1463 puts(_("Filescounter is enabled"));
1464 return EXIT_SUCCESS;
1465 }
1466
1467 if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1468 files_counter = 0;
1469 puts(_("Filescounter is disabled"));
1470 return EXIT_SUCCESS;
1471 }
1472
1473 if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) {
1474 if (files_counter)
1475 puts(_("Filescounter is enabled"));
1476 else
1477 puts(_("Filescounter is disabled"));
1478 return EXIT_SUCCESS;
1479 } else {
1480 fprintf(stderr, "%s\n", _(FC_USAGE));
1481 return (exit_code = EXIT_FAILURE);
1482 }
1483 }
1484
1485 /* #### UNICODE #### */
1486 else if (*comm[0] == 'u' && ((comm[0][1] == 'c' && !comm[0][2])
1487 || strcmp(comm[0], "unicode") == 0)) {
1488 if (!comm[1]) {
1489 fprintf(stderr, "%s\n", _(UNICODE_USAGE));
1490 return (exit_code = EXIT_FAILURE);
1491 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1492 puts(_(UNICODE_USAGE));
1493 return EXIT_SUCCESS;
1494 } else {
1495 if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) {
1496 printf(_("%s: Unicode %s\n"), PROGRAM_NAME,
1497 (unicode) ? _("enabled") : _("disabled"));
1498 } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1499 unicode = 1;
1500 printf(_("%s: Unicode enabled\n"), PROGRAM_NAME);
1501 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1502 unicode = 0;
1503 printf(_("%s: Unicode disabled\n"), PROGRAM_NAME);
1504 } else {
1505 fprintf(stderr, "%s\n", _(UNICODE_USAGE));
1506 exit_code = EXIT_FAILURE;
1507 }
1508 }
1509 return exit_code;
1510 }
1511
1512 /* #### FOLDERS FIRST #### */
1513 else if (*comm[0] == 'f' && ((comm[0][1] == 'f' && !comm[0][2])
1514 || strcmp(comm[0], "folders-first") == 0)) {
1515 if (autols == 0)
1516 return EXIT_SUCCESS;
1517 if (!comm[1]) {
1518 fprintf(stderr, "%s\n", _(FF_USAGE));
1519 return (exit_code = EXIT_FAILURE);
1520 }
1521 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1522 puts(_(FF_USAGE));
1523 return EXIT_SUCCESS;
1524 }
1525
1526 int status = list_folders_first;
1527 if (*comm[1] == 's' && strcmp(comm[1], "status") == 0) {
1528 printf(_("%s: Folders first %s\n"), PROGRAM_NAME,
1529 (list_folders_first) ? _("enabled") : _("disabled"));
1530 } else if (*comm[1] == 'o' && strcmp(comm[1], "on") == 0) {
1531 list_folders_first = 1;
1532 } else if (*comm[1] == 'o' && strcmp(comm[1], "off") == 0) {
1533 list_folders_first = 0;
1534 } else {
1535 fprintf(stderr, "%s\n", _(FF_USAGE));
1536 return (exit_code = EXIT_FAILURE);
1537 }
1538
1539 if (list_folders_first != status) {
1540 if (autols) {
1541 free_dirlist();
1542 exit_code = list_dir();
1543 }
1544 }
1545 return exit_code;
1546 }
1547
1548 /* #### LOG #### */
1549 else if (*comm[0] == 'l' && strcmp(comm[0], "log") == 0) {
1550 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1551 puts(_(LOG_USAGE));
1552 return EXIT_SUCCESS;
1553 }
1554
1555 /* I make this check here, and not in the function itself,
1556 * because this function is also called by other instances of
1557 * the program where no message should be printed */
1558 if (!config_ok) {
1559 fprintf(stderr, _("%s: Log function disabled\n"), PROGRAM_NAME);
1560 return (exit_code = EXIT_FAILURE);
1561 }
1562
1563 return (exit_code = log_function(comm));
1564 }
1565
1566 /* #### MESSAGES #### */
1567 else if (*comm[0] == 'm' && (strcmp(comm[0], "msg") == 0
1568 || strcmp(comm[0], "messages") == 0)) {
1569 if (comm[1] && strcmp(comm[1], "--help") == 0) {
1570 puts(_(MSG_USAGE));
1571 return EXIT_SUCCESS;
1572 }
1573
1574 if (comm[1] && strcmp(comm[1], "clear") == 0) {
1575 if (!msgs_n) {
1576 printf(_("%s: There are no messages\n"), PROGRAM_NAME);
1577 return EXIT_SUCCESS;
1578 }
1579
1580 size_t i;
1581 for (i = 0; i < (size_t)msgs_n; i++)
1582 free(messages[i]);
1583
1584 msgs_n = 0;
1585 pmsg = NOMSG;
1586 } else {
1587 if (msgs_n) {
1588 size_t i;
1589 for (i = 0; i < (size_t)msgs_n; i++)
1590 printf("%s", messages[i]);
1591 } else {
1592 printf(_("%s: There are no messages\n"), PROGRAM_NAME);
1593 }
1594 }
1595 return exit_code;
1596 }
1597
1598 /* #### ALIASES #### */
1599 else if (*comm[0] == 'a' && strcmp(comm[0], "alias") == 0) {
1600 if (comm[1]) {
1601 if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1602 puts(_(ALIAS_USAGE));
1603 return EXIT_SUCCESS;
1604 } else if (*comm[1] == 'i' && strcmp(comm[1], "import") == 0) {
1605 if (!comm[2]) {
1606 fprintf(stderr, "%s\n", _(ALIAS_USAGE));
1607 return (exit_code = EXIT_FAILURE);
1608 }
1609 return (exit_code = alias_import(comm[2]));
1610 }
1611 }
1612
1613 if (aliases_n) {
1614 size_t i;
1615 for (i = 0; i < aliases_n; i++)
1616 printf("%s %s->%s %s\n", aliases[i].name, mi_c, df_c, aliases[i].cmd);
1617 } else {
1618 printf("%s: No aliases found\n", PROGRAM_NAME);
1619 }
1620 return EXIT_SUCCESS;
1621 }
1622
1623 /* #### SHELL #### */
1624 /* else if (*comm[0] == 's' && strcmp(comm[0], "shell") == 0) {
1625 if (!comm[1]) {
1626 if (user.shell)
1627 printf("%s: shell: %s\n", PROGRAM_NAME, user.shell);
1628 else
1629 printf(_("%s: shell: unknown\n"), PROGRAM_NAME);
1630 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1631 puts(_(SHELL_USAGE));
1632 return EXIT_SUCCESS;
1633 } else {
1634 return (exit_code = set_shell(comm[1]));
1635 }
1636 } */
1637
1638 /* #### EDIT #### */
1639 else if (*comm[0] == 'e' && strcmp(comm[0], "edit") == 0)
1640 return (exit_code = edit_function(comm));
1641
1642 /* #### HISTORY #### */
1643 else if (*comm[0] == 'h' && strcmp(comm[0], "history") == 0)
1644 return (exit_code = history_function(comm));
1645
1646 /* #### HIDDEN FILES #### */
1647 else if (*comm[0] == 'h' && ((comm[0][1] == 'f' && !comm[0][2])
1648 || strcmp(comm[0], "hidden") == 0)) {
1649 if (!comm[1]) {
1650 fprintf(stderr, "%s\n", _(HF_USAGE));
1651 return (exit_code = EXIT_FAILURE);
1652 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1653 /* The same message is in hidden_function(), and printed
1654 * whenever an invalid argument is entered */
1655 puts(_(HF_USAGE));
1656 return EXIT_SUCCESS;
1657 } else {
1658 return (exit_code = hidden_function(comm));
1659 }
1660 }
1661
1662 /* #### AUTOCD #### */
1663 else if (*comm[0] == 'a' && (strcmp(comm[0], "acd") == 0
1664 || strcmp(comm[0], "autocd") == 0)) {
1665 if (!comm[1]) {
1666 fprintf(stderr, "%s\n", _(AUTOCD_USAGE));
1667 return (exit_code = EXIT_FAILURE);
1668 }
1669
1670 if (strcmp(comm[1], "on") == 0) {
1671 autocd = 1;
1672 printf(_("%s: autocd is enabled\n"), PROGRAM_NAME);
1673 } else if (strcmp(comm[1], "off") == 0) {
1674 autocd = 0;
1675 printf(_("%s: autocd is disabled\n"), PROGRAM_NAME);
1676 } else if (strcmp(comm[1], "status") == 0) {
1677 if (autocd)
1678 printf(_("%s: autocd is enabled\n"), PROGRAM_NAME);
1679 else
1680 printf(_("%s: autocd is disabled\n"), PROGRAM_NAME);
1681 } else if (*comm[1] == '-' && strcmp(comm[1], "--help") == 0) {
1682 puts(_(AUTOCD_USAGE));
1683 } else {
1684 fprintf(stderr, "%s\n", _(AUTOCD_USAGE));
1685 return (exit_code = EXIT_FAILURE);
1686 }
1687 return EXIT_SUCCESS;
1688 }
1689
1690 /* #### AUTO-OPEN #### */
1691 else if (*comm[0] == 'a' && ((comm[0][1] == 'o' && !comm[0][2])
1692 || strcmp(comm[0], "auto-open") == 0)) {
1693 if (!comm[1]) {
1694 fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE));
1695 return (exit_code = EXIT_FAILURE);
1696 }
1697
1698 if (strcmp(comm[1], "on") == 0) {
1699 auto_open = 1;
1700 printf(_("%s: auto-open is enabled\n"), PROGRAM_NAME);
1701 } else if (strcmp(comm[1], "off") == 0) {
1702 auto_open = 0;
1703 printf(_("%s: auto-open is disabled\n"), PROGRAM_NAME);
1704 } else if (strcmp(comm[1], "status") == 0) {
1705 if (auto_open)
1706 printf(_("%s: auto-open is enabled\n"), PROGRAM_NAME);
1707 else
1708 printf(_("%s: auto-open is disabled\n"), PROGRAM_NAME);
1709 } else if (strcmp(comm[1], "--help") == 0) {
1710 puts(_(AUTO_OPEN_USAGE));
1711 } else {
1712 fprintf(stderr, "%s\n", _(AUTO_OPEN_USAGE));
1713 return (exit_code = EXIT_FAILURE);
1714 }
1715 return EXIT_SUCCESS;
1716 }
1717
1718 /* #### COMMANDS #### */
1719 else if (*comm[0] == 'c' && (strcmp(comm[0], "cmd") == 0
1720 || strcmp(comm[0], "commands") == 0))
1721 return (exit_code = list_commands());
1722
1723 /* #### AND THESE ONES TOO #### */
1724 /* These functions just print stuff, so that the value of exit_code
1725 * is always zero, that is to say, success */
1726 else if (strcmp(comm[0], "path") == 0 || strcmp(comm[0], "cwd") == 0) {
1727 printf("%s\n", ws[cur_ws].path);
1728 return EXIT_SUCCESS;
1729 }
1730
1731 else if ((*comm[0] == '?' && !comm[0][1]) || strcmp(comm[0], "help") == 0) {
1732 help_function();
1733 return EXIT_SUCCESS;
1734 }
1735
1736 else if (*comm[0] == 'c' && ((comm[0][1] == 'c' && !comm[0][2])
1737 || strcmp(comm[0], "colors") == 0)) {
1738 if (comm[1] && *comm[1] == '-' && strcmp(comm[1], "--help") == 0)
1739 puts(_(COLORS_USAGE));
1740 else
1741 color_codes();
1742 return EXIT_SUCCESS;
1743 }
1744
1745 else if (*comm[0] == 'v' && (strcmp(comm[0], "ver") == 0
1746 || strcmp(comm[0], "version") == 0)) {
1747 version_function();
1748 return EXIT_SUCCESS;
1749 }
1750
1751 else if (*comm[0] == 'f' && comm[0][1] == 's' && !comm[0][2]) {
1752 free_software();
1753 return EXIT_SUCCESS;
1754 }
1755
1756 else if (*comm[0] == 'b' && strcmp(comm[0], "bonus") == 0) {
1757 bonus_function();
1758 return EXIT_SUCCESS;
1759 }
1760
1761 else if (*comm[0] == 's' && strcmp(comm[0], "splash") == 0) {
1762 splash();
1763 return EXIT_SUCCESS;
1764 }
1765
1766 /* #### QUIT #### */
1767 else if ((*comm[0] == 'q' && (!comm[0][1] || strcmp(comm[0], "quit") == 0))
1768 || (*comm[0] == 'e' && strcmp(comm[0], "exit") == 0)
1769 || (*comm[0] == 'Q' && !comm[0][1])) {
1770 /* Free everything and exit */
1771 if (*comm[0] == 'Q')
1772 cd_on_quit = 1;
1773 int i = (int)args_n + 1;
1774 while (--i >= 0)
1775 free(comm[i]);
1776 free(comm);
1777 exit(exit_code);
1778 }
1779
1780 else {
1781 /* ###############################
1782 * # AUTOCD & AUTO-OPEN (2) #
1783 * ############################### */
1784
1785 char *tmp = (char *)xnmalloc(strlen(comm[0]) + 1, sizeof(char));
1786 strcpy(tmp, comm[0]);
1787 if (strchr(tmp, '\\')) {
1788 char *dstr = dequote_str(tmp, 0);
1789 if (dstr) {
1790 strcpy(tmp, dstr);
1791 free(dstr);
1792 }
1793 }
1794
1795 if (autocd && cdpath_n && !comm[1]) {
1796 exit_code = cd_function(tmp, CD_NO_PRINT_ERROR);
1797 if (exit_code == EXIT_SUCCESS) {
1798 free(tmp);
1799 return EXIT_SUCCESS;
1800 }
1801 }
1802
1803 struct stat attr;
1804 if (stat(tmp, &attr) == 0) {
1805 if ((attr.st_mode & S_IFMT) == S_IFDIR) {
1806 if (autocd)
1807 exit_code = cd_function(tmp, CD_PRINT_ERROR);
1808 else
1809 fprintf(stderr, _("%s: %s: Is a directory\n"),
1810 PROGRAM_NAME, tmp);
1811 free(tmp);
1812 return exit_code;
1813 } else if (auto_open && (attr.st_mode & S_IFMT) == S_IFREG) {
1814 /* Make sure we have not an executable file */
1815 if (!(attr.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
1816 char *cmd[] = {"open", tmp, (args_n >= 1) ? comm[1]
1817 : NULL, (args_n >= 2) ? comm[2] : NULL, NULL};
1818 args_n++;
1819 exit_code = open_function(cmd);
1820 args_n--;
1821 free(tmp);
1822 return exit_code;
1823 }
1824 }
1825 }
1826
1827 free(tmp);
1828
1829 /* ####################################################
1830 * # EXTERNAL/SHELL COMMANDS #
1831 * ####################################################*/
1832
1833 if ((exit_code = run_shell_cmd(comm)) == EXIT_FAILURE)
1834 return EXIT_FAILURE;
1835 }
1836
1837 CHECK_EVENTS:
1838 if (!autols)
1839 return exit_code;
1840
1841 #ifdef LINUX_INOTIFY
1842 if (watch)
1843 read_inotify();
1844 #elif defined(BSD_KQUEUE)
1845 if (watch && event_fd >= 0)
1846 read_kqueue();
1847 #endif
1848
1849 return exit_code;
1850 }
1851
1852 /* Execute chained commands (cmd1;cmd2 and/or cmd1 && cmd2). The function
1853 * is called by parse_input_str() if some non-quoted double ampersand or
1854 * semicolon is found in the input string AND at least one of these
1855 * chained commands is internal */
1856 void
exec_chained_cmds(char * cmd)1857 exec_chained_cmds(char *cmd)
1858 {
1859 if (!cmd)
1860 return;
1861
1862 size_t i = 0, cmd_len = strlen(cmd);
1863 for (i = 0; i < cmd_len; i++) {
1864 char *str = (char *)NULL;
1865 size_t len = 0, cond_exec = 0;
1866
1867 /* Get command */
1868 str = (char *)xcalloc(strlen(cmd) + 1, sizeof(char));
1869 while (cmd[i] && cmd[i] != '&' && cmd[i] != ';')
1870 str[len++] = cmd[i++];
1871
1872 if (!*str) {
1873 free(str);
1874 continue;
1875 }
1876
1877 /* Should we execute conditionally? */
1878 if (cmd[i] == '&')
1879 cond_exec = 1;
1880
1881 /* Execute the command */
1882 char **tmp_cmd = parse_input_str(str);
1883 free(str);
1884
1885 if (!tmp_cmd)
1886 continue;
1887
1888 int error_code = 0;
1889 size_t j;
1890 char **alias_cmd = check_for_alias(tmp_cmd);
1891 if (alias_cmd) {
1892 if (exec_cmd(alias_cmd) != 0)
1893 error_code = 1;
1894 for (j = 0; alias_cmd[j]; j++)
1895 free(alias_cmd[j]);
1896 free(alias_cmd);
1897 } else {
1898 if (exec_cmd(tmp_cmd) != 0)
1899 error_code = 1;
1900 for (j = 0; j <= args_n; j++)
1901 free(tmp_cmd[j]);
1902 free(tmp_cmd);
1903 }
1904 /* Do not continue if the execution was condtional and
1905 * the previous command failed */
1906 if (cond_exec && error_code)
1907 break;
1908 }
1909 }
1910
1911 void
exec_profile(void)1912 exec_profile(void)
1913 {
1914 if (!config_ok || !profile_file)
1915 return;
1916
1917 FILE *fp = fopen(profile_file, "r");
1918 if (!fp)
1919 return;
1920
1921 size_t line_size = 0;
1922 char *line = (char *)NULL;
1923 ssize_t line_len = 0;
1924
1925 while ((line_len = getline(&line, &line_size, fp)) > 0) {
1926 /* Skip empty and commented lines */
1927 if (!*line || *line == '\n' || *line == '#')
1928 continue;
1929
1930 /* Remove trailing new line char */
1931 if (line[line_len - 1] == '\n')
1932 line[line_len - 1] = '\0';
1933
1934 if (strchr(line, '=') && !_ISDIGIT(*line)) {
1935 create_usr_var(line);
1936 } else if (strlen(line) != 0) {
1937 /* Parse line and execute it */
1938 args_n = 0;
1939
1940 char **cmds = parse_input_str(line);
1941
1942 if (cmds) {
1943 no_log = 1;
1944 exec_cmd(cmds);
1945 no_log = 0;
1946 int i = (int)args_n + 1;
1947 while (--i >= 0)
1948 free(cmds[i]);
1949 free(cmds);
1950 cmds = (char **)NULL;
1951 }
1952 args_n = 0;
1953 }
1954 }
1955
1956 free(line);
1957 fclose(fp);
1958 }
1959