Esempio n. 1
0
/* Load an authorization cookie from file fn and store it in data. If
 * the cookie file doesn't exist, create it */
static int load(const char *fn, void *data, size_t length) {
    int fd = -1;
    int writable = 1;
    int unlock = 0, ret = -1;
    ssize_t r;

    pa_assert(fn);
    pa_assert(data);
    pa_assert(length > 0);

    if ((fd = pa_open_cloexec(fn, O_RDWR|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR)) < 0) {

        if (errno != EACCES || (fd = open(fn, O_RDONLY|O_BINARY)) < 0) {
            pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
            goto finish;
        } else
            writable = 0;
    }

    unlock = pa_lock_fd(fd, 1) >= 0;

    if ((r = pa_loop_read(fd, data, length, NULL)) < 0) {
        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    if ((size_t) r != length) {
        pa_log_debug("Got %d bytes from cookie file '%s', expected %d", (int) r, fn, (int) length);

        if (!writable) {
            pa_log_warn("Unable to write cookie to read-only file");
            goto finish;
        }

        if (generate(fd, data, length) < 0)
            goto finish;
    }

    ret = 0;

finish:

    if (fd >= 0) {

        if (unlock)
            pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
            ret = -1;
        }
    }

    return ret;
}
Esempio n. 2
0
static int open_pid_file(const char *fn, int mode) {
    int fd;

    pa_assert(fn);

    for (;;) {
        struct stat st;

        if ((fd = pa_open_cloexec(fn, mode
#ifdef O_NOFOLLOW
                       |O_NOFOLLOW
#endif
                       , S_IRUSR|S_IWUSR
             )) < 0) {
            if (mode != O_RDONLY || errno != ENOENT)
                pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
            goto fail;
        }

        /* Try to lock the file. If that fails, go without */
        if (pa_lock_fd(fd, 1) < 0)
            goto fail;

        if (fstat(fd, &st) < 0) {
            pa_log_warn("Failed to fstat() PID file '%s': %s", fn, pa_cstrerror(errno));
            goto fail;
        }

        /* Does the file still exist in the file system? When yes, we're done, otherwise restart */
        if (st.st_nlink >= 1)
            break;

        if (pa_lock_fd(fd, 0) < 0)
            goto fail;

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close file '%s': %s", fn, pa_cstrerror(errno));
            fd = -1;
            goto fail;
        }
    }

    return fd;

