~diwic/ubuntu/lucid/pulseaudio/bugfixes

« back to all changes in this revision

Viewing changes to src/pulsecore/core-util.c

  • Committer: Bazaar Package Importer
  • Author(s): Luke Yelavich
  • Date: 2008-11-04 15:46:00 UTC
  • mfrom: (1.2.1 upstream) (1.1.6 lenny)
  • Revision ID: james.westby@ubuntu.com-20081104154600-hlzknpcazaam0nxm
Tags: 0.9.13-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Don't build against, and create jack package. Jack is not in main.
  - Remove --disable-per-user-esound-socket from configure flags, as we still
    want per user esound sockets.
  - Remove stop links from rc0 and rc6.
  - Change default resample algorithm and bubffer size.
  - Add alsa configuration files to route alsa applications via pulseaudio.
  - Move libasound2-plugins from Recommends to Depends.
* debian/pulseaudio.preinst: When upgrading from intrepid, remove
  /etc/X11/Xsession.d/70pulseaudio, as this was used to minimize a race
  condition when starting GNOME in intrepid. This race should not exist in
  jaunty once libcanberra is built to use pulseaudio as a backend.
* Do not spawn a pulseaudio server if clients fail to find a running server.
* Remove explicit version dependency for libspeex-dev to allow the package
  to be built for now.
* Regenerate autotools files to work with Ubuntu's newer libtool/libltdl.
* debian/control: libpulsecore5 -> libpulsecore8 to match the library
  soname.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: core-util.c 2137 2008-03-27 21:20:07Z lennart $ */
2
 
 
3
1
/***
4
2
  This file is part of PulseAudio.
5
3
 
41
39
#include <sys/types.h>
42
40
#include <sys/stat.h>
43
41
#include <sys/time.h>
 
42
#include <dirent.h>
 
43
#include <regex.h>
 
44
#include <langinfo.h>
 
45
#include <sys/utsname.h>
44
46
 
45
47
#ifdef HAVE_STRTOF_L
46
48
#include <locale.h>
103
105
#define MSG_NOSIGNAL 0
104
106
#endif
105
107
 
106
 
#ifndef OS_IS_WIN32
107
 
#define PA_USER_RUNTIME_PATH_PREFIX "/tmp/pulse-"
108
 
#else
109
 
#define PA_USER_RUNTIME_PATH_PREFIX "%TEMP%\\pulse-"
110
 
#endif
111
 
 
112
108
#ifdef OS_IS_WIN32
113
109
 
114
110
#define PULSE_ROOTENV "PULSE_ROOT"
118
114
 
119
115
    strcpy(library_path, PULSE_ROOTENV "=");
120
116
 
 
117
    /* FIXME: Needs to set errno */
 
118
 
121
119
    if (!GetModuleFileName(handle, library_path + sizeof(PULSE_ROOTENV), MAX_PATH))
122
120
        return 0;
123
121
 
175
173
/** Creates a directory securely */
176
174
int pa_make_secure_dir(const char* dir, mode_t m, uid_t uid, gid_t gid) {
177
175
    struct stat st;
178
 
    int r;
 
176
    int r, saved_errno;
179
177
 
180
178
    pa_assert(dir);
181
179
 
184
182
#else
185
183
    {
186
184
    mode_t u;
187
 
    u = umask(~m);
 
185
    u = umask((~m) & 0777);
188
186
    r = mkdir(dir, m);
189
187
    umask(u);
190
188
    }
221
219
        goto fail;
222
220
    }
223
221
#else
224
 
    pa_log_warn("secure directory creation not supported on Win32.");
 
222
    pa_log_warn("Secure directory creation not supported on Win32.");
225
223
#endif
226
224
 
227
225
    return 0;
228
226
 
229
227
fail:
 
228
    saved_errno = errno;
230
229
    rmdir(dir);
 
230
    errno = saved_errno;
 
231
 
231
232
    return -1;
232
233
}
233
234
 
237
238
 
238
239
    if ((slash = (char*) pa_path_get_filename(dir)) == dir) {
239
240
        pa_xfree(dir);
 
241
        errno = ENOENT;
240
242
        return NULL;
241
243
    }
242
244
 
344
346
 
345
347
        ret += r;
346
348
        data = (uint8_t*) data + r;
347
 
        size -= r;
 
349
        size -= (size_t) r;
348
350
    }
349
351
 
350
352
    return ret;
375
377
 
376
378
        ret += r;
377
379
        data = (const uint8_t*) data + r;
378
 
        size -= r;
 
380
        size -= (size_t) r;
379
381
    }
380
382
 
381
383
    return ret;
397
399
    }
398
400
#endif
399
401
 
400
 
    return close(fd);
 
402
    for (;;) {
 
403
        int r;
 
404
 
 
405
        if ((r = close(fd)) >= 0)
 
406
            return r;
 
407
 
 
408
        if (errno != EINTR)
 
409
            return r;
 
410
    }
401
411
}
402
412
 
403
413
/* Print a warning messages in case that the given signal is not
444
454
/* The following function is based on an example from the GNU libc
445
455
 * documentation. This function is similar to GNU's asprintf(). */
446
456
char *pa_sprintf_malloc(const char *format, ...) {
447
 
    int  size = 100;
 
457
    size_t  size = 100;
448
458
    char *c = NULL;
449
459
 
450
460
    pa_assert(format);
461
471
 
462
472
        c[size-1] = 0;
463
473
 
464
 
        if (r > -1 && r < size)
 
474
        if (r > -1 && (size_t) r < size)
465
475
            return c;
466
476
 
467
477
        if (r > -1)    /* glibc 2.1 */
468
 
            size = r+1;
 
478
            size = (size_t) r+1;
469
479
        else           /* glibc 2.0 */
470
480
            size *= 2;
471
481
    }
474
484
/* Same as the previous function, but use a va_list instead of an
475
485
 * ellipsis */
476
486
char *pa_vsprintf_malloc(const char *format, va_list ap) {
477
 
    int  size = 100;
 
487
    size_t  size = 100;
478
488
    char *c = NULL;
479
489
 
480
490
    pa_assert(format);
491
501
 
492
502
        c[size-1] = 0;
493
503
 
494
 
        if (r > -1 && r < size)
 
504
        if (r > -1 && (size_t) r < size)
495
505
            return c;
496
506
 
497
507
        if (r > -1)    /* glibc 2.1 */
498
 
            size = r+1;
 
508
            size = (size_t) r+1;
499
509
        else           /* glibc 2.0 */
500
510
            size *= 2;
501
511
    }
553
563
    pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
554
564
    return 0;
555
565
#else
 
566
 
 
567
    errno = ENOTSUP;
556
568
    return -1;
557
569
#endif
558
570
}
559
571
 
 
572
/* This is merely used for giving the user a hint. This is not correct
 
573
 * for anything security related */
 
574
pa_bool_t pa_can_realtime(void) {
 
575
 
 
576
    if (geteuid() == 0)
 
577
        return TRUE;
 
578
 
 
579
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
 
580
    {
 
581
        struct rlimit rl;
 
582
 
 
583
        if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
 
584
            if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
 
585
                return TRUE;
 
586
    }
 
587
#endif
 
588
 
 
589
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
 
590
    {
 
591
        cap_t cap;
 
592
 
 
593
        if ((cap = cap_get_proc())) {
 
594
            cap_flag_value_t flag = CAP_CLEAR;
 
595
 
 
596
            if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
 
597
                if (flag == CAP_SET) {
 
598
                    cap_free(cap);
 
599
                    return TRUE;
 
600
                }
 
601
 
 
602
            cap_free(cap);
 
603
        }
 
604
    }
 
605
#endif
 
606
 
 
607
    return FALSE;
 
608
}
 
609
 
 
610
/* This is merely used for giving the user a hint. This is not correct
 
611
 * for anything security related */
 
