main.c 9.42 KB
Newer Older
1
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */
Jack Moffitt's avatar
Jack Moffitt committed
2 3 4 5 6 7 8 9 10 11
#include <stdio.h>
#include <string.h>

#include "thread.h"
#include "avl.h"
#include "log.h"
#include "sock.h"
#include "resolver.h"
#include "httpp.h"

12 13 14 15 16 17
#ifdef CHUID
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <errno.h>
#endif
Jack Moffitt's avatar
Jack Moffitt committed
18 19 20 21 22 23 24 25 26

#include "config.h"
#include "sighandler.h"

#include "global.h"
#include "os.h"
#include "connection.h"
#include "refbuf.h"
#include "client.h"
27
#include "slave.h"
Jack Moffitt's avatar
Jack Moffitt committed
28 29
#include "stats.h"
#include "logging.h"
30
#include "xslt.h"
31
#include "fserve.h"
32
#ifdef HAVE_CURL
33
#include "geturl.h"
34
#endif
Jack Moffitt's avatar
Jack Moffitt committed
35

36 37
#include <libxml/xmlmemory.h>

38 39
#ifdef _WIN32
#define snprintf _snprintf
40
#endif
41

Jack Moffitt's avatar
Jack Moffitt committed
42 43 44
#undef CATMODULE
#define CATMODULE "main"

45
static void _print_usage()
Jack Moffitt's avatar
Jack Moffitt committed
46
{
47 48 49
    printf("Usage:\n");
    printf("\ticecast -c <file>\t\tSpecify configuration file\n");
    printf("\n");
Jack Moffitt's avatar
Jack Moffitt committed
50 51
}

52 53
static void _stop_logging(void)
{
54 55
    log_close(errorlog);
    log_close(accesslog);
56 57
}

58
static void _initialize_subsystems(void)
Jack Moffitt's avatar
Jack Moffitt committed
59
{
60 61 62 63 64 65 66 67
    log_initialize();
    thread_initialize();
    sock_initialize();
    resolver_initialize();
    config_initialize();
    connection_initialize();
    global_initialize();
    refbuf_initialize();
68
    xslt_initialize();
69
#ifdef HAVE_CURL
70
    curl_initialize();
71
#endif
Jack Moffitt's avatar
Jack Moffitt committed
72 73
}

74
static void _shutdown_subsystems(void)
Jack Moffitt's avatar
Jack Moffitt committed
75
{
76
#ifdef HAVE_CURL
77
    curl_shutdown();
78
#endif
79
    fserve_shutdown();
80
    xslt_shutdown();
81 82 83
    refbuf_shutdown();
    stats_shutdown();
    slave_shutdown();
84 85

    /* Now that these are done, we can stop the loggers. */
86
    _stop_logging();
87

88 89 90 91 92 93 94
    global_shutdown();
    connection_shutdown();
    config_shutdown();
    resolver_shutdown();
    sock_shutdown();
    thread_shutdown();
    log_shutdown();
95 96

    xmlCleanupParser();
Jack Moffitt's avatar
Jack Moffitt committed
97 98
}

99
static int _parse_config_file(int argc, char **argv, char *filename, int size)
Jack Moffitt's avatar
Jack Moffitt committed
100
{
101 102
    int i = 1;
    int    processID = 0;
Jack Moffitt's avatar
Jack Moffitt committed
103

104
    if (argc < 3) return -1;
Jack Moffitt's avatar
Jack Moffitt committed
105

106 107
    while (i < argc) {
        if (strcmp(argv[i], "-b") == 0) {
108
#ifndef WIN32
109 110 111 112 113
                fprintf(stdout, "Starting icecast2\nDetaching from the console\n");
                if ((processID = (int)fork()) > 0) {
                        /* exit the parent */
                        _exit(0);
                }
114
#endif
115 116 117 118
        }
        if (strcmp(argv[i], "-c") == 0) {
            if (i + 1 < argc) {
                strncpy(filename, argv[i + 1], size-1);
119
                filename[size-1] = 0;
120 121 122 123 124 125 126 127 128
                return 1;
            } else {
                return -1;
            }
        }
        i++;
    }

    return -1;
Jack Moffitt's avatar
Jack Moffitt committed
129 130
}

