#include #include #include #include #include #include #include #include #include unsigned int r_flag; int (*chown_func)(const char *pathname, uid_t owner, gid_t group); int (*stat_func)(const char *restrict pathname, struct stat *restrict statbuf); long gid; long uid; int get_stat(const char *path, struct stat *stat_path) { if (stat_func(path, stat_path)) { fprintf(stderr, "chown: unable to stat %s: %s\n", path, strerror(errno)); return 1; } return 0; } char *make_path(const char *src, const char *dst) { size_t len = strlen(src) + strlen(dst) + 2; char *full_path = malloc(len + 1); if (full_path == NULL) { fprintf(stderr, "chown: malloc() returned NULL\n"); return NULL; } snprintf(full_path, len, "%s/%s", src, dst); return full_path; } int change(const char *file) { struct stat old_file; if (get_stat(file, &old_file)) return 1; if (chown_func(file, uid, gid) == 0) { struct stat new_file; if (get_stat(file, &new_file)) return 1; if (old_file.st_gid != new_file.st_gid || old_file.st_uid != new_file.st_uid) return 0; fprintf(stderr, "chown: %s unchanged\n", file); } else fprintf(stderr, "chown: unable to chown %s: %s\n", file, strerror(errno)); return 1; } int cntree(const char *dst) { int ret = change(dst); struct stat stat_path; if (get_stat(dst, &stat_path)) return 1; if (!S_ISDIR(stat_path.st_mode) || !r_flag) return ret; DIR *dir = opendir(dst); if (dir == NULL) { fprintf(stderr, "chown: %s: Can`t open directory\n", dst); return 1; } struct dirent *ep; while ((ep = readdir(dir)) != NULL) { if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) continue; char *full_path = make_path(dst, ep->d_name); if (full_path == NULL) continue; if (cntree(full_path)) ret = 1; free(full_path); } closedir(dir); return ret; } void get_owner(const char *arg) { char *group = strchr(arg, ':'); unsigned int g_flag = 1; unsigned int u_flag = 1; if (group == arg) u_flag = 0; else if (!group) g_flag = 0; if (g_flag) { group[0] = '\0'; group++; struct group *grp = getgrnam(group); if (!grp) { fprintf(stderr, "chown: invalid group: %s\n", group); exit(1); } gid = grp->gr_gid; } if (u_flag) { struct passwd *pwd = getpwnam(arg); if (!pwd) { fprintf(stderr, "chown: invalid user: %s\n", arg); exit(1); } uid = pwd->pw_gid; } } int main(const int argc, char **argv) { chown_func = lchown; stat_func = stat; int i; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') break; else if (!strcmp(argv[i], "-r")) r_flag = 1; else if (!strcmp(argv[i], "-H")) { chown_func = chown; stat_func = stat; } else if (!strcmp(argv[i], "--help")) { printf("chown [-H (if a command line argument is a symbolic link)] [-r (recursive)] [owner]:[group] [file file2...]\n"); return 0; } } if (argc - i == 0) { fprintf(stderr, "chown: missing operand\n"); return 1; } gid = -1; uid = -1; get_owner(argv[i++]); if (argc - i == 0) { fprintf(stderr, "chown: missing operand\n"); return 1; } int ret = 0; for (; i < argc; i++) if (cntree(argv[i])) ret = 1; return ret; }