Demonstration release of the principles underpinning krsd.
[krsd] / src / config.c
1 /*
2  * rs-serve - (c) 2013 Niklas E. Cathor
3  *
4  * This program is distributed in the hope that it will be useful,
5  * but WITHOUT ANY WARRANTY; without even the implied warranty of
6  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
7  * GNU Affero General Public License for more details.
8  *
9  * You should have received a copy of the GNU Affero General Public License
10  * along with this program. If not, see <http://www.gnu.org/licenses/>.
11  */
12
13 #include "rs-serve.h"
14
15 static void print_help(const char *progname) {
16   fprintf(stderr,
17           "Usage: %s [options]\n"
18           "\n"
19           "Options:\n"
20           "  -h        | --help            - Display this text and exit.\n"
21           "  -v        | --version         - Print program version and exit.\n"
22           "  -p <port> | --port=<port>     - Bind to given port (default: 80).\n"
23           "  -n <name> | --hostname=<name> - Set hostname (defaults to local.dev).\n"
24           "  -f <file> | --log-file=<file> - Log to given file (defaults to stdout)\n"
25           "  -d        | --detach          - After starting the server, detach server\n"
26           "                                  process and exit. If you don't use this in\n"
27           "                                  combination with the --log-file option, all\n"
28           "                                  future output will be lost.\n"
29           "  --dir=<directory-name>        - Name of the directory relative to the user's\n"
30           "                                  home directory to serve data from.\n"
31           "                                  Defaults to: remotestorage\n"
32           "  --static=<directory>          - Directory from which to serve static files.\n"
33           "                                  Defaults to: /var/www/krsd\n"
34           "  --pid-file=<file>             - Write PID to given file.\n"
35           "  --stop                        - Stop a running rs-serve process. The process\n"
36           "                                  is identified by the PID file specified via\n"
37           "                                  the --pid-file option. NOTE: the --stop option\n"
38           "                                  MUST precede the --pid-file option on the\n"
39           "                                  command line for this to work.\n"
40           " --debug                        - Enable debug output.\n"
41 #if 0
42           " --auth-uri=<uri-template>      - URI of the OAuth2 endpoint. Required for webfinger.\n"
43 #endif
44           " --experimental                 - Enable experimental features\n"
45           " --ssl                          - Enable SSL.\n"
46           " --cert-path=<path>             - Set path to SSL certificate file.\n"
47           " --key-path=<path>              - Set path to SSL key file.\n"
48           " --ca-path=<path>               - Set path to SSL CA file.\n"
49           " --no-xattr                     - Don't store meta information in extended attributes.\n"
50           "                                  They will be stored in a separate Berkeley Database\n"
51           "                                  instead. Use this option if your filesystem does not\n"
52           "                                  support extended attributes or you don't want to use\n"
53           "                                  them. (NOT IMPLEMENTED)\n"
54           "\n"
55           "This program is distributed in the hope that it will be useful,\n"
56           "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
57           "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
58           "GNU Affero General Public License for more details.\n"
59           "(c) 2013 Niklas E. Cathor\n\n"
60           , progname);
61 }
62
63 static void print_version() {
64   fprintf(stderr, "rs-serve %d.%d%s\n", RS_VERSION_MAJOR, RS_VERSION_MINOR, RS_VERSION_POSTFIX);
65 }
66
67 int rs_port = 80;
68 char *rs_scheme = "http";
69 char *rs_hostname = "local.dev";
70 int rs_detach = 0;
71 FILE *rs_log_file = NULL;
72 FILE *rs_pid_file = NULL;
73 char *rs_pid_file_path = NULL;
74 char *rs_home_serve_root = NULL;
75 int rs_home_serve_root_len = 0;
76 char *rs_static_dir = NULL;
77 int rs_static_dir_len = 0;
78 int rs_stop_other = 0;
79 char *rs_auth_uri = NULL;
80 int rs_auth_uri_len = 0;
81 int rs_webfinger_enabled = 1;
82 int rs_experimental = 0;
83 int rs_use_ssl = 0;
84 char *rs_ssl_cert_path = NULL;
85 char *rs_ssl_key_path = NULL;
86 char *rs_ssl_ca_path = NULL;
87 int rs_use_xattr = 1;
88
89 void (*current_log_debug)(const char *file, int line, char *format, ...) = NULL;
90
91 static struct option long_options[] = {
92   { "port", required_argument, 0, 'p' },
93   { "hostname", required_argument, 0, 'n' },
94   { "dir", required_argument, 0, 0 },
95   { "pid-file", required_argument, 0, 0 },
96   { "stop", no_argument, 0, 0 },
97   { "log-file", required_argument, 0, 'f' },
98   { "debug", no_argument, 0, 0 },
99   { "detach", no_argument, 0, 'd' },
100   { "help", no_argument, 0, 'h' },
101   { "version", no_argument, 0, 'v' },
102   { "static", required_argument, 0, 0 },
103 #if 0
104   { "auth-uri", required_argument, 0, 0 },
105 #endif
106   { "experimental", no_argument, 0, 0 },
107   { "ssl", no_argument, 0, 0 },
108   { "cert-path", required_argument, 0, 0 },
109   { "key-path", required_argument, 0, 0 },
110   { "ca-path", required_argument, 0, 0 },
111   { "no-xattr", no_argument, 0, 0 },
112   { 0, 0, 0, 0 }
113 };
114
115 void close_pid_file() {
116   fclose(RS_PID_FILE);
117   unlink(RS_PID_FILE_PATH);
118 }
119
120 void init_config(int argc, char **argv) {
121   int opt;
122   for(;;) {
123     int opt_index = 0;
124     opt = getopt_long(argc, argv, "p:n:r:f:dhv", long_options, &opt_index);
125     if(opt == '?') {
126       // invalid option
127       exit(EXIT_FAILURE);
128     } else if(opt == -1) {
129       // no more options
130       break;
131     } else if(opt == 'p') {
132       rs_port = atoi(optarg);
133     } else if(opt == 'n') {
134       rs_hostname = optarg;
135     } else if(opt == 'f') {
136       rs_log_file = fopen(optarg, "a");
137       if(rs_log_file == NULL) {
138         perror("Failed to open log file");
139         exit(EXIT_FAILURE);
140       }
141     } else if(opt == 'd') {
142       rs_detach = 1;
143     } else if(opt == 'h') {
144       print_help(argv[0]);
145       exit(127);
146     } else if(opt == 'v') {
147       print_version();
148       exit(127);
149     } else if(opt == 0) {
150
151       const char *arg_name = long_options[opt_index].name;
152
153       // long option with no short equivalent
154       if(strcmp(arg_name, "pid-file") == 0) { // --pid-file
155         rs_pid_file_path = optarg;
156
157         // stop was requested, kill other process by pid-file
158         if(rs_stop_other) {
159           rs_pid_file = fopen(rs_pid_file_path, "r");
160           if(rs_pid_file == NULL) {
161             perror("Failed to open pid file for reading");
162             exit(EXIT_FAILURE);
163           }
164           pid_t pid;
165           fscanf(rs_pid_file, "%d", &pid);
166           if(kill(pid, SIGTERM) == 0) {
167             printf("Sent SIGTERM to process %d\n", pid);
168             exit(EXIT_SUCCESS);
169           } else {
170             fprintf(stderr, "Sending SIGTERM to process %d failed: %s\n", pid, strerror(errno));
171             exit(EXIT_FAILURE);
172           }
173         }
174
175         // open pid file (process/main stores our pid there)
176         rs_pid_file = fopen(rs_pid_file_path, "wx");
177         if(rs_pid_file == NULL) {
178           perror("Failed to open pid file");
179           exit(EXIT_FAILURE);
180         }
181         atexit(close_pid_file);
182       } else if(strcmp(arg_name, "stop") == 0) { // --stop
183         rs_stop_other = 1;
184       } else if(strcmp(arg_name, "debug") == 0) { // --debug
185         current_log_debug = do_log_debug;
186       } else if(strcmp(arg_name, "dir") == 0) { // --dir=<dirname>
187         rs_home_serve_root = optarg;
188         int len = strlen(rs_home_serve_root);
189         if(rs_home_serve_root[len - 1] == '/') {
190           // strip trailing slash.
191           rs_home_serve_root[--len] = 0;
192         }
193         rs_home_serve_root_len = len;
194       } else if(strcmp(arg_name, "static") == 0) { // --static=<dirname>
195         rs_static_dir = optarg;
196         int len = strlen(rs_static_dir);
197         if(rs_static_dir[len - 1] == '/') {
198           // strip trailing slash.
199           rs_static_dir[--len] = 0;
200         }
201         rs_static_dir = len;
202 #if 0
203       } else if(strcmp(arg_name, "auth-uri") == 0) { // --auth-uri=<uri-template>
204         rs_auth_uri = optarg;
205         rs_auth_uri_len = strlen(rs_auth_uri);
206 #endif
207       } else if(strcmp(arg_name, "experimental") == 0) { // --experimental
208         rs_experimental = 1;
209       } else if(strcmp(arg_name, "ssl") == 0) { // --ssl
210         rs_use_ssl = 1;
211         rs_scheme = "https";
212       } else if(strcmp(arg_name, "cert-path") == 0) { // --cert-path
213         rs_ssl_cert_path = optarg;
214       } else if(strcmp(arg_name, "key-path") == 0) { // --key-path
215         rs_ssl_key_path = optarg;
216       } else if(strcmp(arg_name, "ca-path") == 0) { // --ca-path
217         rs_ssl_ca_path = optarg;
218       } else if(strcmp(arg_name, "no-xattr") == 0) { // --no-xattr
219         rs_use_xattr = 0;
220       }
221     }
222   }
223
224   if(rs_home_serve_root == NULL) {
225     rs_home_serve_root = "remotestorage";
226     rs_home_serve_root_len = 13;
227   }
228
229   if(rs_static_dir == NULL) {
230     rs_static_dir = "/var/www/krsd";
231     rs_static_dir_len = 13;
232   }
233
234   if(rs_stop_other) {
235     fprintf(stderr, "ERROR: can't stop existing process without --pid-file option.\n");
236     exit(EXIT_FAILURE);
237   }
238
239   if(current_log_debug == NULL) {
240     current_log_debug = dont_log_debug;
241   }
242
243   if(rs_log_file == NULL) {
244     rs_log_file = stdout;
245   }
246
247   if(RS_USE_SSL) {
248     if(RS_SSL_CERT_PATH == NULL || RS_SSL_KEY_PATH == NULL) {
249       log_error("You need to specify at least --cert-path and --key-path options to enable SSL");
250       exit(EXIT_FAILURE);
251     }
252
253     if(rs_port == 80) {
254       rs_port = 443;
255     }
256   }
257
258   if(rs_experimental) {
259     log_info("Experimental features enabled");
260   } else {
261     log_info("Running in strict mode");
262   }
263
264 #if 0
265   if(rs_auth_uri == NULL) {
266     log_warn("No --auth-uri set, won't be able to do webfinger!");
267     rs_webfinger_enabled = 0;
268   }
269 #endif
270
271 }
272
273 void cleanup_config() {
274   // remove this?
275 }