131
static int _start_logging(void)
Jack Moffitt's avatar
Jack Moffitt committed
132
{
133 134 135
    char fn_error[FILENAME_MAX];
    char fn_access[FILENAME_MAX];
    ice_config_t *config = config_get_config_unlocked();
Jack Moffitt's avatar
Jack Moffitt committed
136

137
    if(strcmp(config->error_log, "-")) {
138
        snprintf(fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log);
139
        errorlog = log_open(fn_error);
140 141 142
    } else {
        errorlog = log_open_file(stderr);
    }
143
    if(strcmp(config->access_log, "-")) {
144
        snprintf(fn_access, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log);
145
        accesslog = log_open(fn_access);
146 147 148
    } else {
        accesslog = log_open_file(stderr);
    }
149 150 151 152 153 154 155 156 157 158 159 160
    
    log_set_level(errorlog, config->loglevel);
    log_set_level(accesslog, 4);

    if (errorlog < 0)
        fprintf(stderr, "FATAL: could not open %s for error logging\n", fn_error);
    if (accesslog < 0)
        fprintf(stderr, "FATAL: could not open %s for access logging\n", fn_access);

    if (errorlog >= 0 && accesslog >= 0) return 1;
    
    return 0;
Jack Moffitt's avatar
Jack Moffitt committed
161 162
}

163
static int _setup_sockets(void)
Jack Moffitt's avatar
Jack Moffitt committed
164
{
165
    ice_config_t *config;
166 167 168
    int i = 0;
    int ret = 0;
    int successful = 0;
Jack Moffitt's avatar
Jack Moffitt committed
169

170
    config = config_get_config_unlocked();
Jack Moffitt's avatar
Jack Moffitt committed
171

172 173 174 175 176 177 178
    for(i = 0; i < MAX_LISTEN_SOCKETS; i++) {
        if(config->listeners[i].port <= 0)
            break;

        global.serversock[i] = sock_get_server_socket(
                config->listeners[i].port, config->listeners[i].bind_address);

179 180
        if (global.serversock[i] == SOCK_ERROR) {
            fprintf(stderr, "Could not create listener socket on port %d\n", 
181 182 183 184 185 186 187 188
                    config->listeners[i].port);
            return 0;
        }
        else {
            ret = 1;
            successful++;
        }
    }
189

190
    global.server_sockets = successful;
191 192
    
    return ret;
Jack Moffitt's avatar
Jack Moffitt committed
193 194
}

195
static int _start_listening(void)
Jack Moffitt's avatar
Jack Moffitt committed
196
{
197 198
    int i;
    for(i=0; i < global.server_sockets; i++) {
199 200
        if (sock_listen(global.serversock[i], ICE_LISTEN_QUEUE) == SOCK_ERROR)
            return 0;
Jack Moffitt's avatar
Jack Moffitt committed
201

202
        sock_set_blocking(global.serversock[i], SOCK_NONBLOCK);
203
    }
Jack Moffitt's avatar
Jack Moffitt committed
204

205
    return 1;
Jack Moffitt's avatar
Jack Moffitt committed
206 207
}

208
/* bind the socket and start listening */
209
static int _server_proc_init(void)
Jack Moffitt's avatar
Jack Moffitt committed
210
{
211 212
    if (!_setup_sockets())
        return 0;
Jack Moffitt's avatar
Jack Moffitt committed
213

214 215 216 217
    if (!_start_listening()) {
        fprintf(stderr, "Failed trying to listen on server socket\n");
        return 0;
    }
218 219

    return 1;
220
}
Jack Moffitt's avatar
Jack Moffitt committed
221

222 223 224
/* this is the heart of the beast */
static void _server_proc(void)
{
225 226
    int i;

227
    connection_accept_loop();
Jack Moffitt's avatar
Jack Moffitt committed
228

229
    for(i=0; i < MAX_LISTEN_SOCKETS; i++)
230
        sock_close(global.serversock[i]);
Jack Moffitt's avatar
Jack Moffitt committed
231 232
}

233
/* chroot the process. Watch out - we need to do this before starting other
234
 * threads. Change uid as well, after figuring out uid _first_ */
235