612
pa_bool_t pa_can_high_priority(void) {
 
613
 
 
614
    if (geteuid() == 0)
 
615
        return TRUE;
 
616
 
 
617
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
 
618
    {
 
619
        struct rlimit rl;
 
620
 
 
621
        if (getrlimit(RLIMIT_NICE, &rl) >= 0)
 
622
            if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
 
623
                return TRUE;
 
624
    }
 
625
#endif
 
626
 
 
627
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
 
628
    {
 
629
        cap_t cap;
 
630
 
 
631
        if ((cap = cap_get_proc())) {
 
632
            cap_flag_value_t flag = CAP_CLEAR;
 
633
 
 
634
            if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
 
635
                if (flag == CAP_SET) {
 
636
                    cap_free(cap);
 
637
                    return TRUE;
 
638
                }
 
639
 
 
640
            cap_free(cap);
 
641
        }
 
642
    }
 
643
#endif
 
644
 
 
645
    return FALSE;
 
646
}
 
647
 
560
648
/* Raise the priority of the current process as much as possible that
561
649
 * is <= the specified nice level..*/
562
650
int pa_raise_priority(int nice_level) {
584
672
    if (nice_level < 0) {
585
673
        if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
586
674
            pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
 
675
            errno = EPERM;
587
676
            return .-1;
588
677
        } else
589
678
            pa_log_info("Successfully gained high priority class.");
610
699
#endif
611
700
}
612
701
 
 
702
static int match(const char *expr, const char *v) {
 
703
    int k;
 
704
    regex_t re;
 
705
    int r;
 
706
 
 
707
    if (regcomp(&re, expr, REG_NOSUB|REG_EXTENDED) != 0) {
 
708
        errno = EINVAL;
 
709
        return -1;
 
710
    }
 
711
 
 
712
    if ((k = regexec(&re, v, 0, NULL, 0)) == 0)
 
713
        r = 1;
 
714
    else if (k == REG_NOMATCH)
 
715
        r = 0;
 
716
    else
 
717
        r = -1;
 
718
 
 
719
    regfree(&re);
 
720
 
 
721
    if (r < 0)
 
722
        errno = EINVAL;
 
723
 
 
724
    return r;
 
725
}
 
726
 
613
727
/* Try to parse a boolean string value.*/
614
728
int pa_parse_boolean(const char *v) {
 
729
    const char *expr;
 
730
    int r;
 
731
    pa_assert(v);
615
732
 
 
733
    /* First we check language independant */
616
734
    if (!strcmp(v, "1") || v[0] == 'y' || v[0] == 'Y' || v[0] == 't' || v[0] == 'T' || !strcasecmp(v, "on"))
617
735
        return 1;
618
736
    else if (!strcmp(v, "0") || v[0] == 'n' || v[0] == 'N' || v[0] == 'f' || v[0] == 'F' || !strcasecmp(v, "off"))
619
737
        return 0;
620
738
 
 
739
    /* And then we check language dependant */
 
740
    if ((expr = nl_langinfo(YESEXPR)))
 
741
        if (expr[0])
 
742
            if ((r = match(expr, v)) > 0)
 
743
                return 1;
 
744
 
 
745
    if ((expr = nl_langinfo(NOEXPR)))
 
746
        if (expr[0])
 
747
            if ((r = match(expr, v)) > 0)
 
748
                return 0;
 
749
 
 
750
    errno = EINVAL;
621
751
    return -1;
622
752
}
623
753
 
805
935
#else
806
936
    n = -1;
807
937
#endif
808
 
    if (n < 0) n = 512;
809
 
    data = pa_xmalloc(n);
810
 
 
811
 
    if (getgrgid_r(gid, &group, data, n, &result) < 0 || !result) {
812
 
        pa_log("getgrgid_r(%u): %s", (unsigned)gid, pa_cstrerror(errno));
 
938
    if (n < 0)
 
939
        n = 512;
 
940
 
 
941
    data = pa_xmalloc((size_t) n);
 
942
 
 
943
    errno = 0;
 
944
    if (getgrgid_r(gid, &group, data, (size_t) n, &result) < 0 || !result) {
 
945
        pa_log("getgrgid_r(%u): %s", (unsigned) gid, pa_cstrerror(errno));
 
946
 
 
947
        if (!errno)
 
948
            errno = ENOENT;
 
949
 
813
950
        goto finish;
814
951
    }
815
952
 
820
957
#else
821
958
    /* XXX Not thread-safe, but needed on OSes (e.g. FreeBSD 4.X) that do not
822
959
     * support getgrgid_r. */
 
960
 
 
961
    errno = 0;
823
962
    if ((result = getgrgid(gid)) == NULL) {
824
963
        pa_log("getgrgid(%u): %s", gid, pa_cstrerror(errno));
 
964
 
 
965
        if (!errno)
 
966
            errno = ENOENT;
 
967
 
825
968
        goto finish;
826
969
    }
827
970
 
836
979
/* Check the current user is member of the specified group */
837
980
int pa_own_uid_in_group(const char *name, gid_t *gid) {
838
981
    GETGROUPS_T *gids, tgid;
839
 
    int n = sysconf(_SC_NGROUPS_MAX);
840
 
    int r = -1, i;
 
982
    long n = sysconf(_SC_NGROUPS_MAX);
 
983
    int r = -1, i, k;
841
984
 
842
985
    pa_assert(n > 0);
843
986
 
844
 
    gids = pa_xmalloc(sizeof(GETGROUPS_T)*n);
 
987
    gids = pa_xmalloc(sizeof(GETGROUPS_T) * (size_t) n);
845
988
 
846
 
    if ((n = getgroups(n, gids)) < 0) {
 
989
    if ((n = getgroups((int) n, gids)) < 0) {
847
990
        pa_log("getgroups(): %s", pa_cstrerror(errno));
848
991
        goto finish;
849
992
    }
850
993
 
851
994
    for (i = 0; i < n; i++) {
852
 
        if (is_group(gids[i], name) > 0) {
 
995
 
 
996
        if ((k = is_group(gids[i], name)) < 0)
 
997
            goto finish;
 
998
        else if (k > 0) {
853
999
            *gid = gids[i];
854
1000
            r = 1;
855
1001
            goto finish;
856
1002
        }
857
1003
    }
858
1004
 
859
 
    if (is_group(tgid = getgid(), name) > 0) {
 
1005
    if ((k = is_group(tgid = getgid(), name)) < 0)
 
1006
        goto finish;
 
1007
    else if (k > 0) {
860
1008
        *gid = tgid;
861
1009
        r = 1;
862
1010
        goto finish;
879
1027
    int r = -1;
880
1028
 
881
1029
    g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
882
 
    g_buf = pa_xmalloc(g_n);
 
1030
    g_buf = pa_xmalloc((size_t) g_n);
883
1031
 
884
1032
    p_n = sysconf(_SC_GETPW_R_SIZE_MAX);
885
 
    p_buf = pa_xmalloc(p_n);
886
 
 
887
 
    if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
 
1033
    p_buf = pa_xmalloc((size_t) p_n);
 
1034
 
 
1035
    errno = 0;
 
1036
    if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
 
1037
 
 
1038
        if (!errno)
 
1039
            errno = ENOENT;
 
1040
 
888
1041
        goto finish;
 
1042
    }
889
1043
 
890
1044
    r = 0;
891
1045
    for (i = gr->gr_mem; *i; i++) {
892
1046
        struct passwd pwbuf, *pw;
893
1047
 
 
1048
        errno = 0;
894
1049
        if (getpwnam_r(*i, &pwbuf, p_buf, (size_t) p_n, &pw) != 0 || !pw)
895
1050
            continue;
896
1051
 
915
1070
    struct group grbuf, *gr;
916
1071
 
917
1072
    g_n = sysconf(_SC_GETGR_R_SIZE_MAX);
918
 
    g_buf = pa_xmalloc(g_n);
919
 
 
920
 
    if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr)
 
1073
    g_buf = pa_xmalloc((size_t) g_n);
 
1074
 
 
1075
    errno = 0;
 
1076
    if (getgrnam_r(name, &grbuf, g_buf, (size_t) g_n, &gr) != 0 || !gr) {
 
1077
 
 
1078
        if (!errno)
 
1079
            errno = ENOENT;
 
1080
 
921
1081
        goto finish;
 
1082
    }
922
1083
 
923
1084
    ret = gr->gr_gid;
924
1085
 
944
1105
#else /* HAVE_GRP_H */
945
1106
 
946
1107
int pa_own_uid_in_group(const char *name, gid_t *gid) {
 
1108
    errno = ENOSUP;
947
1109
    return -1;
948
1110
 
949
1111
}
950
1112
 
951
1113
int pa_uid_in_group(uid_t uid, const char *name) {
 
1114
    errno = ENOSUP;
952
1115
    return -1;
953
1116
}
954
1117
 
955
1118
gid_t pa_get_gid_of_group(const char *name) {
 
1119
    errno = ENOSUP;
956
1120
    return (gid_t) -1;
957
1121
}
958
1122
 
959
1123
int pa_check_in_group(gid_t g) {
 
1124
    errno = ENOSUP;
960
1125
    return -1;
961
1126
}
962
1127
 
970
1135
 
971
1136
    /* Try a R/W lock first */
972
1137
 
973
 
    flock.l_type = b ? F_WRLCK : F_UNLCK;
 
1138
    flock.l_type = (short) (b ? F_WRLCK : F_UNLCK);
974
1139
    flock.l_whence = SEEK_SET;
975
1140
    flock.l_start = 0;
976
1141
    flock.l_len = 0;
997
1162
        return 0;
998
1163
 
999
1164
    pa_log("%slock failed: 0x%08X", !b ? "un" : "", GetLastError());
 
1165
 
 
1166
    /* FIXME: Needs to set errno! */
1000
1167
#endif
1001
1168
 
1002
1169
    return -1;
1063
1230
 
1064
1231
fail:
1065
1232
 
1066
 
    if (fd >= 0)
 
1233
    if (fd >= 0) {
 
1234
        int saved_errno = errno;
1067
1235
        pa_close(fd);
 
1236
        errno = saved_errno;
 
1237
    }
1068
1238
 
1069
1239
    return -1;
1070
1240
}
1072
1242
/* Unlock a temporary lcok file */
1073
1243
int pa_unlock_lockfile(const char *fn, int fd) {
1074
1244
    int r = 0;
1075
 
    pa_assert(fn);
1076
1245
    pa_assert(fd >= 0);
1077
1246
 
1078
 
    if (unlink(fn) < 0) {
1079
 
        pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
1080
 
        r = -1;
 
1247
    if (fn) {
 
1248
        if (unlink(fn) < 0) {
 
1249
            pa_log_warn("Unable to remove lock file '%s': %s", fn, pa_cstrerror(errno));
 
1250
            r = -1;
 
1251
        }
1081
1252
    }
1082
1253
 
1083
1254
    if (pa_lock_fd(fd, 0) < 0) {
1093
1264
    return r;
1094
1265
}
1095
1266
 
 
1267
static char *get_pulse_home(void) {
 
1268
    char h[PATH_MAX];
 
1269
    struct stat st;
 
1270
 
 
1271
    if (!pa_get_home_dir(h, sizeof(h))) {
 
1272
        pa_log_error("Failed to get home directory.");
 
1273
        return NULL;
 
1274
    }
 
1275
 
 
1276
    if (stat(h, &st) < 0) {
 
1277
        pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
 
1278
        return NULL;
 
1279
    }
 
1280
 
 
1281
    if (st.st_uid != getuid()) {
 
1282
        pa_log_error("Home directory %s not ours.", h);
 
1283
        errno = EACCES;
 
1284
        return NULL;
 
1285
    }
 
1286
 
 
1287
    return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
 
1288
}
 
1289
 
 
1290
char *pa_get_state_dir(void) {
 
1291
    char *d;
 
1292
 
 
1293
    /* The state directory shall contain dynamic data that should be
 
1294
     * kept across reboots, and is private to this user */
 
1295
 
 
1296
    if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
 
1297
        if (!(d = get_pulse_home()))
 
1298
            return NULL;
 
1299
 
 
1300
    /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
 
1301
     * dir then this will break. */
 
1302
 
 
1303
    if (pa_make_secure_dir(d, 0700U, (uid_t) -1, (gid_t) -1) < 0)  {
 
1304
        pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 
1305
        pa_xfree(d);
 
1306
        return NULL;
 
1307
    }
 
1308
 
 
1309
    return d;
 
1310
}
 
1311
 
 
1312
static char* make_random_dir(mode_t m) {
 
1313
    static const char table[] =
 
1314
        "abcdefghijklmnopqrstuvwxyz"
 
1315
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 
1316
        "0123456789";
 
1317
 
 
1318
    const char *tmpdir;
 
1319
    char *fn;
 
1320
    size_t pathlen;
 
1321
 
 
1322
    if (!(tmpdir = getenv("TMPDIR")))
 
1323
        if (!(tmpdir = getenv("TMP")))
 
1324
            if (!(tmpdir = getenv("TEMP")))
 
1325
                tmpdir = getenv("TEMPDIR");
 
1326
 
 
1327
    if (!tmpdir || !pa_is_path_absolute(tmpdir))
 
1328
        tmpdir = "/tmp";
 
1329
 
 
1330
    fn = pa_sprintf_malloc("%s/pulse-XXXXXXXXXXXX", tmpdir);
 
1331
    pathlen = strlen(fn);
 
1332
 
 
1333
    for (;;) {
 
1334
        size_t i;
 
1335
        int r;
 
1336
        mode_t u;
 
1337
        int saved_errno;
 
1338
 
 
1339
        for (i = pathlen - 12; i < pathlen; i++)
 
1340
            fn[i] = table[rand() % (sizeof(table)-1)];
 
1341
 
 
1342
        u = umask((~m) & 0777);
 
1343
        r = mkdir(fn, m);
 
1344
 
 
1345
        saved_errno = errno;
 
1346
        umask(u);
 
1347
        errno = saved_errno;
 
1348
 
 
1349
        if (r >= 0)
 
1350
            return fn;
 
1351
 
 
1352
        if (errno != EEXIST) {
 
1353
            pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
 
1354
            pa_xfree(fn);
 
1355
            return NULL;
 
1356
        }
 
1357
    }
 
1358
}
 
1359
 
 
1360
static int make_random_dir_and_link(mode_t m, const char *k) {
 
1361
    char *p;
 
1362
 
 
1363
    if (!(p = make_random_dir(m)))
 
1364
        return -1;
 
1365
 
 
1366
    if (symlink(p, k) < 0) {
 
1367
        int saved_errno = errno;
 
1368
 
 
1369
        if (errno != EEXIST)
 
1370
            pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
 
1371
 
 
1372
        rmdir(p);
 
1373
        pa_xfree(p);
 
1374
 
 
1375
        errno = saved_errno;
 
1376
        return -1;
 
1377
    }
 
1378
 
 
1379
    return 0;
 
1380
}
 
1381
 
 
1382
char *pa_get_runtime_dir(void) {
 
1383
    char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
 
1384
    struct stat st;
 
1385
    mode_t m;
 
1386
 
 
1387
    /* The runtime directory shall contain dynamic data that needs NOT
 
1388
     * to be kept accross reboots and is usuallly private to the user,
 
1389
     * except in system mode, where it might be accessible by other
 
1390
     * users, too. Since we need POSIX locking and UNIX sockets in
 
1391
     * this directory, we link it to a random subdir in /tmp, if it
 
1392
     * was not explicitly configured. */
 
1393
 
 
1394
    m = pa_in_system_mode() ? 0755U : 0700U;
 
1395
 
 
1396
    if ((d = getenv("PULSE_RUNTIME_PATH"))) {
 
1397
 
 
1398
        if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0)  {
 
1399
            pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 
1400
            goto fail;
 
1401
        }
 
1402
 
 
1403
        return pa_xstrdup(d);
 
1404
    }
 
1405
 
 
1406
    if (!(d = get_pulse_home()))
 
1407
        goto fail;
 
1408
 
 
1409
    if (pa_make_secure_dir(d, m, (uid_t) -1, (gid_t) -1) < 0)  {
 
1410
        pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 
1411
        goto fail;
 
1412
    }
 
1413
 
 
1414
    if (!(mid = pa_machine_id())) {
 
1415
        pa_xfree(d);
 
1416
        goto fail;
 
1417
    }
 
1418
 
 
1419
    k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
 
1420
    pa_xfree(d);
 
1421
    pa_xfree(mid);
 
1422
 
 
1423
    for (;;) {
 
1424
        /* OK, first let's check if the "runtime" symlink is already
 
1425
         * existant */
 
1426
 
 
1427
        if (!(p = pa_readlink(k))) {
 
1428
 
 
1429
            if (errno != ENOENT) {
 
1430
                pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
 
1431
                goto fail;
 
1432
            }
 
1433
 
 
1434
            /* Hmm, so the runtime directory didn't exist yet, so let's
 
1435
             * create one in /tmp and symlink that to it */
 
1436
 
 
1437
            if (make_random_dir_and_link(0700, k) < 0) {
 
1438
 
 
1439
                /* Mhmm, maybe another process was quicker than us,
 
1440
                 * let's check if that was valid */
 
1441
                if (errno == EEXIST)
 
1442
                    continue;
 
1443
 
 
1444
                goto fail;
 
1445
            }
 
1446
 
 
1447
            return k;
 
1448
        }
 
1449
 
 
1450
        /* Make sure that this actually makes sense */
 
1451
        if (!pa_is_path_absolute(p)) {
 
1452
            pa_log_error("Path %s in link %s is not absolute.", p, k);
 
1453
            errno = ENOENT;
 
1454
            goto fail;
 
1455
        }
 
1456
 
 
1457
        /* Hmm, so this symlink is still around, make sure nobody fools
 
1458
         * us */
 
1459
 
 
1460
        if (lstat(p, &st) < 0) {
 
1461
 
 
1462
            if (errno != ENOENT) {
 
1463
                pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
 
1464
                goto fail;
 
1465
            }
 
1466
 
 
1467
        } else {
 
1468
 
 
1469
            if (S_ISDIR(st.st_mode) &&
 
1470
                (st.st_uid == getuid()) &&
 
1471
                ((st.st_mode & 0777) == 0700)) {
 
1472
 
 
1473
                pa_xfree(p);
 
1474
                return k;
 
1475
            }
 
1476
 
 
1477
            pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
 
1478
        }
 
1479
 
 
1480
        pa_xfree(p);
 
1481
        p = NULL;
 
1482
 
 
1483
        /* Hmm, so the link points to some nonexisting or invalid
 
1484
         * dir. Let's replace it by a new link. We first create a
 
1485
         * temporary link and then rename that to allow concurrent
 
1486
         * execution of this function. */
 
1487
 
 
1488
        t = pa_sprintf_malloc("%s.tmp", k);
 
1489
 
 
1490
        if (make_random_dir_and_link(0700, t) < 0) {
 
1491
 
 
1492
            if (errno != EEXIST) {
 
1493
                pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
 
1494
                goto fail;
 
1495
            }
 
1496
 
 
1497
            pa_xfree(t);
 
1498
            t = NULL;
 
1499
 
 
1500
            /* Hmm, someone lese was quicker then us. Let's give
 
1501
             * him some time to finish, and retry. */
 
1502
            pa_msleep(10);
 
1503
            continue;
 
1504
        }
 
1505
 
 
1506
        /* OK, we succeeded in creating the temporary symlink, so
 
1507
         * let's rename it */
 
1508
        if (rename(t, k) < 0) {
 
1509
            pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
 
1510
            goto fail;
 
1511
        }
 
1512
 
 
1513
        pa_xfree(t);
 
1514
        return k;
 
1515
    }
 
1516
 
 
1517
fail:
 
1518
    pa_xfree(p);
 
1519
    pa_xfree(k);
 
1520
    pa_xfree(t);
 
1521
 
 
1522
    return NULL;
 
1523
}
 
1524
 
1096
1525
/* Try to open a configuration file. If "env" is specified, open the
1097
1526
 * value of the specified environment variable. Otherwise look for a
1098
1527
 * file "local" in the home directory or a file "global" in global
1099
1528
 * file system. If "result" is non-NULL, a pointer to a newly
1100
1529
 * allocated buffer containing the used configuration file is
1101
1530
 * stored there.*/
1102
 
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result, const char *mode) {
1103
 
    const char *fn;
1104
 
    char h[PATH_MAX];
1105
 
 
1106
 
#ifdef OS_IS_WIN32
1107
 
    char buf[PATH_MAX];
1108
 
 
1109
 
    if (!getenv(PULSE_ROOTENV))
1110
 
        pa_set_root(NULL);
1111
 
#endif
1112
 
 
1113
 
    if (env && (fn = getenv(env))) {
1114
 
#ifdef OS_IS_WIN32
1115
 
        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
1116
 
            return NULL;
1117
 
        fn = buf;
1118
 
#endif
1119
 
 
1120
 
        if (result)
1121
 
            *result = pa_xstrdup(fn);
1122
 
 
1123
 
        return fopen(fn, mode);
1124
 
    }
1125
 
 
1126
 
    if (local) {
1127
 
        const char *e;
1128
 
        char *lfn = NULL;
1129
 
 
1130
 
        if ((e = getenv("PULSE_CONFIG_PATH")))
1131
 
            fn = lfn = pa_sprintf_malloc("%s/%s", e, local);
1132
 
        else if (pa_get_home_dir(h, sizeof(h))) {
1133
 
            char *d;
1134
 
 
1135
 
            d = pa_sprintf_malloc("%s/.pulse", h);
1136
 
            mkdir(d, 0755);
1137
 
            pa_xfree(d);
1138
 
 
1139
 
            fn = lfn = pa_sprintf_malloc("%s/.pulse/%s", h, local);
1140
 
        }
1141
 
 
1142
 
        if (lfn) {
1143
 
            FILE *f;
1144
 
 
1145
 
#ifdef OS_IS_WIN32
1146
 
            if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX))
1147
 
                return NULL;
1148
 
            fn = buf;
1149
 
#endif
1150
 
 
1151
 
            f = fopen(fn, mode);
1152
 
            if (f != NULL) {
1153
 
                if (result)
1154
 
                    *result = pa_xstrdup(fn);
1155
 
                pa_xfree(lfn);
1156
 
                return f;
1157
 
            }
1158
 
 
1159
 
            if (errno != ENOENT)
1160
 
                pa_log_warn("Failed to open configuration file '%s': %s", lfn, pa_cstrerror(errno));
1161
 
 
1162
 
            pa_xfree(lfn);
1163
 
        }
1164
 
    }
1165
 
 
1166
 
    if (!global) {
1167
 
        if (result)
1168
 
            *result = NULL;
1169
 
        errno = ENOENT;
1170
 
        return NULL;
1171
 
    }
1172
 
 
1173
 
#ifdef OS_IS_WIN32
1174
 
    if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
1175
 
        return NULL;
1176
 
    global = buf;
1177
 
#endif
1178
 
 
1179
 
    if (result)
1180
 
        *result = pa_xstrdup(global);
1181
 
 
1182
 
    return fopen(global, mode);
 
1531
FILE *pa_open_config_file(const char *global, const char *local, const char *env, char **result) {
 
1532
    const char *fn;
 
1533
#ifdef OS_IS_WIN32
 
1534
    char buf[PATH_MAX];
 
1535
 
 
1536
    if (!getenv(PULSE_ROOTENV))
 
1537
        pa_set_root(NULL);
 
1538
#endif
 
1539
 
 
1540
    if (env && (fn = getenv(env))) {
 
1541
        FILE *f;
 
1542
 
 
1543
#ifdef OS_IS_WIN32
 
1544
        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
 
1545
            /* FIXME: Needs to set errno! */
 
1546
            return NULL;
 
1547
        fn = buf;
 
1548
#endif
 
1549
 
 
1550
        if ((f = fopen(fn, "r"))) {
 
1551
            if (result)
 
1552
                *result = pa_xstrdup(fn);
 
1553
 
 
1554
            return f;
 
1555
        }
 
1556
 
 
1557
        pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
 
1558
        return NULL;
 
1559
    }
 
1560
 
 
1561
    if (local) {
 
1562
        const char *e;
 
1563
        char *lfn;
 
1564
        char h[PATH_MAX];
 
1565
        FILE *f;
 
1566
 
 
1567
        if ((e = getenv("PULSE_CONFIG_PATH")))
 
1568
            fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
 
1569
        else if (pa_get_home_dir(h, sizeof(h)))
 
1570
            fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
 
1571
        else
 
1572
            return NULL;
 
1573
 
 
1574
#ifdef OS_IS_WIN32
 
1575
        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
 
1576
            /* FIXME: Needs to set errno! */
 
1577
            pa_xfree(lfn);
 
1578
            return NULL;
 
1579
        }
 
1580
        fn = buf;
 
1581
#endif
 
1582
 
 
1583
        if ((f = fopen(fn, "r"))) {
 
1584
            if (result)
 
1585
                *result = pa_xstrdup(fn);
 
1586
 
 
1587
            pa_xfree(lfn);
 
1588
            return f;
 
1589
        }
 
1590
 
 
1591
        if (errno != ENOENT) {
 
1592
            pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
 
1593
            pa_xfree(lfn);
 
1594
            return NULL;
 
1595
        }
 
1596
 
 
1597
        pa_xfree(lfn);
 
1598
    }
 
1599
 
 
1600
    if (global) {
 
1601
        FILE *f;
 
1602
 
 
1603
#ifdef OS_IS_WIN32
 
1604
        if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
 
1605
            /* FIXME: Needs to set errno! */
 
1606
            return NULL;
 
1607
        global = buf;
 
1608
#endif
 
1609
 
 
1610
        if ((f = fopen(global, "r"))) {
 
1611
 
 
1612
            if (result)
 
1613
                *result = pa_xstrdup(global);
 
1614
 
 
1615
            return f;
 
1616
        }
 
1617
    }
 
1618
 
 
1619
    errno = ENOENT;
 
1620
    return NULL;
 
1621
}
 
1622
 
 
1623
char *pa_find_config_file(const char *global, const char *local, const char *env) {
 
1624
    const char *fn;
 
1625
#ifdef OS_IS_WIN32
 
1626
    char buf[PATH_MAX];
 
1627
 
 
1628
    if (!getenv(PULSE_ROOTENV))
 
1629
        pa_set_root(NULL);
 
1630
#endif
 
1631
 
 
1632
    if (env && (fn = getenv(env))) {
 
1633
 
 
1634
#ifdef OS_IS_WIN32
 
1635
        if (!ExpandEnvironmentStrings(fn, buf, PATH_MAX))
 
1636
            /* FIXME: Needs to set errno! */
 
1637
            return NULL;
 
1638
        fn = buf;
 
1639
#endif
 
1640
 
 
1641
        if (access(fn, R_OK) == 0)
 
1642
            return pa_xstrdup(fn);
 
1643
 
 
1644
        pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
 
1645
        return NULL;
 
1646
    }
 
1647
 
 
1648
    if (local) {
 
1649
        const char *e;
 
1650
        char *lfn;
 
1651
        char h[PATH_MAX];
 
1652
 
 
1653
        if ((e = getenv("PULSE_CONFIG_PATH")))
 
1654
            fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", e, local);
 
1655
        else if (pa_get_home_dir(h, sizeof(h)))
 
1656
            fn = lfn = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse" PA_PATH_SEP "%s", h, local);
 
1657
        else
 
1658
            return NULL;
 
1659
 
 
1660
#ifdef OS_IS_WIN32
 
1661
        if (!ExpandEnvironmentStrings(lfn, buf, PATH_MAX)) {
 
1662
            /* FIXME: Needs to set errno! */
 
1663
            pa_xfree(lfn);
 
1664
            return NULL;
 
1665
        }
 
1666
        fn = buf;
 
1667
#endif
 
1668
 
 
1669
        if (access(fn, R_OK) == 0) {
 
1670
            char *r = pa_xstrdup(fn);
 
1671
            pa_xfree(lfn);
 
1672
            return r;
 
1673
        }
 
1674
 
 
1675
        if (errno != ENOENT) {
 
1676
            pa_log_warn("Failed to access configuration file '%s': %s", fn, pa_cstrerror(errno));
 
1677
            pa_xfree(lfn);
 
1678
            return NULL;
 
1679
        }
 
1680
 
 
1681
        pa_xfree(lfn);
 
1682
    }
 
1683
 
 
1684
    if (global) {
 
1685
#ifdef OS_IS_WIN32
 
1686
        if (!ExpandEnvironmentStrings(global, buf, PATH_MAX))
 
1687
            /* FIXME: Needs to set errno! */
 
1688
            return NULL;
 
1689
        global = buf;
 
1690
#endif
 
1691
 
 
1692
        if (access(global, R_OK) == 0)
 
1693
            return pa_xstrdup(global);
 
1694
    }
 
1695
 
 
1696
    errno = ENOENT;
 
1697
 
 
1698
    return NULL;
1183
1699
}
1184
1700
 
1185
1701
/* Format the specified data as a hexademical string */
1214
1730
    if (c >= 'a' && c <= 'f')
1215
1731
        return c - 'a' + 10;
1216
1732
 
 
1733
    errno = EINVAL;
1217
1734
    return -1;
1218
1735
}
1219
1736
 
1246
1763
}
1247
1764
 
