main.c 18 KB
Newer Older
1 2 3 4 5
/* Icecast
 *
 * This program is distributed under the GNU General Public License, version 2.
 * A copy of this license is included with this source.
 *
6
 * Copyright 2000-2004, Jack Moffitt <jack@xiph.org,
7 8
 *                      Michael Smith <msmith@xiph.org>,
 *                      oddsock <oddsock@xiph.org>,
9
 *                      Karl Heyes <karl@xiph.org>,
10
 *                      and others (see AUTHORS for details).
11
 * Copyright 2011-2018, Philipp "ph3-der-loewe" Schafft <lion@lion.leolix.org>,
12
 * Copyright 2014,      Thomas B. Ruecker <thomas@ruecker.fi>.
13 14
 */

15
/* -*- c-basic-offset: 4; indent-tabs-mode: nil; -*- */
16 17 18 19
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

Jack Moffitt's avatar
Jack Moffitt committed
20 21
#include <stdio.h>
#include <string.h>
22 23
#include <errno.h>

24
#ifdef HAVE_CURL
25
#include "curl.h"
26 27
#endif

28
#ifdef WIN32
29
#ifndef _WIN32_WINNT
30
#define _WIN32_WINNT 0x0400
31
#endif
32 33 34 35 36 37
/* For getpid() */
#include <process.h>
#include <windows.h>
#define snprintf _snprintf
#define getpid _getpid
#endif
Jack Moffitt's avatar
Jack Moffitt committed
38

39 40 41 42
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

43 44 45 46
#ifdef HAVE_UNAME
#include <sys/utsname.h>
#endif

47 48 49 50
#include "common/thread/thread.h"
#include "common/net/sock.h"
#include "common/net/resolver.h"
#include "common/httpp/httpp.h"
Jack Moffitt's avatar
Jack Moffitt committed
51

52
#if HAVE_SYS_TYPES_H
53
#include <sys/types.h>
54 55
#endif
#if HAVE_GRP_H
56
#include <grp.h>
57 58
#endif
#if HAVE_PWD_H
59 60
#include <pwd.h>
#endif
Jack Moffitt's avatar
Jack Moffitt committed
61

62
#include "main.h"
63
#include "cfgfile.h"
64
#include "util.h"
Jack Moffitt's avatar
Jack Moffitt committed
65 66 67
#include "sighandler.h"

#include "global.h"
68
#include "compat.h"
Jack Moffitt's avatar
Jack Moffitt committed
69 70 71
#include "connection.h"
#include "refbuf.h"
#include "client.h"
72
#include "slave.h"
Jack Moffitt's avatar
Jack Moffitt committed
73 74
#include "stats.h"
#include "logging.h"
75
#include "xslt.h"
76
#include "fserve.h"
77
#include "yp.h"
78
#include "auth.h"
79
#include "event.h"
80
#include "listensocket.h"
81
#include "fastevent.h"
Jack Moffitt's avatar
Jack Moffitt committed
82

83 84
#include <libxml/xmlmemory.h>

Jack Moffitt's avatar
Jack Moffitt committed
85 86 87
#undef CATMODULE
#define CATMODULE "main"

88 89 90
static int background;
static char *pidfile = NULL;

91 92
static void pidfile_update(ice_config_t *config, int always_try);

93
static void _fatal_error(const char *perr)
94
{
95 96 97
#ifdef WIN32_SERVICE
    MessageBox(NULL, perr, "Error", MB_SERVICE_NOTIFICATION);
#elif defined(WIN32)
98 99 100 101 102 103
    MessageBox(NULL, perr, "Error", MB_OK);
#else
    fprintf(stdout, "%s\n", perr);
#endif
}

