"Fossies" - the Fresh Open Source Software Archive 
Member "chkrootkit-0.55/chkdirs.c" (8 Mar 2021, 7376 Bytes) of package /linux/misc/chkrootkit-0.55.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "chkdirs.c" see the
Fossies "Dox" file reference documentation and the last
Fossies "Diffs" side-by-side code changes report:
0.53_vs_0.54.
1 /* Copyright (C) Hal Pomeranz <hal@deer-run.com> and Deer Run Assoc, 2002/11/24
2 All rights reserved. Permission granted to freely redistribute and update
3 as long as this Copyright notice is preserved. No warranty expressed or
4 implied.
5
6 $Id: chkdirs.c,v 1.3 2003/01/20 19:44:13 hal Exp $
7
8
9 Usage: chkdirs [-n] dir ...
10 Examples: chkdirs /
11 chkdirs -n /proc
12 Recursively traverses one or more directories looking for discrepancies
13 between the parent directory link count and the number of subdirectories
14 (parent directory link count should always equal the number of subdirs
15 plus two-- anything else indicates a "hidden" directory). "-n" option
16 means check directory but don't recursively descend into subdirectories.
17
18 Changelog :
19 2002/12/19 - Little port for *BSB and Solaris - Nelson Murilo
20 2003/01/09 - More fix for Solaris - Nelson Murilo
21 2003/01/14 - HP-UX patch - Gerard Breiner
22 2003/01/20 - NAME_MAX Fix by Hal Pomeranz
23 2003/09/01 - BSDI port by Nelson Murilo and Thomas Davidson
24 2005/22/05 - APPLE test for limits.h included by Aaron Harwood
25 2007/08/10 - strncpy used instead of strcpy - nm
26 2007/12/24 - change `c' variable type - NIDE, Naoyuki
27 2020/12/24 - Add a warning for btrfs (no inode usage)
28
29 */
30
31 #if defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__sun) || defined (hpux) || defined (__bsdi__) || defined (bsdi) || defined (__APPLE__)
32 #include <limits.h>
33 #elif defined(__APPLE__) && defined(__MACH__)
34 #include <sys/syslimits.h>
35 #endif
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <unistd.h>
42 #include <dirent.h>
43 #include <string.h>
44 #include <errno.h>
45
46 #ifndef NAME_MAX
47 #define NAME_MAX PATH_MAX
48 #endif
49
50 struct dirinfolist {
51 char dil_name[NAME_MAX+1];
52 int dil_lc;
53 struct dirinfolist *dil_next;
54 };
55
56
57 void usage ()
58 {
59 fprintf(stderr, "chkdirs [-n] dir ...\n");
60 exit(255);
61 }
62
63 char *make_pathname (char *path, char *dir, char **buffer)
64 {
65 int plen, pathname_len, bufsize, offs;
66
67 bufsize = 0;
68
69 plen = strlen(path);
70 pathname_len = plen + strlen(dir) + 2;
71
72 if (!(*buffer) || (sizeof(*buffer) < pathname_len)) {
73 if (buffer) free((void *)*buffer);
74 bufsize = (pathname_len > PATH_MAX) ? pathname_len : PATH_MAX;
75 if (!(*buffer = (char *)malloc(bufsize))) {
76 return((char *)NULL);
77 }
78 }
79
80 if (dir[0] == '/') { /* "dir" is absolute pathname, don't prepend "path" */
81 offs = 0;
82 }
83 else {
84 strncpy(*buffer, path, bufsize);
85 if ((*buffer)[plen-1] == '/') { /* "path" ends in "/", don't add extra */
86 offs = plen;
87 }
88 else {
89 (*buffer)[plen] = '/';
90 offs = plen + 1;
91 }
92 }
93 strncpy((*buffer)+offs, dir, bufsize - offs);
94 return((*buffer));
95 }
96
97 int check_dir (char *dir, char *path, int linkcount, int norecurse)
98 {
99 int diff = -1;
100 int plen, buflen, numdirs;
101 char *curpath, *fullpath;
102 DIR *dirhandle;
103 struct dirent *finfo;
104 struct dirinfolist *dl, *dptr;
105 struct stat statinfo;
106
107 /* When called recursively, "path" will be the full path of the cwd,
108 but when called from main() "path" is empty. We need the cwd path
109 so we can chdir() back at the end of this routine, as well as when
110 printing errors and other output.
111 */
112 if (!path || !(plen = strlen(path))) {
113 buflen = PATH_MAX;
114 retry:
115 if (!(curpath = (char *)malloc(buflen))) {
116 fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
117 return(-1);
118 }
119 if (!getcwd(curpath, buflen)) {
120 if (errno == ERANGE) {
121 free((void *)curpath);
122 buflen = buflen * 2;
123 goto retry;
124 }
125 else {
126 fprintf(stderr, "getcwd() failed: %s\n", strerror(errno));
127 return(-1);
128 }
129 }
130 }
131 else { /* "path" is set, so just copy it into "curpath" */
132 if (!(curpath = (char *)malloc(plen+1))) {
133 fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
134 return(-1);
135 }
136 strncpy(curpath, path, plen+1);
137 }
138
139 /* Now set "fullpath" to be the absolute path name of the directory
140 we will be checking (prepend "curpath" if "dir" is not already an
141 absolute pathname).
142 */
143 fullpath = (char *)NULL;
144 if (!make_pathname(curpath, dir, &fullpath)) {
145 fprintf(stderr, "make_pathname() failed: %s\n", strerror(errno));
146 free((void *)curpath);
147 return(-1);
148 }
149
150 if (chdir(dir)) {
151 fprintf(stderr, "chdir(%s): %s\n", fullpath, strerror(errno));
152 free((void *)curpath);
153 free((void *)fullpath);
154 return(-1);
155 }
156
157 /* Again, "linkcount" (the link count of the current directory) is set
158 only if check_dir() is called recursively. Otherwise, we need to
159 stat the directory ourselves.
160 */
161 if (!linkcount) {
162 if (lstat(".", &statinfo)) {
163 fprintf(stderr, "lstat(%s): %s\n", fullpath, strerror(errno));
164 goto abort;
165 }
166 linkcount = statinfo.st_nlink;
167 if (linkcount == 1)
168 {
169 fprintf(stderr, "WARNIING: It seems you are using BTRFS, if this is true chkdirs can't help you to find hidden files/dirs\n");
170 goto abort;
171 }
172 }
173
174 if (!(dirhandle = opendir("."))) {
175 fprintf(stderr, "opendir(%s): %s\n", fullpath, strerror(errno));
176 goto abort;
177 }
178
179 numdirs = 0;
180 dl = (struct dirinfolist *)NULL;
181 while ((finfo = readdir(dirhandle))) {
182 if (!strcmp(finfo->d_name, ".") || !strcmp(finfo->d_name, ".."))
183 continue;
184
185 if (lstat(finfo->d_name, &statinfo)) {
186 fprintf(stderr, "lstat(%s/%s): %s\n",
187 fullpath, finfo->d_name, strerror(errno));
188 closedir(dirhandle);
189 goto abort;
190 }
191
192 if (S_ISDIR(statinfo.st_mode)) {
193 numdirs++;
194
195 if (norecurse) continue; /* just count subdirs if "-n" */
196
197 /* Otherwise, keep a list of all directories found that have link
198 count > 2 (indicating directory contains subdirectories). We'll
199 call check_dir() on each of these subdirectories in a moment...
200 */
201 if (statinfo.st_nlink > 2) {
202 dptr = dl;
203 if (!(dl = (struct dirinfolist *)malloc(sizeof(struct dirinfolist)))) {
204 fprintf(stderr, "malloc() failed: %s\n", strerror(errno));
205 norecurse = 1;
206 while (dptr) {
207 dl = dptr->dil_next;
208 free((void *)dptr);
209 dptr = dl;
210 }
211 continue;
212 }
213
214 strncpy(dl->dil_name, finfo->d_name, sizeof(dl->dil_name));
215 dl->dil_lc = statinfo.st_nlink;
216 dl->dil_next = dptr;
217 }
218 }
219 }
220 closedir(dirhandle);
221
222 /* Parent directory link count had better equal #subdirs+2... */
223 diff = linkcount - numdirs - 2;
224 if (diff) printf("%d\t%s\n", diff, fullpath);
225
226 /* Now check all subdirectories in turn... */
227 while (dl) {
228 check_dir(dl->dil_name, fullpath, dl->dil_lc, norecurse);
229 dptr = dl->dil_next;
230 free((void *)dl);
231 dl = dptr;
232 }
233
234 abort:
235 if (chdir(curpath)) {
236 fprintf(stderr, "Final chdir(%s) failed (%s) -- EXIT!\n",
237 curpath, strerror(errno));
238 exit(255);
239 }
240 free((void *)fullpath);
241 free((void *)curpath);
242 return(diff);
243 }
244
245
246 int main (int argc, char **argv)
247 {
248 int norecurse = 0;
249 int i, retval;
250 int c;
251
252 opterr = 0;
253 while ((c = getopt(argc, argv, "n")) > 0) {
254 switch (c) {
255 case 'n':
256 norecurse = 1;
257 break;
258 default:
259 usage();
260 }
261 }
262 if (argc <= optind) usage();
263
264 for (i = optind; i < argc; i++) {
265 retval = check_dir(argv[i], (char *)NULL, 0, norecurse);
266 }
267 exit(retval);
268 }