1248
1765
/* Returns nonzero when *s starts with *pfx */
1249
 
int pa_startswith(const char *s, const char *pfx) {
 
1766
pa_bool_t pa_startswith(const char *s, const char *pfx) {
1250
1767
    size_t l;
1251
1768
 
1252
1769
    pa_assert(s);
1258
1775
}
1259
1776
 
1260
1777
/* Returns nonzero when *s ends with *sfx */
1261
 
int pa_endswith(const char *s, const char *sfx) {
 
1778
pa_bool_t pa_endswith(const char *s, const char *sfx) {
1262
1779
    size_t l1, l2;
1263
1780
 
1264
1781
    pa_assert(s);
1270
1787
    return l1 >= l2 && strcmp(s+l1-l2, sfx) == 0;
1271
1788
}
1272
1789
 
1273
 
/* if fn is null return the PulseAudio run time path in s (/tmp/pulse)
1274
 
 * if fn is non-null and starts with / return fn in s
1275
 
 * otherwise append fn to the run time path and return it in s */
1276
 
char *pa_runtime_path(const char *fn, char *s, size_t l) {
1277
 
    const char *e;
 
1790
pa_bool_t pa_is_path_absolute(const char *fn) {
 
1791
    pa_assert(fn);
1278
1792
 
1279
1793
#ifndef OS_IS_WIN32
1280
 
    if (fn && *fn == '/')
 
1794
    return *fn == '/';
1281
1795
#else
1282
 
    if (fn && strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\')
1283
 
#endif
1284
 
        return pa_strlcpy(s, fn, l);
1285
 
 
1286
 
    if ((e = getenv("PULSE_RUNTIME_PATH"))) {
1287
 
 
1288
 
        if (fn)
1289
 
            pa_snprintf(s, l, "%s%c%s", e, PA_PATH_SEP_CHAR, fn);
1290
 
        else
1291
 
            pa_snprintf(s, l, "%s", e);
1292
 
 
1293
 
    } else {
1294
 
        char u[256];
1295
 
 
1296
 
        if (fn)
1297
 
            pa_snprintf(s, l, "%s%s%c%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)), PA_PATH_SEP_CHAR, fn);
1298
 
        else
1299
 
            pa_snprintf(s, l, "%s%s", PA_USER_RUNTIME_PATH_PREFIX, pa_get_user_name(u, sizeof(u)));
1300
 
    }
1301
 
 
1302
 
 
1303
 
#ifdef OS_IS_WIN32
1304
 
    {
1305
 
        char buf[l];
1306
 
        strcpy(buf, s);
1307
 
        ExpandEnvironmentStrings(buf, s, l);
1308
 
    }
1309
 
#endif
1310
 
 
1311
 
    return s;
 
1796
    return strlen(fn) >= 3 && isalpha(fn[0]) && fn[1] == ':' && fn[2] == '\\';
 
1797
#endif
 
1798
}
 
1799
 
 
1800
char *pa_make_path_absolute(const char *p) {
 
1801
    char *r;
 
1802
    char *cwd;
 
1803
 
 
1804
    pa_assert(p);
 
1805
 
 
1806
    if (pa_is_path_absolute(p))
 
1807
        return pa_xstrdup(p);
 
1808
 
 
1809
    if (!(cwd = pa_getcwd()))
 
1810
        return pa_xstrdup(p);
 
1811
 
 
1812
    r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", cwd, p);
 
1813
    pa_xfree(cwd);
 
1814
    return r;
 
1815
}
 
1816
 
 
1817
/* if fn is null return the PulseAudio run time path in s (~/.pulse)
 
1818
 * if fn is non-null and starts with / return fn
 
1819
 * otherwise append fn to the run time path and return it */
 
1820
static char *get_path(const char *fn, pa_bool_t prependmid, pa_bool_t rt) {
 
1821
    char *rtp;
 
1822
 
 
1823
    if (pa_is_path_absolute(fn))
 
1824
        return pa_xstrdup(fn);
 
1825
 
 
1826
    rtp = rt ? pa_get_runtime_dir() : pa_get_state_dir();
 
1827
 
 
1828
    if (!rtp)
 
1829
        return NULL;
 
1830
 
 
1831
    if (fn) {
 
1832
        char *r;
 
1833
 
 
1834
        if (prependmid) {
 
1835
            char *mid;
 
1836
 
 
1837
            if (!(mid = pa_machine_id())) {
 
1838
                pa_xfree(rtp);
 
1839
                return NULL;
 
1840
            }
 
1841
 
 
1842
            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:%s", rtp, mid, fn);
 
1843
            pa_xfree(mid);
 
1844
        } else
 
1845
            r = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", rtp, fn);
 
1846
 
 
1847
        pa_xfree(rtp);
 
1848
        return r;
 
1849
    } else
 
1850
        return rtp;
 
1851
}
 
1852
 
 
1853
char *pa_runtime_path(const char *fn) {
 
1854
    return get_path(fn, FALSE, TRUE);
 
1855
}
 
1856
 
 
1857
char *pa_state_path(const char *fn, pa_bool_t appendmid) {
 
1858
    return get_path(fn, appendmid, FALSE);
1312
1859
}
1313
1860
 
1314
1861
/* Convert the string s to a signed integer in *ret_i */
1322
1869
    errno = 0;
1323
1870
    l = strtol(s, &x, 0);
1324
1871
 
1325
 
    if (!x || *x || errno != 0)
 
1872
    if (!x || *x || errno) {
 
1873
        if (!errno)
 
1874
            errno = EINVAL;
1326
1875
        return -1;
 
1876
    }
1327
1877
 
1328
 
    if ((int32_t) l != l)
 
1878
    if ((int32_t) l != l) {
 
1879
        errno = ERANGE;
1329
1880
        return -1;
 
1881
    }
1330
1882
 
1331
1883
    *ret_i = (int32_t) l;
1332
1884
 
1344
1896
    errno = 0;
1345
1897
    l = strtoul(s, &x, 0);
1346
1898
 
1347
 
    if (!x || *x || errno != 0)
 
1899
    if (!x || *x || errno) {
 
1900
        if (!errno)
 
1901
            errno = EINVAL;
1348
1902
        return -1;
 
1903
    }
1349
1904
 
1350
 
    if ((uint32_t) l != l)
 
1905
    if ((uint32_t) l != l) {
 
1906
        errno = ERANGE;
1351
1907
        return -1;
 
1908
    }
1352
1909
 
1353
1910
    *ret_u = (uint32_t) l;
1354
1911
 
1363
1920
}
1364
1921
#endif
1365
1922
 
1366
 
int pa_atof(const char *s, float *ret_f) {
 
1923
int pa_atod(const char *s, double *ret_d) {
1367
1924
    char *x = NULL;
1368
 
    float f;
1369
 
    int r = 0;
 
1925
    double f;
1370
1926
 
1371
1927
    pa_assert(s);
1372
 
    pa_assert(ret_f);
 
1928
    pa_assert(ret_d);
1373
1929
 
1374
1930
    /* This should be locale independent */
1375
1931
 
1384
1940
 
1385
1941
    if (c_locale) {
1386
1942
        errno = 0;
1387
 
        f = strtof_l(s, &x, c_locale);
 
1943
        f = strtod_l(s, &x, c_locale);
1388
1944
    } else
1389
1945
#endif
1390
1946
    {
1391
1947
        errno = 0;
1392
 
#ifdef HAVE_STRTOF
1393
 
        f = strtof(s, &x);
1394
 
#else
1395
1948
        f = strtod(s, &x);
1396
 
#endif
1397
 
    }
1398
 
 
1399
 
    if (!x || *x || errno != 0)
1400
 
        r =  -1;
1401
 
    else
1402
 
        *ret_f = f;
1403
 
 
1404
 
    return r;
 
1949
    }
 
1950
 
 
1951
    if (!x || *x || errno) {
 
1952
        if (!errno)
 
1953
            errno = EINVAL;
 
1954
        return -1;
 
1955
    }
 
1956
 
 
1957
    *ret_d = f;
 
1958
 
 
1959
    return 0;
1405
1960
}
1406
1961
 
1407
1962
/* Same as snprintf, but guarantees NUL-termination on every platform */
1408
 
int pa_snprintf(char *str, size_t size, const char *format, ...) {
1409
 
    int ret;
 
1963
size_t pa_snprintf(char *str, size_t size, const char *format, ...) {
 
1964
    size_t ret;
1410
1965
    va_list ap;
1411
1966
 
1412
1967
    pa_assert(str);
1414
1969
    pa_assert(format);
1415
1970
 
1416
1971
    va_start(ap, format);
 
1972
    ret = pa_vsnprintf(str, size, format, ap);
 
1973
    va_end(ap);
 
1974
 
 
1975
    return ret;
 
1976
}
 
1977
 
 
1978
/* Same as vsnprintf, but guarantees NUL-termination on every platform */
 
1979
size_t pa_vsnprintf(char *str, size_t size, const char *format, va_list ap) {
 
1980
    int ret;
 
1981
 
 
1982
    pa_assert(str);
 
1983
    pa_assert(size > 0);
 
1984
    pa_assert(format);
 
1985
 
1417
1986
    ret = vsnprintf(str, size, format, ap);
1418
 
    va_end(ap);
1419
1987
 
1420
1988
    str[size-1] = 0;
1421
1989
 
1422
 
    return ret;
 
1990
    if (ret < 0)
 
1991
        return strlen(str);
 
1992
 
 
1993
    if ((size_t) ret > size-1)
 
1994
        return size-1;
 
1995
 
 
1996
    return (size_t) ret;
1423
1997
}
1424
1998
 
1425
1999
/* Truncate the specified string, but guarantee that the string
1443
2017
    size_t l = 128;
1444
2018
 
1445
2019
    for (;;) {
1446
 
        char *p = pa_xnew(char, l);
 
2020
        char *p = pa_xmalloc(l);
1447
2021
        if (getcwd(p, l))
1448
2022
            return p;
1449
2023
 
1455
2029
    }
1456
2030
}
1457
2031
 
1458
 
char *pa_make_path_absolute(const char *p) {
1459
 
    char *r;
1460
 
    char *cwd;
1461
 
 
1462
 
    pa_assert(p);
1463
 
 
1464
 
    if (p[0] == '/')
1465
 
        return pa_xstrdup(p);
1466
 
 
1467
 
    if (!(cwd = pa_getcwd()))
1468
 
        return pa_xstrdup(p);
1469
 
 
1470
 
    r = pa_sprintf_malloc("%s/%s", cwd, p);
1471
 
    pa_xfree(cwd);
1472
 
    return r;
1473
 
}
1474
 
 
1475
2032
void *pa_will_need(const void *p, size_t l) {
1476
2033
#ifdef RLIMIT_MEMLOCK
1477
2034
    struct rlimit rlim;
1485
2042
    pa_assert(l > 0);
1486
2043
 
1487
2044
    a = PA_PAGE_ALIGN_PTR(p);
1488
 
    size = (const uint8_t*) p + l - (const uint8_t*) a;
 
2045
    size = (size_t) ((const uint8_t*) p + l - (const uint8_t*) a);
1489
2046
 
1490
2047
#ifdef HAVE_POSIX_MADVISE
1491
2048
    if ((r = posix_madvise((void*) a, size, POSIX_MADV_WILLNEED)) == 0) {
1506
2063
 
1507
2064
    if (rlim.rlim_cur < PA_PAGE_SIZE) {
1508
2065
        pa_log_debug("posix_madvise() failed (or doesn't exist), resource limits don't allow mlock(), can't page in data: %s", pa_cstrerror(r));
 
2066
        errno = EPERM;
1509
2067
        return (void*) p;
1510
2068
    }
1511
2069
 
1512
 
    bs = PA_PAGE_ALIGN(rlim.rlim_cur);
 
2070
    bs = PA_PAGE_ALIGN((size_t) rlim.rlim_cur);
1513
2071
#else
1514
2072
    bs = PA_PAGE_SIZE*4;
1515
2073
#endif
1561
2119
        char *c;
1562
2120
        ssize_t n;
1563
2121
 
1564
 
        c = pa_xnew(char, l);
 
2122
        c = pa_xmalloc(l);
1565
2123
 
1566
2124
        if ((n = readlink(p, c, l-1)) < 0) {
1567
2125
            pa_xfree(c);
1577
2135
        l *= 2;
1578
2136
    }
1579
2137
}
 
2138
 
 
2139
int pa_close_all(int except_fd, ...) {
 
2140
    va_list ap;
 
2141
    unsigned n = 0, i;
 
2142
    int r, *p;
 
2143
 
 
2144
    va_start(ap, except_fd);
 
2145
 
 
2146
    if (except_fd >= 0)
 
2147
        for (n = 1; va_arg(ap, int) >= 0; n++)
 
2148
            ;
 
2149
 
 
2150
    va_end(ap);
 
2151
 
 
2152
    p = pa_xnew(int, n+1);
 
2153
 
 
2154
    va_start(ap, except_fd);
 
2155
 
 
2156
    i = 0;
 
2157
    if (except_fd >= 0) {
 
2158
        int fd;
 
2159
        p[i++] = except_fd;
 
2160
 
 
2161
        while ((fd = va_arg(ap, int)) >= 0)
 
2162
            p[i++] = fd;
 
2163
    }
 
2164
    p[i] = -1;
 
2165
 
 
2166
    va_end(ap);
 
2167
 
 
2168
    r = pa_close_allv(p);
 
2169
    free(p);
 
2170
 
 
2171
    return r;
 
2172
}
 
2173
 
 
2174
int pa_close_allv(const int except_fds[]) {
 
2175
    struct rlimit rl;
 
2176
    int fd;
 
2177
    int saved_errno;
 
2178
 
 
2179
#ifdef __linux__
 
2180
 
 
2181
    DIR *d;
 
2182
 
 
2183
    if ((d = opendir("/proc/self/fd"))) {
 
2184
 
 
2185
        struct dirent *de;
 
2186
 
 
2187
        while ((de = readdir(d))) {
 
2188
            pa_bool_t found;
 
2189
            long l;
 
2190
            char *e = NULL;
 
2191
            int i;
 
2192
 
 
2193
            if (de->d_name[0] == '.')
 
2194
                continue;
 
2195
 
 
2196
            errno = 0;
 
2197
            l = strtol(de->d_name, &e, 10);
 
2198
            if (errno != 0 || !e || *e) {
 
2199
                closedir(d);
 
2200
                errno = EINVAL;
 
2201
                return -1;
 
2202
            }
 
2203
 
 
2204
            fd = (int) l;
 
2205
 
 
2206
            if ((long) fd != l) {
 
2207
                closedir(d);
 
2208
                errno = EINVAL;
 
2209
                return -1;
 
2210
            }
 
2211
 
 
2212
            if (fd < 3)
 
2213
                continue;
 
2214
 
 
2215
            if (fd == dirfd(d))
 
2216
                continue;
 
2217
 
 
2218
            found = FALSE;
 
2219
            for (i = 0; except_fds[i] >= 0; i++)
 
2220
                if (except_fds[i] == fd) {
 
2221
                    found = TRUE;
 
2222
                    break;
 
2223
                }
 
2224
 
 
2225
            if (found)
 
2226
                continue;
 
2227
 
 
2228
            if (pa_close(fd) < 0) {
 
2229
                saved_errno = errno;
 
2230
                closedir(d);
 
2231
                errno = saved_errno;
 
2232
 
 
2233
                return -1;
 
2234
            }
 
2235
        }
 
2236
 
 
2237
        closedir(d);
 
2238
        return 0;
 
2239
    }
 
2240
 
 
2241
#endif
 
2242
 
 
2243
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
 
2244
        return -1;
 
2245
 
 
2246
    for (fd = 3; fd < (int) rl.rlim_max; fd++) {
 
2247
        int i;
 
2248
        pa_bool_t found;
 
2249
 
 
2250
        found = FALSE;
 
2251
        for (i = 0; except_fds[i] >= 0; i++)
 
2252
            if (except_fds[i] == fd) {
 
2253
                found = TRUE;
 
2254
                break;
 
2255
            }
 
2256
 
 
2257
        if (found)
 
2258
            continue;
 
2259
 
 
2260
        if (pa_close(fd) < 0 && errno != EBADF)
 
2261
            return -1;
 
2262
    }
 
2263
 
 
2264
    return 0;
 
2265
}
 
2266
 
 
2267
int pa_unblock_sigs(int except, ...) {
 
2268
    va_list ap;
 
2269
    unsigned n = 0, i;
 
2270
    int r, *p;
 
2271
 
 
2272
    va_start(ap, except);
 
2273
 
 
2274
    if (except >= 1)
 
2275
        for (n = 1; va_arg(ap, int) >= 0; n++)
 
2276
            ;
 
2277
 
 
2278
    va_end(ap);
 
2279
 
 
2280
    p = pa_xnew(int, n+1);
 
2281
 
 
2282
    va_start(ap, except);
 
2283
 
 
2284
    i = 0;
 
2285
    if (except >= 1) {
 
2286
        int sig;
 
2287
        p[i++] = except;
 
2288
 
 
2289
        while ((sig = va_arg(ap, int)) >= 0)
 
2290
            p[i++] = sig;
 
2291
    }
 
2292
    p[i] = -1;
 
2293
 
 
2294
    va_end(ap);
 
2295
 
 
2296
    r = pa_unblock_sigsv(p);
 
2297
    pa_xfree(p);
 
2298
 
 
2299
    return r;
 
2300
}
 
2301
 
 
2302
int pa_unblock_sigsv(const int except[]) {
 
2303
    int i;
 
2304
    sigset_t ss;
 
2305
 
 
2306
    if (sigemptyset(&ss) < 0)
 
2307
        return -1;
 
2308
 
 
2309
    for (i = 0; except[i] > 0; i++)
 
2310
        if (sigaddset(&ss, except[i]) < 0)
 
2311
            return -1;
 
2312
 
 
2313
    return sigprocmask(SIG_SETMASK, &ss, NULL);
 
2314
}
 
2315
 
 
2316
int pa_reset_sigs(int except, ...) {
 
2317
    va_list ap;
 
2318
    unsigned n = 0, i;
 
2319
    int *p, r;
 
2320
 
 
2321
    va_start(ap, except);
 
2322
 
 
2323
    if (except >= 1)
 
2324
        for (n = 1; va_arg(ap, int) >= 0; n++)
 
2325
            ;
 
2326
 
 
2327
    va_end(ap);
 
2328
 
 
2329
    p = pa_xnew(int, n+1);
 
2330
 
 
2331
    va_start(ap, except);
 
2332
 
 
2333
    i = 0;
 
2334
    if (except >= 1) {
 
2335
        int sig;
 
2336
        p[i++] = except;
 
2337
 
 
2338
        while ((sig = va_arg(ap, int)) >= 0)
 
2339
            sig = p[i++];
 
2340
    }
 
2341
    p[i] = -1;
 
2342
 
 
2343
    va_end(ap);
 
2344
 
 
2345
    r = pa_reset_sigsv(p);
 
2346
    pa_xfree(p);
 
2347
 
 
2348
    return r;
 
2349
}
 
2350
 
 
2351
int pa_reset_sigsv(const int except[]) {
 
2352
    int sig;
 
2353
 
 
2354
    for (sig = 1; sig < NSIG; sig++) {
 
2355
        pa_bool_t reset = TRUE;
 
2356
 
 
2357
        switch (sig) {
 
2358
            case SIGKILL:
 
2359
            case SIGSTOP:
 
2360
                reset = FALSE;
 
2361
                break;
 
2362
 
 
2363
            default: {
 
2364
                int i;
 
2365
 
 
2366
                for (i = 0; except[i] > 0; i++) {
 
2367
                    if (sig == except[i]) {
 
2368
                        reset = FALSE;
 
2369
                        break;
 
2370
                    }
 
2371
                }
 
2372
            }
 
2373
        }
 
2374
 
 
2375
        if (reset) {
 
2376
            struct sigaction sa;
 
2377
 
 
2378
            memset(&sa, 0, sizeof(sa));
 
2379
            sa.sa_handler = SIG_DFL;
 
2380
 
 
2381
            /* On Linux the first two RT signals are reserved by
 
2382
             * glibc, and sigaction() will return EINVAL for them. */
 
2383
            if ((sigaction(sig, &sa, NULL) < 0))
 
2384
                if (errno != EINVAL)
 
2385
                    return -1;
 
2386
        }
 
2387
    }
 
2388
 
 
2389
    return 0;
 
2390
}
 
2391
 
 
2392
void pa_set_env(const char *key, const char *value) {
 
2393
    pa_assert(key);
 
2394
    pa_assert(value);
 
2395
 
 
2396
    putenv(pa_sprintf_malloc("%s=%s", key, value));
 
2397
}
 
2398
 
 
2399
pa_bool_t pa_in_system_mode(void) {
 
2400
    const char *e;
 
2401
 
 
2402
    if (!(e = getenv("PULSE_SYSTEM")))
 
2403
        return FALSE;
 
2404
 
 
2405
    return !!atoi(e);
 
2406
}
 
2407
 
 
2408
char *pa_machine_id(void) {
 
2409
    FILE *f;
 
2410
    size_t l;
 
2411
 
 
2412
    /* The returned value is supposed be some kind of ascii identifier
 
2413
     * that is unique and stable across reboots. */
 
2414
 
 
2415
    /* First we try the D-Bus UUID, which is the best option we have,
 
2416
     * since it fits perfectly our needs and is not as volatile as the
 
2417
     * hostname which might be set from dhcp. */
 
2418
 
 
2419
    if ((f = fopen(PA_MACHINE_ID, "r"))) {
 
2420
        char ln[34] = "", *r;
 
2421
 
 
2422
        r = fgets(ln, sizeof(ln)-1, f);
 
2423
        fclose(f);
 
2424
 
 
2425
        pa_strip_nl(ln);
 
2426
 
 
2427
        if (ln[0])
 
2428
            return pa_xstrdup(ln);
 
2429
    }
 
2430
 
 
2431
    /* The we fall back to the host name. It supposed to be somewhat
 
2432
     * unique, at least in a network, but may change. */
 
2433
 
 
2434
    l = 100;
 
2435
    for (;;) {
 
2436
        char *c;
 
2437
 
 
2438
        c = pa_xmalloc(l);
 
2439
 
 
2440
        if (!pa_get_host_name(c, l)) {
 
2441
 
 
2442
            if (errno != EINVAL && errno != ENAMETOOLONG)
 
2443
                break;
 
2444
 
 
2445
        } else if (strlen(c) < l-1) {
 
2446
 
 
2447
            if (*c == 0) {
 
2448
                pa_xfree(c);
 
2449
                break;
 
2450
            }
 
2451
 
 
2452
            return c;
 
2453
        }
 
2454
 
 
2455
        /* Hmm, the hostname is as long the space we offered the
 
2456
         * function, we cannot know if it fully fit in, so let's play
 
2457
         * safe and retry. */
 
2458
 
 
2459
        pa_xfree(c);
 
2460
        l *= 2;
 
2461
    }
 
2462
 
 
2463
    /* If no hostname was set we use the POSIX hostid. It's usually
 
2464
     * the IPv4 address.  Mit not be that stable. */
 
2465
    return pa_sprintf_malloc("%08lx", (unsigned long) gethostid);
 
2466
}
 
2467
 
 
2468
char *pa_uname_string(void) {
 
2469
    struct utsname u;
 
2470
 
 
2471
    pa_assert_se(uname(&u) == 0);
 
2472
 
 
2473
    return pa_sprintf_malloc("%s %s %s %s", u.sysname, u.machine, u.release, u.version);
 
2474
}
 
2475
 
 
2476
#ifdef HAVE_VALGRIND_MEMCHECK_H
 
2477
pa_bool_t pa_in_valgrind(void) {
 
2478
    static int b = 0;
 
2479
 
 
2480
    /* To make heisenbugs a bit simpler to find we check for $VALGRIND
 
2481
     * here instead of really checking whether we run in valgrind or
 
2482
     * not. */
 
2483
 
 
2484
    if (b < 1)
 
2485
        b = getenv("VALGRIND") ? 2 : 1;
 
2486
 
 
2487
    return b > 1;
 
2488
}
 
2489
#endif