104
static void _print_usage(void)
Jack Moffitt's avatar
Jack Moffitt committed
105
{
106
    printf("%s\n\n", ICECAST_VERSION_STRING);
107 108
    printf("usage: icecast [-b] -c <file>\n");
    printf("or   : icecast {-v|--version}\n");
109
    printf("options:\n");
110 111 112
    printf("\t-c <file>       Specify configuration file\n");
    printf("\t-v or --version Display version info\n");
    printf("\t-b              Run icecast in the background\n");
113
    printf("\n");
Jack Moffitt's avatar
Jack Moffitt committed
114 115
}

116 117
static void _stop_logging(void)
{
118 119
    log_close(errorlog);
    log_close(accesslog);
120
    log_close(playlistlog);
121 122
}

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
#ifndef FASTEVENT_ENABLED
static void __fastevent_cb(const void *userdata, fastevent_type_t type, fastevent_flag_t flags, fastevent_datatype_t datatype, va_list ap)
{
    event_t *event;

    if (datatype != FASTEVENT_DATATYPE_EVENT)
        return;

    event = va_arg(ap, event_t*);

    if (event == NULL) {
        ICECAST_LOG_DEBUG("event=%p", event);
    } else {
        ICECAST_LOG_DEBUG("event=%p{.trigger='%s', ...}", event, event->trigger);
    }
}

static refobject_t fastevent_reg;
#endif

143
static void initialize_subsystems(void)
Jack Moffitt's avatar
Jack Moffitt committed
144
{
145 146
    log_initialize();
    thread_initialize();
147
    global_initialize();
148
#ifndef FASTEVENT_ENABLED
149
    fastevent_initialize();
150 151
    fastevent_reg = fastevent_register(FASTEVENT_TYPE_SLOWEVENT, __fastevent_cb, NULL, NULL);
#endif
152 153 154
    sock_initialize();
    resolver_initialize();
    config_initialize();
155
    tls_initialize();
156 157
    connection_initialize();
    refbuf_initialize();
158

159
    xslt_initialize();
160 161
#ifdef HAVE_CURL
    icecast_curl_initialize();
162
#endif
Jack Moffitt's avatar
Jack Moffitt committed
163 164
}

165
static void shutdown_subsystems(void)
Jack Moffitt's avatar
Jack Moffitt committed
166
{
167
    event_shutdown();
168
    fserve_shutdown();
169 170
    refbuf_shutdown();
    slave_shutdown();
171
    auth_shutdown();
172
    yp_shutdown();
173
    stats_shutdown();
174

175
    connection_shutdown();
176
    tls_shutdown();
177 178 179
    config_shutdown();
    resolver_shutdown();
    sock_shutdown();
180 181
#ifndef FASTEVENT_ENABLED
    refobject_unref(fastevent_reg);
182
    fastevent_shutdown();
183
#endif
184
    global_shutdown();
185
    thread_shutdown();
186

187
#ifdef HAVE_CURL
188
    icecast_curl_shutdown();
189 190
#endif

191 192
    /* Now that these are done, we can stop the loggers. */
    _stop_logging();
193
    log_shutdown();
194
    xslt_shutdown();
Jack Moffitt's avatar
Jack Moffitt committed
195 196
}

197 198 199 200 201 202
void main_config_reload(ice_config_t *config)
{
    ICECAST_LOG_DEBUG("Reloading configuration.");
    pidfile_update(config, 0);
}

203
static int _parse_config_opts(int argc, char **argv, char *filename, size_t size)
Jack Moffitt's avatar
Jack Moffitt committed
204
{
205
    int i = 1;
206 207
    int config_ok = 0;

208
    background = 0;
209 210
    if (argc < 2) {
        if (filename[0] != 0) {
211
            /* We have a default filename, so we can work with no options. */
212 213
            return 1;
        } else {
214
            /* We need at least a config filename. */
215 216 217
            return -1;
        }
    }
Jack Moffitt's avatar
Jack Moffitt committed
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
    while (i < argc) {
        if (strcmp(argv[i], "-b") == 0) {
#ifndef WIN32
            pid_t pid;
            fprintf(stdout, "Starting icecast2\nDetaching from the console\n");

            pid = fork();

            if (pid > 0) {
                /* exit the parent */
                exit(0);
            }
            else if(pid < 0) {
                fprintf(stderr, "FATAL: Unable to fork child!");
                exit(1);
            }
            background = 1;
#endif
        }
238
        if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--version") == 0) {
239
            fprintf(stdout, "%s\n", ICECAST_VERSION_STRING);
240 241 242
            exit(0);
        }

243 244 245
        if (strcmp(argv[i], "-c") == 0) {
            if (i + 1 < argc) {
                strncpy(filename, argv[i + 1], size-1);
246
                filename[size-1] = 0;
247
                config_ok = 1;
248 249 250 251
            } else {
                return -1;
            }
        }
252
        i++;
253 254
    }

