mirror of
				https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
				synced 2025-11-03 09:01:50 -05:00 
			
		
		
		
	Rework state/runtime directory logic
The runtime directory is now guaranteed to be in /tmp which will hopefully provide support for POSIX file locking and UNIX sockets. The state directory stays in $HOME.
This commit is contained in:
		
							parent
							
								
									4e6fb67e9f
								
							
						
					
					
						commit
						bd05b36a1e
					
				
					 1 changed files with 225 additions and 30 deletions
				
			
		| 
						 | 
					@ -1164,48 +1164,243 @@ int pa_unlock_lockfile(const char *fn, int fd) {
 | 
				
			||||||
    return r;
 | 
					    return r;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static char *get_dir(mode_t m, const char *env_name) {
 | 
					static char *get_pulse_home(void) {
 | 
				
			||||||
    const char *e;
 | 
					    char h[PATH_MAX];
 | 
				
			||||||
    char *d;
 | 
					    struct stat st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ((e = getenv(env_name)))
 | 
					    if (!pa_get_home_dir(h, sizeof(h))) {
 | 
				
			||||||
        d = pa_xstrdup(e);
 | 
					        pa_log_error("Failed to get home directory.");
 | 
				
			||||||
    else {
 | 
					        return NULL;
 | 
				
			||||||
        char h[PATH_MAX];
 | 
					 | 
				
			||||||
        struct stat st;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!pa_get_home_dir(h, sizeof(h))) {
 | 
					 | 
				
			||||||
            pa_log_error("Failed to get home directory.");
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (stat(h, &st) < 0) {
 | 
					 | 
				
			||||||
            pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (st.st_uid != getuid()) {
 | 
					 | 
				
			||||||
            pa_log_error("Home directory %s not ours.", h);
 | 
					 | 
				
			||||||
            return NULL;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        d = pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0)  {
 | 
					    if (stat(h, &st) < 0) {
 | 
				
			||||||
 | 
					        pa_log_error("Failed to stat home directory %s: %s", h, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (st.st_uid != getuid()) {
 | 
				
			||||||
 | 
					        pa_log_error("Home directory %s not ours.", h);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pa_sprintf_malloc("%s" PA_PATH_SEP ".pulse", h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *pa_get_state_dir(void) {
 | 
				
			||||||
 | 
					    char *d;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* The state directory shall contain dynamic data that should be
 | 
				
			||||||
 | 
					     * kept across reboots, and is private to this user */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(d = pa_xstrdup(getenv("PULSE_STATE_PATH"))))
 | 
				
			||||||
 | 
					        if (!(d = get_pulse_home()))
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* If PULSE_STATE_PATH and PULSE_RUNTIME_PATH point to the same
 | 
				
			||||||
 | 
					     * dir then this will break. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pa_make_secure_dir(d, 0700, (pid_t) -1, (pid_t) -1) < 0)  {
 | 
				
			||||||
        pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 | 
					        pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 | 
				
			||||||
 | 
					        pa_xfree(d);
 | 
				
			||||||
        return NULL;
 | 
					        return NULL;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return d;
 | 
					    return d;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *pa_get_runtime_dir(void) {
 | 
					static char* make_random_dir(mode_t m) {
 | 
				
			||||||
    return get_dir(pa_in_system_mode() ? 0755 : 0700, "PULSE_RUNTIME_PATH");
 | 
					    static const char table[] =
 | 
				
			||||||
 | 
					        "abcdefghijklmnopqrstuvwxyz"
 | 
				
			||||||
 | 
					        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
 | 
				
			||||||
 | 
					        "0123456789";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    char fn[24] = "/tmp/pulse-";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn[sizeof(fn)-1] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        unsigned i;
 | 
				
			||||||
 | 
					        int r;
 | 
				
			||||||
 | 
					        mode_t u;
 | 
				
			||||||
 | 
					        int saved_errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (i = 11; i < sizeof(fn)-1; i++)
 | 
				
			||||||
 | 
					            fn[i] = table[rand() % (sizeof(table)-1)];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        u = umask((~m) & 0777);
 | 
				
			||||||
 | 
					        r = mkdir(fn, m);
 | 
				
			||||||
 | 
					        saved_errno = errno;
 | 
				
			||||||
 | 
					        umask(u);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (r >= 0)
 | 
				
			||||||
 | 
					            return pa_xstrdup(fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        errno = saved_errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (errno != EEXIST) {
 | 
				
			||||||
 | 
					            pa_log_error("Failed to create random directory %s: %s", fn, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
char *pa_get_state_dir(void) {
 | 
					static int make_random_dir_and_link(mode_t m, const char *k) {
 | 
				
			||||||
    return get_dir(0700, "PULSE_STATE_PATH");
 | 
					    char *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(p = make_random_dir(m)))
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (symlink(p, k) < 0) {
 | 
				
			||||||
 | 
					        int saved_errno = errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (errno != EEXIST)
 | 
				
			||||||
 | 
					            pa_log_error("Failed to symlink %s to %s: %s", k, p, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        rmdir(p);
 | 
				
			||||||
 | 
					        pa_xfree(p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        errno = saved_errno;
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char *pa_get_runtime_dir(void) {
 | 
				
			||||||
 | 
					    char *d, *k = NULL, *p = NULL, *t = NULL, *mid;
 | 
				
			||||||
 | 
					    struct stat st;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* The runtime directory shall contain dynamic data that needs NOT
 | 
				
			||||||
 | 
					     * to be kept accross reboots and is usuallly private to the user,
 | 
				
			||||||
 | 
					     * except in system mode, where it might be accessible by other
 | 
				
			||||||
 | 
					     * users, too. Since we need POSIX locking and UNIX sockets in
 | 
				
			||||||
 | 
					     * this directory, we link it to a random subdir in /tmp, if it
 | 
				
			||||||
 | 
					     * was not explicitly configured. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((d = getenv("PULSE_RUNTIME_PATH"))) {
 | 
				
			||||||
 | 
					        mode_t m;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        m = pa_in_system_mode() ? 0755 : 0700;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (pa_make_secure_dir(d, m, (pid_t) -1, (pid_t) -1) < 0)  {
 | 
				
			||||||
 | 
					            pa_log_error("Failed to create secure directory: %s", pa_cstrerror(errno));
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return pa_xstrdup(d);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(d = get_pulse_home()))
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!(mid = pa_machine_id())) {
 | 
				
			||||||
 | 
					        pa_xfree(d);
 | 
				
			||||||
 | 
					        goto fail;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    k = pa_sprintf_malloc("%s" PA_PATH_SEP "%s:runtime", d, mid);
 | 
				
			||||||
 | 
					    pa_xfree(d);
 | 
				
			||||||
 | 
					    pa_xfree(mid);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (;;) {
 | 
				
			||||||
 | 
					        /* OK, first let's check if the "runtime" symlink is already
 | 
				
			||||||
 | 
					         * existant */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!(p = pa_readlink(k))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (errno != ENOENT) {
 | 
				
			||||||
 | 
					                pa_log_error("Failed to stat runtime directory %s: %s", k, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					                goto fail;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Hmm, so the runtime directory didn't exist yet, so let's
 | 
				
			||||||
 | 
					             * create one in /tmp and symlink that to it */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (make_random_dir_and_link(0700, k) < 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                /* Mhmm, maybe another process was quicker than us,
 | 
				
			||||||
 | 
					                 * let's check if that was valid */
 | 
				
			||||||
 | 
					                if (errno == EEXIST)
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                goto fail;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return k;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Make sure that this actually makes sense */
 | 
				
			||||||
 | 
					        if (!pa_is_path_absolute(p)) {
 | 
				
			||||||
 | 
					            pa_log_error("Path %s in link %s is not absolute.", p, k);
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Hmm, so this symlink is still around, make sure nobody fools
 | 
				
			||||||
 | 
					         * us */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (lstat(p, &st) < 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (errno != ENOENT) {
 | 
				
			||||||
 | 
					                pa_log_error("Failed to stat runtime directory %s: %s", p, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					                goto fail;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (S_ISDIR(st.st_mode) &&
 | 
				
			||||||
 | 
					                (st.st_uid == getuid()) &&
 | 
				
			||||||
 | 
					                ((st.st_mode & 0777) == 0700)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                pa_xfree(p);
 | 
				
			||||||
 | 
					                return k;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_log_info("Hmm, runtime path exists, but points to an invalid directory. Changing runtime directory.");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_xfree(p);
 | 
				
			||||||
 | 
					        p = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* Hmm, so the link points to some nonexisting or invalid
 | 
				
			||||||
 | 
					         * dir. Let's replace it by a new link. We first create a
 | 
				
			||||||
 | 
					         * temporary link and then rename that to allow concurrent
 | 
				
			||||||
 | 
					         * execution of this function. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        t = pa_sprintf_malloc("%s.tmp", k);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (make_random_dir_and_link(0700, t) < 0) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (errno != EEXIST) {
 | 
				
			||||||
 | 
					                pa_log_error("Failed to symlink %s: %s", t, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					                goto fail;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            pa_xfree(t);
 | 
				
			||||||
 | 
					            t = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            /* Hmm, someone lese was quicker then us. Let's give
 | 
				
			||||||
 | 
					             * him some time to finish, and retry. */
 | 
				
			||||||
 | 
					            pa_msleep(10);
 | 
				
			||||||
 | 
					            continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        /* OK, we succeeded in creating the temporary symlink, so
 | 
				
			||||||
 | 
					         * let's rename it */
 | 
				
			||||||
 | 
					        if (rename(t, k) < 0) {
 | 
				
			||||||
 | 
					            pa_log_error("Failed to rename %s to %s: %s", t, k, pa_cstrerror(errno));
 | 
				
			||||||
 | 
					            goto fail;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        pa_xfree(t);
 | 
				
			||||||
 | 
					        return k;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fail:
 | 
				
			||||||
 | 
					    pa_xfree(p);
 | 
				
			||||||
 | 
					    pa_xfree(k);
 | 
				
			||||||
 | 
					    pa_xfree(t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Try to open a configuration file. If "env" is specified, open the
 | 
					/* Try to open a configuration file. If "env" is specified, open the
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue