/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* cmd_cd.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: tmaze +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2019/01/07 16:44:40 by tmaze #+# #+# */ /* Updated: 2020/01/26 22:17:48 by tmaze ### ########.fr */ /* */ /* ************************************************************************** */ #include "minishell.h" void *put_error_cd(char *file, char *msg) { ft_putstr("cd: "); ft_putstr(file); ft_putstr(": "); ft_putendl(msg); return (NULL); } int put_error_cd2(char *file, char *msg) { ft_putstr("cd: "); ft_putstr(file); ft_putstr(": "); ft_putendl(msg); return (1); } char *check_path_slash_cd(char *exec) { int i; struct stat info; struct stat info2; if (exec[0] == '/') { if ((i = access(exec, F_OK)) != 0) return (put_error_cd(exec, "no such file or directory")); if ((i = lstat(exec, &info)) != 0) return (put_error_cd(exec, "can't determine info")); if ((S_ISLNK(info.st_mode) && ((i = stat(exec, &info2)) != 0 || !S_ISDIR(info2.st_mode))) && !S_ISDIR(info.st_mode)) return (put_error_cd(exec, "not a directory")); if ((i = access(exec, X_OK)) != 0) return (put_error_cd(exec, "permission denied")); return (exec); } return (NULL); } int cmd_cd_update_env(char *path, t_env **env, char opt) { t_env *pwd; char *oldpwd; char *c_path; char p_path[4096]; ft_bzero(p_path, 4096); if (!(pwd = ft_envgetelem("PWD", *env))) return (put_error_cd2(path, "env var PWD undefined")); if (getcwd(p_path, 4096) == NULL || (oldpwd = ft_strdup(pwd->val)) == NULL || ft_realpath(path, &c_path) == NULL) return (put_error_cd2(path, "error")); if (ft_envupdate("PWD", *env, ((opt == 'P') ? p_path : c_path)) == NULL || ft_envupdate("OLDPWD", *env, oldpwd) == NULL) { ft_strdel(&oldpwd); ft_strdel(&c_path); return (put_error_cd2(path, "error")); } ft_strdel(&oldpwd); ft_strdel(&c_path); return (0); } int cmd_cd_core(char *path, t_env **env, char opt) { t_env *pwd; if (check_path_slash_cd(path) == NULL) return (1); if (chdir(path) == -1 || (pwd = ft_envgetelem("PWD", *env)) == NULL) { put_error_cd(path, "error"); return (1); } return (cmd_cd_update_env(path, env, opt)); } char cd_getparams(char **argv, size_t *i) { char ret[2]; size_t j; ret[1] = '\0'; ret[0] = 'L'; *i = 0; while (argv[++(*i)] && argv[*i][0] == '-' && ft_strlen(argv[*i]) > 1) { j = 1; while (argv[*i][j] && (argv[*i][j] == 'L' || argv[*i][j] == 'P')) ret[0] = argv[*i][j++]; if (argv[*i][j] && argv[*i][j] != 'L' && argv[*i][j] != 'P') { ret[0] = argv[*i][j]; put_error_cd(ret, "invalid option"); put_error_cd("usage", "cd [-L|-P] [dir]"); ret[0] = '\0'; break ; } } return (ret[0]); } int cmd_cd_switchboard(char **av, t_env **env, char opt, int i) { t_env *e; char *p; int ret; if ((!av[i] && (e = ft_envgetelem("HOME", *env)) != NULL && e->val != NULL) || (av[i] && av[i][0] == '-' && (e = ft_envgetelem("OLDPWD", *env)) != NULL)) return (cmd_cd_core(e->val, env, opt)); else if (av[i] && av[i][0] == '/') return (cmd_cd_core(av[i], env, opt)); else if (av[i] && av[i][0] != '/' && (e = ft_envgetelem("PWD", *env)) != NULL && e->val != NULL) { if ((p = ft_strnew(ft_strlen(e->val) + ft_strlen(av[i]) + 1)) == NULL) put_error_cd(av[i], "memory error"); if (p == NULL) return (1); ft_strcpy(p, e->val); p[ft_strlen(p)] = '/'; ft_strcat(p, av[i]); ret = cmd_cd_core(p, env, opt); ft_strdel(&p); return (ret); } return (1); } int cmd_cd(char **argv, t_env **env) { size_t i; char opt; i = 0; if ((opt = cd_getparams(argv, &i)) == '\0') return (1); return (cmd_cd_switchboard(argv, env, opt, i)); }