255 256 257 258
    if(config_ok)
        return 1;
    else
        return -1;
Jack Moffitt's avatar
Jack Moffitt committed
259 260
}

261 262 263 264 265
static int _start_logging_stdout(void) {
    errorlog = log_open_file(stderr);
    if ( errorlog < 0 )
        return 0;

266
    log_set_level(errorlog, ICECAST_LOGLEVEL_WARN);
267 268 269 270

    return 1;
}

271
static int _start_logging(void)
Jack Moffitt's avatar
Jack Moffitt committed
272
{
273 274
    char fn_error[FILENAME_MAX];
    char fn_access[FILENAME_MAX];
275
    char fn_playlist[FILENAME_MAX];
276
    char buf[1024];
277
    int log_to_stderr;
278

279
    ice_config_t *config = config_get_config_unlocked();
Jack Moffitt's avatar
Jack Moffitt committed
280

281 282 283
    if(strcmp(config->error_log, "-") == 0) {
        /* this is already in place because of _start_logging_stdout() */
    } else {
284
        snprintf(fn_error, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->error_log);
285
        errorlog = log_open(fn_error);
286
        log_to_stderr = 0;
287 288 289
        if (config->logsize)
            log_set_trigger (errorlog, config->logsize);
        log_set_archive_timestamp(errorlog, config->logarchive);
290
    }
291 292 293

    if (errorlog < 0) {
        buf[sizeof(buf)-1] = 0;
294
        snprintf(buf, sizeof(buf)-1,
295 296
                "FATAL: could not open error logging (%s): %s",
                log_to_stderr?"standard error":fn_error,
297 298 299 300 301
                strerror(errno));
        _fatal_error(buf);
    }
    log_set_level(errorlog, config->loglevel);

302 303 304 305
    if(strcmp(config->access_log, "-") == 0) {
        accesslog = log_open_file(stderr);
        log_to_stderr = 1;
    } else {
306
        snprintf(fn_access, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->access_log);
307
        accesslog = log_open(fn_access);
308
        log_to_stderr = 0;
309 310 311
        if (config->logsize)
            log_set_trigger (accesslog, config->logsize);
        log_set_archive_timestamp(accesslog, config->logarchive);
312
    }
313 314 315

    if (accesslog < 0) {
        buf[sizeof(buf)-1] = 0;
316 317 318 319
        snprintf(buf, sizeof(buf) - 1,
            "FATAL: could not open access logging (%s): %s",
            log_to_stderr ? "standard error" : fn_access,
            strerror(errno));
320 321
        _fatal_error(buf);
    }
322 323 324 325 326 327

    if(config->playlist_log) {
        snprintf(fn_playlist, FILENAME_MAX, "%s%s%s", config->log_dir, PATH_SEPARATOR, config->playlist_log);
        playlistlog = log_open(fn_playlist);
        if (playlistlog < 0) {
            buf[sizeof(buf)-1] = 0;
328
            snprintf(buf, sizeof(buf)-1,
329 330 331 332 333 334
                "FATAL: could not open playlist logging (%s): %s",
                log_to_stderr?"standard error":fn_playlist,
                strerror(errno));
            _fatal_error(buf);
        }
        log_to_stderr = 0;
335 336 337
        if (config->logsize)
            log_set_trigger (playlistlog, config->logsize);
        log_set_archive_timestamp(playlistlog, config->logarchive);
338 339 340
    } else {
        playlistlog = -1;
    }
341

342 343
    log_set_level(errorlog, config->loglevel);
    log_set_level(accesslog, 4);
344
    log_set_level(playlistlog, 4);
345 346

    if (errorlog >= 0 && accesslog >= 0) return 1;
347

348
    return 0;
Jack Moffitt's avatar
Jack Moffitt committed
349 350
}

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
static void pidfile_update(ice_config_t *config, int always_try)
{
    char *newpidfile = NULL;

    if (config->pidfile) {
        FILE *f;

        /* check if the file actually changed */
        if (pidfile && strcmp(pidfile, config->pidfile) == 0)
            return;

        ICECAST_LOG_DEBUG("New pidfile on %H", config->pidfile);

        if (!always_try) {
            if (config->chuid) {
                ICECAST_LOG_ERROR("Can not write new pidfile, changeowner in effect.");
                return;
            }

            if (config->chroot) {
                ICECAST_LOG_ERROR("Can not write new pidfile, chroot in effect.");
                return;
            }
        }

        newpidfile = strdup(config->pidfile);
        if (!newpidfile) {
            ICECAST_LOG_ERROR("Can not allocate memory for pidfile filename. BAD.");
            return;
        }

        f = fopen(newpidfile, "w");
        if (!f) {
            free(newpidfile);
            ICECAST_LOG_ERROR("Can not open new pidfile for writing.");
            return;
        }

        fprintf(f, "%lld\n", (long long int)getpid());
        fclose(f);

392
        ICECAST_LOG_INFO("pidfile %H updated.", pidfile);
393 394 395 396 397 398 399 400 401 402
    }

    if (newpidfile != pidfile) {
        if (pidfile)
            remove(pidfile);
        free(pidfile);
        pidfile = newpidfile;
    }
}

