1 /*
2 * Copyright (c) 2002, 2013
3 * FREEBSD HACKERS NET (http://www.freebsdhackers.net) All rights reserved.
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by FREEBSD HACKERS NET,
17 * http://www.freebsdhackers.net
18 * 4. Neither the name "FREEBSD HACKERS NET" nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE FREEBSD HACKERS NET ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL FREEBSD HACKERS NET OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 * POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 /*
36 * MAINTAINER: Shane Kinney (mod6) <modsix@gmail.com>
37 */
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <errno.h>
46 #include <fts.h>
47
48 #define MAXBUFFSIZE 8192
49
50 void usage();
51 void setup(unsigned long filesize, char *path, int sflag);
52 void traverse(char **argv, int fflag, int qflag, int sflag);
53 void destroy(int read_fd, int write_fd, char *buf, int sz_buf, unsigned long filesize);
54 void unlink_special(char *path);
55
main(int argc,char * argv[])56 int main(int argc, char *argv[]) {
57
58 int ch, fflag, qflag, sflag;
59
60 if(argc < 2) {
61 usage();
62 exit(1);
63 }
64
65 /* don't want getopt() writing to stderr -- set flags to 0 for good mesasure. */
66 opterr = fflag = qflag = sflag = 0;
67
68 while((ch = getopt(argc, argv, "s:fqh")) != -1) {
69 switch(ch) {
70 case 's':
71 sflag = atoi(optarg);
72 if(sflag < 1 || sflag > 20) { // The number of overwrites must between 1 and 20
73 usage();
74 exit(1);
75 }
76 break;
77 case 'f':
78 fflag = 1;
79 break;
80 case 'q':
81 qflag = 1;
82 break;
83 case 'h':
84 usage();
85 case '?':
86 /* see `man 3 getopt` */
87 fprintf(stderr, "Unrecognized option: -%c\n", optopt);
88 usage();
89 default:
90 usage();
91 }
92 }
93
94 /* If user didn't set a default sflag number, set it to 7 (US DOD Standard). */
95 if(!sflag) {
96 sflag = 7;
97 }
98
99 argc -= optind;
100 argv += optind;
101
102 if(argc < 1) {
103 usage();
104 }
105
106 traverse(argv, fflag, qflag, sflag);
107 return 0;
108 }
109
traverse(char ** argv,int fflag,int qflag,int sflag)110 void traverse(char **argv, int fflag, int qflag, int sflag) {
111 FTS *fts;
112 FTSENT *p;
113 int dirCount, flags;
114 unsigned long filesize;
115 flags = FTS_PHYSICAL;
116 dirCount = 0;
117
118 /* Open the path given from the command line */
119 if(!(fts = fts_open(argv, flags, NULL))) {
120 perror("Error!: ");
121 exit(1);
122 }
123
124 /* Recursivly attempt to destroy all valid files */
125 while((p = fts_read(fts)) != NULL) {
126
127 /* Now look the stat of the file and determine the st_mode */
128 switch(p->fts_statp->st_mode & S_IFMT) {
129
130 case S_IFIFO: /* named pipe (fifo) */
131 if(fflag) {
132 if(!qflag) {
133 printf("Named Pipe: \t %s \n", p->fts_accpath);
134 }
135 unlink_special(p->fts_accpath);
136 } else if(!qflag) {
137 fprintf(stderr, "Named Pipe: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
138 }
139 break;
140
141 case S_IFCHR: /* character special */
142 if(fflag) {
143 if(!qflag) {
144 printf("Character Special: \t %s \n", p->fts_accpath);
145 }
146 unlink_special(p->fts_accpath);
147 } else if(!qflag) {
148 fprintf(stderr, "Character Special: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
149 }
150 break;
151
152 case S_IFDIR: /* directory */
153 if(!qflag) {
154 printf("Directory: \t %s \n", p->fts_accpath);
155 }
156 rmdir(p->fts_accpath);
157 break;
158
159 case S_IFBLK: /* block special */
160 if(fflag) {
161 printf("Block Special: \t %s \n", p->fts_accpath);
162 unlink_special(p->fts_accpath);
163 } else if(!qflag) {
164 fprintf(stderr, "Block Special: \t %s \t Skipping...no '-f' flag given!\n", p->fts_accpath);
165 }
166 break;
167
168 case S_IFREG: /* regular */
169 filesize = p->fts_statp->st_size;
170 if(!qflag) {
171 printf("Regular File: \t %s \t Size: \t %lu Bytes\n", p->fts_accpath, filesize);
172 }
173
174 setup(filesize, p->fts_accpath, sflag);
175 break;
176
177 case S_IFLNK: /* symbolic link */
178 if(fflag) {
179 if(!qflag) {
180 printf("Symbolic Link: \t %s \n", p->fts_accpath);
181 }
182 unlink_special(p->fts_accpath);
183 } else if(!qflag) {
184 fprintf(stderr, "Symbolic Link: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
185 }
186 break;
187
188 case S_IFSOCK: /* socket */
189 if(fflag) {
190 if(!qflag) {
191 printf("Socket: \t %s \n", p->fts_accpath);
192 }
193 unlink_special(p->fts_accpath);
194 } else if(!qflag) {
195 fprintf(stderr, "Socket: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
196 }
197 break;
198 #ifdef __FreeBSD__
199 case S_IFWHT: /* whiteout is only a FreeBSD type */
200 if(fflag) {
201 if(!qflag) {
202 printf("Whiteout: \t %s \n", p->fts_accpath);
203 }
204 unlink_special(p->fts_accpath);
205 } else if(!qflag) {
206 fprintf(stderr, "Whiteout: \t %s \t Skipping... no '-f' flag set!\n", p->fts_accpath);
207 }
208 break;
209 #endif
210 default:
211 if(!qflag) {
212 fprintf(stderr, "Type Unknown...\n");
213 }
214 }
215 }
216 }
217
setup(unsigned long filesize,char * path,int sflag)218 void setup(unsigned long filesize, char *path, int sflag) {
219 struct stat sb;
220 int i, fd_rand, fd_zero, fd_userfile;
221 char *buf;
222 char *devrand = "/dev/urandom";
223 char *devzero = "/dev/zero";
224 int mode = O_WRONLY | O_EXCL;
225
226 int result = 0;
227
228 #if defined(O_NOFOLLOW)
229 mode |= O_NOFOLLOW;
230 #endif
231
232 /* allocate our buffer memory. */
233 if((buf = (char *) malloc(MAXBUFFSIZE * sizeof(char))) == NULL) {
234 perror("Error ");
235 exit(1);
236 }
237
238 /* Open /dev/zero get and get a file descriptor for it */
239 if((fd_zero = open(devzero, O_RDONLY)) < 0) {
240 perror("Error ");
241 usage();
242 exit(1);
243 }
244
245 /* Open our user file, and get a file descriptor for it */
246 if((fd_userfile = open(path, mode)) < 0) {
247 perror("Error ");
248 usage();
249 exit(1);
250 }
251
252 /* Open /dev/urandom and get a file descriptor for it */
253 if((fd_rand = open(devrand, O_RDONLY)) < 0) {
254 perror("Error ");
255 usage();
256 exit(1);
257 }
258
259 /* Do each over write (rand & null) 'sflag' times (specified by cli). */
260 for(i = 0; i < sflag; i++) {
261 destroy(fd_rand, fd_userfile, buf, MAXBUFFSIZE, filesize);
262 destroy(fd_zero, fd_userfile, buf, MAXBUFFSIZE, filesize);
263 }
264
265 /* close everything open: */
266 close(fd_userfile);
267 close(fd_rand);
268 close(fd_zero);
269
270 /* Unlink our file */
271 if(unlink(path) < 0) {
272 perror("Error ");
273 exit(1);
274 }
275
276 /* Free our malloc()'d memory */
277 free(buf);
278 }
279
destroy(int fd_read,int fd_write,char * buf,int sz_buf,unsigned long filesize)280 void destroy(int fd_read, int fd_write, char *buf, int sz_buf, unsigned long filesize) {
281
282 int offset = 0;
283 int bytes_read;
284 int cursz_buf = sz_buf; // current number of bytes to fill buffer with
285
286 /* Seek to the beginning of the file. */
287 if(lseek(fd_write, offset, SEEK_SET) < 0) {
288 perror("Error ");
289 exit(1);
290 }
291
292 /* Loop through file */
293 while(offset < filesize) {
294
295 /* If the size of the file is less than MAXBUFFSIZE */
296 if((filesize - offset) < sz_buf) {
297 cursz_buf = filesize - offset;
298 }
299
300 /* Read bytes from /dev/urandom or /dev/zero */
301 if((bytes_read = read(fd_read, buf, cursz_buf)) < 0) {
302 perror("Error ");
303 exit(1);
304 }
305
306 /* Write out the bytes to the file. */
307 if(write(fd_write, buf, bytes_read) != bytes_read) {
308 perror("Error ");
309 exit(1);
310 }
311
312 offset += bytes_read;
313 }
314
315 /* fsync our data the hard disk. */
316 if((fsync(fd_write) < 0) && (errno == EIO)) {
317 perror("Error ");
318 exit(1);
319 }
320 }
321
unlink_special(char * path)322 void unlink_special(char *path) {
323 /* Unlink the special files we encounter if the -f (fflag) is set. */
324 if(unlink(path) < 0) {
325 perror("Error ");
326 exit(1);
327 }
328 }
329
usage()330 void usage() {
331 fprintf(stderr, "Usage: destroy [ -s <int> ] [ -f ] [ -q ] [ -h ] <[file(s) | directory]>\n");
332 fprintf(stderr, " -s: The number of overwrites to each file.\n");
333 fprintf(stderr, "\tThe default is set to 5, the minimum allowed is 1, and the maximum allowed is 20.\n");
334 fprintf(stderr, " -f: Enable force deletion of special file types.\n");
335 fprintf(stderr, " -q: Enable quiet output.\n");
336 fprintf(stderr, " -h: Print this help screen.\n");
337 fprintf(stderr, "\n");
338 fprintf(stderr, "\n");
339 fprintf(stderr, "View the man page file for all the info: `man 1 destroy`\n");
340 fprintf(stderr, "For more help:\n");
341 fprintf(stderr, "\tGo to: irc.freebsdhackers.net #freebsd\n");
342 fprintf(stderr, "\tOr to: http://www.mod6.net\n");
343 fprintf(stderr, "\tOr write to: modsix@gmail.com\n");
344 exit(1);
345 }
346