vfs: check userland buffers before reading them.
[haiku.git] / src / bin / fortune.c
blob1303c53bf55b8b61c8a17d22beaa6ec0bd21d798
1 /*
2 * Copyright 2002-2009, Haiku. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
7 #include <dirent.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
16 #include <FindDirectory.h>
17 #include <OS.h>
20 static int
21 choose_file(const char *path)
23 struct dirent *dirent;
24 int count = 0;
25 int chosen;
27 DIR *dir = opendir(path);
28 if (dir == NULL)
29 return -1;
31 // count directory entries
33 while ((dirent = readdir(dir)) != NULL) {
34 if (dirent->d_name[0] == '.')
35 continue;
37 count++;
40 if (count == 0) {
41 closedir(dir);
42 return -1;
44 // choose and open entry
46 chosen = rand() % count;
47 count = 0;
48 rewinddir(dir);
50 while ((dirent = readdir(dir)) != NULL) {
51 if (dirent->d_name[0] == '.')
52 continue;
54 if (chosen <= count) {
55 char name[PATH_MAX];
56 int fd;
58 // build full path
59 strlcpy(name, path, sizeof(name));
60 strlcat(name, "/", sizeof(name));
61 strlcat(name, dirent->d_name, sizeof(name));
63 fd = open(name, O_RDONLY);
64 if (fd >= 0) {
65 closedir(dir);
66 return fd;
69 count++;
72 closedir(dir);
73 return -1;
77 int
78 main(int argc, char **argv)
80 char path[PATH_MAX] = {'\0'};
81 const char *file = path;
82 int fd;
83 char *buffer;
84 unsigned start, i;
85 unsigned count;
86 struct stat stat;
88 srand(system_time() % INT_MAX);
90 if (argc > 1) {
91 // if there are arguments, choose one randomly
92 file = argv[1 + (rand() % (argc - 1))];
93 } else if (find_directory(B_SYSTEM_DATA_DIRECTORY, -1, false, path,
94 sizeof(path)) == B_OK) {
95 strlcat(path, "/fortunes", sizeof(path));
98 fd = open(file, O_RDONLY, 0);
99 if (fd < 0) {
100 fprintf(stderr, "Couldn't open %s: %s\n", file, strerror(errno));
101 return 1;
104 if (fstat(fd, &stat) < 0) {
105 fprintf(stderr, "stat() failed: %s\n", strerror(errno));
106 return 1;
109 if (S_ISDIR(stat.st_mode)) {
110 close(fd);
112 fd = choose_file(file);
113 if (fd < 0) {
114 fprintf(stderr, "Could not find any fortune file.\n");
115 return 1;
118 if (fstat(fd, &stat) < 0) {
119 fprintf(stderr, "stat() failed: %s\n", strerror(errno));
120 return 1;
124 buffer = malloc(stat.st_size + 1);
125 if (buffer == NULL) {
126 fprintf(stderr, "Not enough memory.\n");
127 return 1;
130 if (read(fd, buffer, stat.st_size) < 0) {
131 fprintf(stderr, "Could not read from fortune file: %s\n",
132 strerror(errno));
133 return -1;
136 buffer[stat.st_size] = '\0';
137 close(fd);
139 // count fortunes
141 count = 0;
142 for (i = 0; i < stat.st_size - 2; i++) {
143 if (!strncmp(buffer + i, "\n%\n", 3)) {
144 count++;
145 i += 3;
149 if (!count) {
150 printf("Out of cookies...\n");
151 return 0;
154 count = rand() % count;
155 start = 0;
157 // find beginning & end
158 for (i = 0; i < stat.st_size - 2; i++) {
159 if (!strncmp(buffer + i, "\n%\n", 3)) {
160 if (count-- <= 0) {
161 buffer[i] = '\0';
162 break;
165 i += 3;
166 start = i;
170 puts(buffer + start);
171 return 0;