Added a basic implementation of wc.
[4chanprog.git] / coreutils / chgrp.c
blobb416825ab352f2bfbf0f3f83c1b8e521fe3ca39a
1 /* @chgrp.c */
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <grp.h>
8 #include <dirent.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <ctype.h>
13 int opt_h,
14 opt_R,
15 opt_HLP; /* 0: do not follow symlinks; 1: only for cmd args; 2: all */
16 gid_t new_gid;
18 char *g_nam;
20 struct visited {
21 struct visited *next;
22 dev_t dev;
23 ino_t ino;
24 } *v_stack;
26 int add_visited(struct stat *s) {
27 struct visited *v;
28 if(!(v=malloc(sizeof(struct visited))))
29 return 1;
30 v->dev = s->st_dev;
31 v->ino = s->st_ino;
32 v->next = v_stack;
33 if(v_stack)
34 v_stack->next=v;
35 else
36 v_stack=v;
37 return 0;
40 int del_visited() {
41 if(v_stack) {
42 struct visited *v = v_stack->next;
43 free(v_stack);
44 v_stack=v;
45 return 0;
47 return 1;
50 int is_visited(struct stat *s) {
51 struct visited *v=v_stack;
52 while(v) {
53 if(v->dev==s->st_dev && v->ino==s->st_ino)
54 return 1;
55 v=v->next;
57 return 0;
60 /* chgrp everything in directory pointed to by path (and recurse, per opt_R and opt_HLP) */
61 int do_chgrp(char *path) {
62 DIR *cur;
63 struct dirent *cur_file;
64 struct stat f_stat;
65 char *filename;
66 int ret=0;
68 if(stat(path,&f_stat)) {
69 fprintf(stderr,"%s: cannot stat %s: %s\n",g_nam,path,strerror(errno));
70 return 1;
72 if(chdir(path)) {
73 fprintf(stderr,"%s: cannot enter directory %s\n",g_nam,path);
74 return 1;
76 if(add_visited(&f_stat)) {
77 fprintf(stderr,"%s: cannot add path to stack: %s\n",g_nam,strerror(errno));
78 return 1;
80 if(!(cur=opendir("."))) {
81 fprintf(stderr,"%s: cannot open directory %s\n",g_nam,path);
82 ret=1;
83 goto enter_parent;
85 while(cur_file=readdir(cur)) {
86 filename=cur_file->d_name;
87 if(!strcmp(filename,".") || !strcmp(filename,".."))
88 continue;
89 if((opt_h)?lchown(filename,-1,new_gid):chown(filename,-1,new_gid)) {
90 fprintf(stderr,"%s: cannot change group of %s: %s\n",g_nam,filename,strerror(errno));
91 ret=1;
92 continue;
94 if(opt_R) {
95 if(lstat(filename,&f_stat)) {
96 stat_fail:
97 fprintf(stderr,"%s: cannot stat %s: %s\n",g_nam,filename,strerror(errno));
98 ret=1;
99 continue;
101 switch(f_stat.st_mode&S_IFMT) {
102 case S_IFLNK:
103 /* check if symlink points to directory... */
104 if(stat(filename,&f_stat))
105 goto stat_fail;
106 if(f_stat.st_mode!=S_IFDIR)
107 break;
108 /* fall through and enter directory */
109 case S_IFDIR:
110 if(opt_HLP<2 || is_visited(&f_stat))
111 break;
112 ret|=do_chgrp(filename);
113 break;
114 default:
115 break;
119 ret|=closedir(cur);
120 enter_parent:
121 del_visited();
122 if(chdir("..")) {
123 fprintf(stderr,"%s: cannot return to parent of %s: %s\n",g_nam,path,strerror(errno));
124 return 1;
126 return ret;
129 int main(int argc, char **argv) {
130 int c;
131 struct group *new_group;
132 struct stat f_stat;
133 char *path;
135 g_nam=argv[0];
136 while((c=getopt(argc,argv,"hHLPR"))!=-1) {
137 switch(c) {
138 case 'h': /* chgrp symlink regular files and not its destination */
139 opt_h=1;
140 break;
141 case 'H': /* enter only symlinked directories as args */
142 opt_HLP=1;
143 break;
144 case 'L': /* enter all symlinked directories */
145 opt_HLP=2;
146 break;
147 case 'P': /* do not enter symlinked directories */
148 opt_HLP=0;
149 break;
150 case 'R': /* recurse */
151 opt_R=1;
152 break;
153 case '?':
154 fprintf(stderr,"%s: invalid option %c\n",argv[0],optopt);
155 goto do_usage;
158 if(!argv[optind]) {
159 do_usage:
160 fprintf(stderr,"usage: %s [-hR] group file ...\n %s -R [-H | -L | -P] group file ...\n",argv[0],argv[0]);
161 return 1;
163 if(!isdigit(argv[optind][0])) {
164 if(!(new_group=getgrnam(argv[optind++]))) {
165 fprintf(stderr,"%s: invalid group %s\n",argv[0],argv[optind-1]);
166 return 2;
168 new_gid=new_group->gr_gid;
169 } else
170 new_gid=atoi(argv[optind++]);
171 c=0;
172 while(path=argv[optind++]) { /* main chown loop */
173 if((opt_h)?lchown(path,-1,new_gid):chown(path,-1,new_gid)) {
174 fprintf(stderr,"%s: cannot change group of %s: %s\n",argv[0],path,strerror(errno));
175 c=1;
176 continue;
178 if(opt_R) { /* recurse if a subdirectory */
179 if(lstat(path,&f_stat)) {
180 stat_fail:
181 fprintf(stderr,"%s: cannot stat %s: %s\n",argv[0],path,strerror(errno));
182 c=1;
183 continue;
185 switch(f_stat.st_mode&S_IFMT) {
186 case S_IFLNK:
187 if(!opt_HLP) /* do not follow any symlinks */
188 break;
189 /* check if symlink points to directory... */
190 if(stat(path,&f_stat))
191 goto stat_fail;
192 if(f_stat.st_mode!=S_IFDIR)
193 break;
194 /* fall through and enter directory */
195 case S_IFDIR:
196 c|=do_chgrp(path);
197 break;
198 default:
199 break;
203 return c;