1 #include <stdio.h>
2 #include <dirent.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <unistd.h>
6 #include <sys/stat.h>
7 #include <aos/cli.h>
8 #include <stdbool.h>
9 #include <fcntl.h>
10 
11 static char g_last_working_directory[512] = "/";
12 
up_one_level(char * abspath)13 static int up_one_level(char *abspath)
14 {
15     char *c, *last_slash;
16 
17     if (strcmp(abspath, "/") == 0)
18         return -1;
19 
20     c = abspath + 1;
21     last_slash = abspath;
22 
23     while (*c != '\0') {
24         if ((*c == '/') && (*(c + 1) != '\0'))
25             last_slash = c;
26         c++;
27     }
28 
29     *(last_slash + 1) = '\0';
30 
31     return 0;
32 }
33 
34 #define ROOT_DIR "/"
cd_main(int argc,char ** argv)35 static int cd_main(int argc, char **argv)
36 {
37     char absolute[256] = {0}, *ret, *target, cwd_backup[256] = {0};
38     struct stat s;
39 
40     if (argc > 1) {
41         target = argv[1];
42     } else {
43         target = ROOT_DIR;
44     }
45 
46     if (!target) {
47         aos_cli_printf("target dir is NULL!\r\n");
48         return -1;
49     }
50 
51     ret = getcwd(absolute, sizeof(absolute));
52     if (!ret) {
53         aos_cli_printf("Failed to get current working directory!\r\n");
54         return -1;
55     }
56 
57     strncpy(cwd_backup, absolute, sizeof(cwd_backup));
58 
59     if (target[0] != '/') {
60         if (target[0] == '-') {
61             memset(absolute, 0, sizeof(absolute));
62             strncpy(absolute, g_last_working_directory, sizeof(absolute));
63             absolute[sizeof(absolute) - 1] = '\0';
64             goto check_and_cd;
65         }
66 
67         if (absolute[strlen(absolute) - 1] != '/') {
68             absolute[strlen(absolute)] = '/';
69         }
70 
71         // exclude heading "./"
72         while (strncmp(target, "./", strlen("./")) == 0) {
73             target += strlen("./");
74             while (target[0] == '/')
75                 target++;
76         }
77 
78         // parse heading ".."
79         while (target && strncmp(target, "..", strlen("..")) == 0) {
80             if (up_one_level(absolute) != 0) {
81                 aos_cli_printf("up to parent dir failed. %s may " \
82                            "not be a valid path!", target);
83                 return -1;
84             }
85 
86             target += strlen("..");
87             while (target[0] == '/')
88                 target++;
89         }
90 
91         if (target)
92             strncpy(absolute + strlen(absolute), target, \
93                             sizeof(absolute) - strlen(absolute));
94     } else {
95         strncpy(absolute, target, sizeof(absolute));
96     }
97 
98 check_and_cd:
99     if (stat(absolute, &s)) {
100         aos_cli_printf("cd: %s not existed\r\n", target);
101         return -1;
102     }
103 
104     if (access(absolute, F_OK) != 0) {
105         aos_cli_printf("%s is not a valid path.\r\n", target);
106         return -1;
107     }
108 
109     if (!S_ISDIR(s.st_mode)) {
110         aos_cli_printf("cd: %s not a directory\r\n", target);
111         return -1;
112     }
113 
114     int err = chdir(absolute);
115     if (err != 0) {
116         aos_cli_printf("Failed to change to %s, errno: %d\r\n",
117                         absolute, errno);
118         return -1;
119     }
120 
121     memset(g_last_working_directory,
122            0,
123            sizeof(g_last_working_directory));
124 
125     strncpy(g_last_working_directory,
126             cwd_backup,
127             sizeof(g_last_working_directory));
128 
129     return 0;
130 }
131 ALIOS_CLI_CMD_REGISTER(cd_main, cd, change current working directory);
132