403
/* bind the socket and start listening */
404
static int _server_proc_init(void)
Jack Moffitt's avatar
Jack Moffitt committed
405
{
406
    ice_config_t *config = config_get_config_unlocked();
407

408
    connection_setup_sockets(config);
409

410 411 412 413 414
    if (listensocket_container_sockcount(global.listensockets) < 1) {
        ICECAST_LOG_ERROR("Can not listen on any sockets.");
        return 0;
    }

415
    pidfile_update(config, 1);
416

417
    return 1;
418
}
Jack Moffitt's avatar
Jack Moffitt committed
419

420 421 422
/* this is the heart of the beast */
static void _server_proc(void)
{
423 424 425 426 427 428
    if (background)
    {
        fclose (stdin);
        fclose (stdout);
        fclose (stderr);
    }
429
    connection_accept_loop();
Jack Moffitt's avatar
Jack Moffitt committed
430

431
    connection_setup_sockets (NULL);
Jack Moffitt's avatar
Jack Moffitt committed
432 433
}

434
/* chroot the process. Watch out - we need to do this before starting other
435
 * threads. Change uid as well, after figuring out uid _first_ */
436
#if defined(HAVE_SETUID) || defined(HAVE_CHROOT) || defined(HAVE_SETUID)
437
static void _ch_root_uid_setup(void)
438
{
439
   ice_config_t *conf = config_get_config_unlocked();
440
#ifdef HAVE_SETUID
441 442 443 444 445 446 447
   struct passwd *user;
   struct group *group;
   uid_t uid=-1;
   gid_t gid=-1;

   if(conf->chuid)
   {
448 449 450 451 452 453 454 455 456
       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);
457

458 459 460 461 462
           if(group)
               gid = group->gr_gid;
           else
               fprintf(stderr, "Couldn't find group \"%s\" in groups file\n", conf->group);
       }
463 464 465
   }
#endif