Michael Smith's avatar
Michael Smith committed
236
static void _ch_root_uid_setup(void)
237
{
238
   ice_config_t *conf = config_get_config_unlocked();
239 240 241 242 243 244 245 246
#ifdef CHUID
   struct passwd *user;
   struct group *group;
   uid_t uid=-1;
   gid_t gid=-1;

   if(conf->chuid)
   {
247 248 249 250 251 252 253 254 255
       if(conf->user) {
           user = getpwnam(conf->user);
           if(user)
               uid = user->pw_uid;
           else
               fprintf(stderr, "Couldn't find user \"%s\" in password file\n", conf->user);
       }
       if(conf->group) {
           group = getgrnam(conf->group);
256

257 258 259 260 261
           if(group)
               gid = group->gr_gid;
           else
               fprintf(stderr, "Couldn't find group \"%s\" in groups file\n", conf->group);
       }
262 263 264 265
   }
#endif

#ifdef CHROOT
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
   if (conf->chroot)
   {
       if(getuid()) /* root check */
       {
           fprintf(stderr, "WARNING: Cannot change server root unless running as root.\n");
           return;
       }
       if(chroot(conf->base_dir))
       {
           fprintf(stderr,"WARNING: Couldn't change server root: %s\n", strerror(errno));
           return;
       }
       else
           fprintf(stdout, "Changed root successfully to \"%s\".\n", conf->base_dir);

   }   
#endif
#ifdef CHUID
284

285 286 287 288 289 290 291 292
   if(conf->chuid)
   {
       if(getuid()) /* root check */
       {
           fprintf(stderr, "WARNING: Can't change user id unless you are root.\n");
           return;
       }

293 294
       if(gid != -1) {
           if(!setgid(gid))
295
               fprintf(stdout, "Changed groupid to %i.\n", gid);
296 297 298
           else
               fprintf(stdout, "Error changing groupid: %s.\n", strerror(errno));
       }
299

300 301
       if(uid != -1) {
           if(!setuid(uid))
302
               fprintf(stdout, "Changed userid to %i.\n", uid);
303 304 305
           else
               fprintf(stdout, "Error changing userid: %s.\n", strerror(errno));
       }
306 307
   }
#endif
308
}
309

Jack Moffitt's avatar
Jack Moffitt committed
310 311
int main(int argc, char **argv)
{
312 313 314 315 316 317 318 319 320 321 322 323
    int res, ret;
    char filename[512];

    /* parse the '-c icecast.xml' option
    ** only, so that we can read a configfile
    */
    res = _parse_config_file(argc, argv, filename, 512);
    if (res == 1) {
        /* startup all the modules */
        _initialize_subsystems();

        /* parse the config file */
324
        config_get_config();
325
        ret = config_initial_parse_file(filename);
326
        config_release_config();
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
        if (ret < 0) {
            fprintf(stderr, "FATAL: error parsing config file:");
            switch (ret) {
            case CONFIG_EINSANE:
                fprintf(stderr, "filename was null or blank\n");
                break;
            case CONFIG_ENOROOT:
                fprintf(stderr, "no root element found\n");
                break;
            case CONFIG_EBADROOT:
                fprintf(stderr, "root element is not <icecast>\n");
                break;
            default:
                fprintf(stderr, "parse error\n");
                break;
            }
343 344
            _shutdown_subsystems();
            return 1;
345 346 347 348 349 350 351 352
        }
    } else if (res == -1) {
        _print_usage();
        return 1;
    }
    
    /* override config file options with commandline options */
    config_parse_cmdline(argc, argv);
Jack Moffitt's avatar
Jack Moffitt committed
353

354 355 356 357 358 359
    /* Bind socket, before we change userid */
    if(!_server_proc_init()) {
        fprintf(stderr, "Server startup failed. Exiting.\n");
        _shutdown_subsystems();
        return 1;
    }
360

Michael Smith's avatar
Michael Smith committed
361
    _ch_root_uid_setup(); /* Change user id and root if requested/possible */
362 363

    stats_initialize(); /* We have to do this later on because of threading */
364
    fserve_initialize(); /* This too */
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380

#ifdef CHUID 
    /* We'll only have getuid() if we also have setuid(), it's reasonable to
     * assume */
    if(!getuid()) /* Running as root! Don't allow this */
    {
        fprintf(stderr, "WARNING: You should not run icecast2 as root\n");
        fprintf(stderr, "Use the changeowner directive in the config file\n");
        _shutdown_subsystems();
        return 1;
    }
#endif

    /* setup default signal handlers */
    sighandler_initialize();

381 382 383 384 385
    if (!_start_logging()) {
        fprintf(stderr, "FATAL: Could not start logging\n");
        _shutdown_subsystems();
        return 1;
    }
Jack Moffitt's avatar
Jack Moffitt committed
386

387 388 389
    /* Do this after logging init */
    slave_initialize();

390
    INFO0("icecast server started");
Jack Moffitt's avatar
Jack Moffitt committed
391

392
    /* REM 3D Graphics */
Jack Moffitt's avatar
Jack Moffitt committed
393

394 395 396
    /* let her rip */
    global.running = ICE_RUNNING;
    _server_proc();
Jack Moffitt's avatar
Jack Moffitt committed
397

398
    INFO0("Shutting down");
Jack Moffitt's avatar
Jack Moffitt committed
399

400
    _shutdown_subsystems();
Jack Moffitt's avatar
Jack Moffitt committed
401

402
    return 0;
Jack Moffitt's avatar
Jack Moffitt committed
403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
}