fail:

    if (fd >= 0) {
        int saved_errno = errno;
        pa_lock_fd(fd, 0);
        pa_close(fd);
        errno = saved_errno;
    }

    return -1;
}
Esempio n. 3
0
static int save_rules(struct userdata *u) {
    FILE *f;
    int ret = -1;
    void *state = NULL;
    struct rule *rule;

    if (!u->modified)
        return 0;

    pa_log_info("Saving rules...");

    f = u->table_file ?
        fopen(u->table_file, "w") :
        pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w");

    if (!f) {
        pa_log("Failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));
        goto finish;
    }

    pa_lock_fd(fileno(f), 1);

    while ((rule = pa_hashmap_iterate(u->hashmap, &state, NULL))) {
        unsigned i;

        fprintf(f, "%s\n", rule->name);

        if (rule->volume_is_set) {
            fprintf(f, "%u", rule->volume.channels);

            for (i = 0; i < rule->volume.channels; i++)
                fprintf(f, " %u", rule->volume.values[i]);
        }

        fprintf(f, "\n%s\n%s\n",
                rule->sink ? rule->sink : "",
                rule->source ? rule->source : "");
    }

    ret = 0;
    u->modified = FALSE;
    pa_log_debug("Successfully saved rules...");

finish:
    if (f) {
        pa_lock_fd(fileno(f), 0);
        fclose(f);
    }

    return ret;
}
Esempio n. 4
0
/* Kill a current running daemon. Return non-zero on success, -1
 * otherwise. If successful *pid contains the PID of the daemon
 * process. */
int pa_pid_file_kill(int sig, pid_t *pid, const char *procname) {
    int fd = -1;
    char *fn;
    int ret = -1;
    pid_t _pid;
#ifdef __linux__
    char *e = NULL;
#endif

    if (!pid)
        pid = &_pid;

    if (!(fn = pa_runtime_path("pid")))
        goto fail;

    if ((fd = open_pid_file(fn, O_RDONLY)) < 0) {

        if (errno == ENOENT)
            errno = ESRCH;

        goto fail;
    }

    if ((*pid = read_pid(fn, fd)) == (pid_t) -1)
        goto fail;

    if (procname) {
        int ours;

        if ((ours = proc_name_ours(*pid, procname)) < 0)
            goto fail;

        if (!ours) {
            errno = ESRCH;
            goto fail;
        }
    }

    ret = kill(*pid, sig);

fail:

    if (fd >= 0) {
        int saved_errno = errno;
        pa_lock_fd(fd, 0);
        pa_close(fd);
        errno = saved_errno;
    }

#ifdef __linux__
    pa_xfree(e);
#endif

    pa_xfree(fn);

    return ret;

}
Esempio n. 5
0
/* Store the specified cookie in the specified cookie file */
int pa_authkey_save(const char *fn, const void *data, size_t length) {
    int fd = -1;
    int unlock = 0, ret = -1;
    ssize_t r;
    char *p;

    pa_assert(fn);
    pa_assert(data);
    pa_assert(length > 0);

    if (!(p = normalize_path(fn)))
        return -2;

    if ((fd = pa_open_cloexec(p, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR)) < 0) {
        pa_log_warn("Failed to open cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    unlock = pa_lock_fd(fd, 1) >= 0;

    if ((r = pa_loop_write(fd, data, length, NULL)) < 0 || (size_t) r != length) {
        pa_log("Failed to read cookie file '%s': %s", fn, pa_cstrerror(errno));
        goto finish;
    }

    ret = 0;

finish:

    if (fd >= 0) {

        if (unlock)
            pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close cookie file: %s", pa_cstrerror(errno));
            ret = -1;
        }
    }

    pa_xfree(p);

    return ret;
}
Esempio n. 6
0
/* Create a new PID file for the current process. */
int pa_pid_file_create(const char *procname) {
    int fd = -1;
    int ret = -1;
    char t[20];
    pid_t pid;
    size_t l;
    char *fn;

#ifdef OS_IS_WIN32
    HANDLE process;
#endif

    if (!(fn = pa_runtime_path("pid")))
        goto fail;

    if ((fd = open_pid_file(fn, O_CREAT|O_RDWR)) < 0)
        goto fail;

    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
        pa_log_warn("Corrupt PID file, overwriting.");
    else if (pid > 0) {
        int ours = 1;

#ifdef OS_IS_WIN32
        if ((process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid)) != NULL) {
            CloseHandle(process);
#else
        if (kill(pid, 0) >= 0 || errno != ESRCH) {
#endif

            if (procname)
                if ((ours = proc_name_ours(pid, procname)) < 0) {
                    pa_log_warn("Could not check to see if pid %lu is a pulseaudio process. "
                                "Asssuming it is and the daemon is already running.", (unsigned long) pid);
                    goto fail;
                }

            if (ours) {
                pa_log("Daemon already running.");
                ret = 1;
                goto fail;
            }
        }

        pa_log_warn("Stale PID file, overwriting.");
    }

    /* Overwrite the current PID file */
    if (lseek(fd, (off_t) 0, SEEK_SET) == (off_t) -1 || ftruncate(fd, (off_t) 0) < 0) {
        pa_log("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

    pa_snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid());
    l = strlen(t);

    if (pa_loop_write(fd, t, l, NULL) != (ssize_t) l) {
        pa_log("Failed to write PID file.");
        goto fail;
    }

    ret = 0;

fail:
    if (fd >= 0) {
        pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
            ret = -1;
        }
    }

    pa_xfree(fn);

    return ret;
}

/* Remove the PID file, if it is ours */
int pa_pid_file_remove(void) {
    int fd = -1;
    char *fn;
    int ret = -1;
    pid_t pid;

    if (!(fn = pa_runtime_path("pid")))
        goto fail;

    if ((fd = open_pid_file(fn, O_RDWR)) < 0) {
        pa_log_warn("Failed to open PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

    if ((pid = read_pid(fn, fd)) == (pid_t) -1)
        goto fail;

    if (pid != getpid()) {
        pa_log("PID file '%s' not mine!", fn);
        goto fail;
    }

    if (ftruncate(fd, (off_t) 0) < 0) {
        pa_log_warn("Failed to truncate PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

#ifdef OS_IS_WIN32
    pa_lock_fd(fd, 0);
    pa_close(fd);
    fd = -1;
#endif

    if (unlink(fn) < 0) {
        pa_log_warn("Failed to remove PID file '%s': %s", fn, pa_cstrerror(errno));
        goto fail;
    }

    ret = 0;

fail:

    if (fd >= 0) {
        pa_lock_fd(fd, 0);

        if (pa_close(fd) < 0) {
            pa_log_warn("Failed to close PID file '%s': %s", fn, pa_cstrerror(errno));
            ret = -1;
        }
    }

    pa_xfree(fn);

    return ret;
}
Esempio n. 7
0
static int load_rules(struct userdata *u) {
    FILE *f;
    int n = 0;
    int ret = -1;
    char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256];
    char *ln = buf_name;

    f = u->table_file ?
        fopen(u->table_file, "r") :
        pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r");

    if (!f) {
        if (errno == ENOENT) {
            pa_log_info("starting with empty ruleset.");
            ret = 0;
        } else
            pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));

        goto finish;
    }

    pa_lock_fd(fileno(f), 1);

    while (!feof(f)) {
        struct rule *rule;
        pa_cvolume v;
        pa_bool_t v_is_set;

        if (!fgets(ln, sizeof(buf_name), f))
            break;

        n++;

        pa_strip_nl(ln);

        if (ln[0] == '#')
            continue;

        if (ln == buf_name) {
            ln = buf_volume;
            continue;
        }

        if (ln == buf_volume) {
            ln = buf_sink;
            continue;
        }

        if (ln == buf_sink) {
            ln = buf_source;
            continue;
        }

        pa_assert(ln == buf_source);

        if (buf_volume[0]) {
            if (!parse_volume(buf_volume, &v)) {
                pa_log("parse failure in %s:%u, stopping parsing", u->table_file, n);
                goto finish;
            }

            v_is_set = TRUE;
        } else
            v_is_set = FALSE;

        ln = buf_name;

        if (pa_hashmap_get(u->hashmap, buf_name)) {
            pa_log("double entry in %s:%u, ignoring", u->table_file, n);
            continue;
        }

        rule = pa_xnew(struct rule, 1);
        rule->name = pa_xstrdup(buf_name);
        if ((rule->volume_is_set = v_is_set))
            rule->volume = v;
        rule->sink = buf_sink[0] ? pa_xstrdup(buf_sink) : NULL;
        rule->source = buf_source[0] ? pa_xstrdup(buf_source) : NULL;

        pa_hashmap_put(u->hashmap, rule->name, rule);
    }

    if (ln != buf_name) {
        pa_log("invalid number of lines in %s.", u->table_file);
        goto finish;
    }

    ret = 0;

finish:
    if (f) {
        pa_lock_fd(fileno(f), 0);
        fclose(f);
    }

    return ret;
}