466
#if HAVE_CHROOT
467 468 469 470 471 472
   if (conf->chroot)
   {
       if(getuid()) /* root check */
       {
           fprintf(stderr, "WARNING: Cannot change server root unless running as root.\n");
       }
473
       if(chroot(conf->base_dir) == -1 || chdir("/") == -1)
474 475 476 477 478 479 480
       {
           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);

481
   }
482
#endif
483

484
#if HAVE_SETUID
485 486 487 488 489 490 491 492
   if(conf->chuid)
   {
       if(getuid()) /* root check */
       {
           fprintf(stderr, "WARNING: Can't change user id unless you are root.\n");
           return;
       }

493
       if(uid != (uid_t)-1 && gid != (gid_t)-1) {
494 495 496 497 498
#ifdef HAVE_SETRESGID
           if(!setresgid(gid, gid, gid)) {
#else
           if(!setgid(gid)) {
#endif
499
               fprintf(stdout, "Changed groupid to %i.\n", (int)gid);
500
           } else {
501
               fprintf(stdout, "Error changing groupid: %s.\n", strerror(errno));
502
           }
503 504
           if(!initgroups(conf->user, gid))
               fprintf(stdout, "Changed supplementary groups based on user: %s.\n", conf->user);
505
           else
506
               fprintf(stdout, "Error changing supplementary groups: %s.\n", strerror(errno));
507 508 509 510 511
#ifdef HAVE_SETRESUID
           if(!setresuid(uid, uid, uid)) {
#else
           if(!setuid(uid)) {
#endif
512
               fprintf(stdout, "Changed userid to %i.\n", (int)uid);
513
           } else {
514
               fprintf(stdout, "Error changing userid: %s.\n", strerror(errno));
515
           }
516
       }
517 518
   }
#endif
519
}
520
#endif
521

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561
static inline void __log_system_name(void) {
    char hostname[80] = "(unknown)";
    char system[128] = "(unknown)";
    int have_hostname = 0;
#ifdef HAVE_UNAME
    struct utsname utsname;
#endif
    ice_config_t *config;

#ifdef HAVE_GETHOSTNAME
    if (gethostname(hostname, sizeof(hostname)) != 0) {
        strncpy(hostname, "(unknown)", sizeof(hostname));
    } else {
        have_hostname = 1;
    }
#endif
#ifdef HAVE_UNAME
    if(uname(&utsname) == 0) {
        snprintf(system, sizeof(system), "%s %s, %s, %s, %s",
                 utsname.sysname, utsname.release, utsname.nodename, utsname.version, utsname.machine);
        if (!have_hostname) {
            strncpy(hostname, utsname.nodename, sizeof(hostname));
            have_hostname = 1;
        }
    }
#elif defined(WIN32)
    strncpy(system, "MS Windows", sizeof(system));
#endif

   ICECAST_LOG_INFO("Running on %s; OS: %s; Address Bits: %i", hostname, system, sizeof(void*)*8);

   if (have_hostname) {
       config = config_get_config();
       if (!config->sane_hostname && util_hostcheck(hostname) == HOSTCHECK_SANE) {
           ICECAST_LOG_WARN("Hostname is not set to anything useful in <hostname>, Consider setting it to the system's name \"%s\".", hostname);
       }
       config_release_config();
   }
}

562
#ifdef WIN32_SERVICE
563 564 565 566
int mainService(int argc, char **argv)
#else
int main(int argc, char **argv)
#endif
Jack Moffitt's avatar
Jack Moffitt committed
567
{
568
    int res, ret;
569 570 571 572 573
#ifdef ICECAST_DEFAULT_CONFIG
    char filename[512] = ICECAST_DEFAULT_CONFIG;
#else
    char filename[512] = "";
#endif
574
    char pbuf[1024];
575 576 577 578

    /* parse the '-c icecast.xml' option
    ** only, so that we can read a configfile
    */
579
    res = _parse_config_opts(argc, argv, filename, sizeof(filename));
580
    if (res == 1) {
581
#if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__)
582
        /* startup all the modules */
583
        initialize_subsystems();
584 585 586 587 588
        if (!_start_logging_stdout()) {
            _fatal_error("FATAL: Could not start logging on stderr.");
            shutdown_subsystems();
            return 1;
        }
589
#endif
590
        /* parse the config file */
591
        config_get_config();
592
        ret = config_initial_parse_file(filename);
593
        config_release_config();
594
        if (ret < 0) {
595
            memset(pbuf, '\000', sizeof(pbuf));
596
            snprintf(pbuf, sizeof(pbuf)-1,
597 598
                "FATAL: error parsing config file (%s)", filename);
            _fatal_error(pbuf);
599 600
            switch (ret) {
            case CONFIG_EINSANE:
601
                _fatal_error("filename was null or blank");
602 603
                break;
            case CONFIG_ENOROOT:
604
                _fatal_error("no root element found");
605 606
                break;
            case CONFIG_EBADROOT:
607
                _fatal_error("root element is not <icecast>");
608 609
                break;
            default:
610
                _fatal_error("XML config parsing error");
611 612
                break;
            }
613
#if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__)
614 615
            shutdown_subsystems();
#endif
616
            return 1;
617 618 619 620 621
        }
    } else if (res == -1) {
        _print_usage();
        return 1;
    }
622

623 624
    /* override config file options with commandline options */
    config_parse_cmdline(argc, argv);
Jack Moffitt's avatar
Jack Moffitt committed
625

626 627
    /* Bind socket, before we change userid */
    if(!_server_proc_init()) {
628
        _fatal_error("Server startup failed. Exiting");
629
        shutdown_subsystems();
630 631
        return 1;
    }
632

633
#if defined(HAVE_SETUID) || defined(HAVE_CHROOT) || defined(HAVE_SETUID)
634
    _ch_root_uid_setup(); /* Change user id and root if requested/possible */
635
#endif
636 637

    stats_initialize(); /* We have to do this later on because of threading */
638
    fserve_initialize(); /* This too */
639

640
#ifdef HAVE_SETUID
641 642
    /* We'll only have getuid() if we also have setuid(), it's reasonable to
     * assume */
643
    if(!getuid() && getpid() != 1) /* Running as root! Don't allow this */
644
    {
645
        fprintf(stderr, "ERROR: You should not run icecast2 as root\n");
646
        fprintf(stderr, "Use the changeowner directive in the config file\n");
647
        shutdown_subsystems();
648 649 650 651 652 653 654
        return 1;
    }
#endif

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

655
    if (!_start_logging()) {
656
        _fatal_error("FATAL: Could not start logging");
657
        shutdown_subsystems();
658 659
        return 1;
    }
Jack Moffitt's avatar
Jack Moffitt committed
660

661
    ICECAST_LOG_INFO("%s server started", ICECAST_VERSION_STRING);
662
    ICECAST_LOG_INFO("Server's PID is %lli", (long long int)getpid());
663
    __log_system_name();
Jack Moffitt's avatar
Jack Moffitt committed
664

665
    /* REM 3D Graphics */
Jack Moffitt's avatar
Jack Moffitt committed
666

667
    /* let her rip */
668
    global.running = ICECAST_RUNNING;
669 670 671 672

    /* Startup yp thread */
    yp_initialize();

673 674
    /* Do this after logging init */
    slave_initialize();
675
    auth_initialise ();
676
    event_initialise();
677

678
    event_emit_global("icecast-start");
679
    _server_proc();
680
    event_emit_global("icecast-stop");
Jack Moffitt's avatar
Jack Moffitt committed
681

682
    ICECAST_LOG_INFO("Shutting down");
683
#if !defined(_WIN32) || defined(_CONSOLE) || defined(__MINGW32__) || defined(__MINGW64__)
684 685
    shutdown_subsystems();
#endif
686 687 688 689 690 691
    if (pidfile)
    {
        remove (pidfile);
        free (pidfile);
    }

692
    return 0;
Jack Moffitt's avatar
Jack Moffitt committed
693 694 695
}