Merge lp:~xnox/upstart/user-log-dir into lp:upstart

Proposed by Dimitri John Ledkov on 2013-01-14
Status: Merged
Merged at revision: 1428
Proposed branch: lp:~xnox/upstart/user-log-dir
Merge into: lp:upstart
Diff against target: 896 lines (+352/-86)
10 files modified
ChangeLog (+12/-0)
init/Makefile.am (+14/-14)
init/control.c (+2/-7)
init/job_process.c (+2/-1)
init/main.c (+5/-0)
init/man/init.5 (+31/-12)
init/man/init.8 (+4/-1)
init/tests/test_xdg.c (+184/-40)
init/xdg.c (+91/-10)
init/xdg.h (+7/-1)
To merge this branch: bzr merge lp:~xnox/upstart/user-log-dir
Reviewer Review Type Date Requested Status
James Hunt 2013-01-14 Approve on 2013-01-23
Review via email: mp+143091@code.launchpad.net

Description of the change

This branch implements writting job logs to $XDG_CACHE_HOME/upstart/ when running in --user-mode.
One can override the location with command-line arg.
Note the environment variable is not honoured.

To post a comment you must log in.
James Hunt (jamesodhunt) wrote :

* init/main.c:
  - handle_logdir(): Is there a reason we are not honouring the environment variable? If not, why don't we put
    the 'dir = getenv (LOGDIR_ENV)' immediately before the 'if (user_mode)' since we can then say in the
    user_mode block: 'log_dir = dir ? dir : get_user_log_dir ()' and thus honour the env var for user mode too.
* init/xdg.c:
  - get_user_log_dir():
    - Spacing around '='.
    - 'path' is leaked.
    - We should be logging to $HOME/.cache/upstart/logs/ as per the spec: this allows us to create a
      $HOME/.cache/upstart/sessions/ also in the spec.
* init/man/init.5: This needs updating for '--user' and location of
  conf files and logfiles when running in this mode. Specifically the following sections need updating:
    - 'User Jobs'
    - 'Process environment' -> console -> log
    - 'FILES': should reflect conf directories listed in the 'User
      Session Mode' and specify location of User Session log files.
* init/man/init.8: Description of '--logdir' and '--confdir' also need updating.

review: Needs Fixing
lp:~xnox/upstart/user-log-dir updated on 2013-01-15
1425. By James Hunt on 2013-01-15

* init/log.c:
  - log_clear_unflushed(): Correct remote_closed assertion to handle
    early-job-logging scenario where a job satisfies both of the
    following conditions:
    - ends before the log directory becomes writeable.
    - has spawned one or more processes that continue to run after the
      job itself has exited and which produce output before the log
      directory becomes writeable.
    (LP: #1096531).

James Hunt (jamesodhunt) wrote :

The reason we don't honour the LOGDIR_ENV variable for Session Inits is to handle the scenario where the root user starts its own Session Init: if that is to happen, we don't want the root Session Init to log to the same directory as Upstart running as PID 1 should the LOGDIR_ENV variable be set when root starts the Session Init.

Dimitri John Ledkov (xnox) wrote :

Reading XDG specification, it sounds like instead of $XDG_CACHE_HOME/upstart/sessions, we instead should be using $XDG_RUNTIME_DIR/upstart/ to store session init's pids.

"""
$XDG_RUNTIME_DIR defines the base directory relative to which user-specific non-essential runtime files and other file objects (such as sockets, named pipes, ...) should be stored. The directory MUST be owned by the user, and he MUST be the only one having read and write access to it. Its Unix access mode MUST be 0700.

The lifetime of the directory MUST be bound to the user being logged in. It MUST be created when the user first logs in and if the user fully logs out the directory MUST be removed. If the user logs in more than once he should get pointed to the same directory, and it is mandatory that the directory continues to exist from his first login to his last logout on the system, and not removed in between. Files in the directory MUST not survive reboot or a full logout/login cycle.
"""

http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html

Currently I like how all our logs are stored in a flat directory and I'd rather not introduce subdirs.

Shall I update the spec with:
logs go to $XDG_CACHE_HOME/upstart
the address of the session goes to $XDG_RUNTIME_DIR/upstart

James Hunt (jamesodhunt) wrote :

Sounds good. Yes, please update the spec.

Please can you also update the doc as outlined in original comments. Also...

* init/xdg.c:
  xdg_get_cache_home(): XDG_CACHE_HOME and ".cache" should be defined in init/paths.h for consistency.

Steve Langasek (vorlon) wrote :

On Wed, Jan 16, 2013 at 12:02:21PM -0000, Dmitrijs Ledkovs wrote:

> Reading XDG specification, it sounds like instead of
> $XDG_CACHE_HOME/upstart/sessions, we instead should be using
> $XDG_RUNTIME_DIR/upstart/ to store session init's pids.

> """

> $XDG_RUNTIME_DIR defines the base directory relative to which
> user-specific non-essential runtime files and other file objects (such as
> sockets, named pipes, ...) should be stored. The directory MUST be owned
> by the user, and he MUST be the only one having read and write access to
> it. Its Unix access mode MUST be 0700.

> The lifetime of the directory MUST be bound to the user being logged in.
> It MUST be created when the user first logs in and if the user fully logs
> out the directory MUST be removed. If the user logs in more than once he
> should get pointed to the same directory, and it is mandatory that the
> directory continues to exist from his first login to his last logout on
> the system, and not removed in between. Files in the directory MUST not
> survive reboot or a full logout/login cycle.

This last paragraph is the problematic part, since up to this point AIUI
we've been discussing having one upstart session per login session, *not*
one upstart session per logged-in user. XDG_RUNTIME_DIR only has the
correct semantics for the latter.

Dimitri John Ledkov (xnox) wrote :

XDG_RUNTIME_DIR guarantees that we get the same dir no matter how many times we login.
We can manage multiple pids/sockets ourself per user.

The file we store there will be pid e.g. $XDG_RUNTIME_DIR/upstart/12345
For another session (for the same user) we will have pid e.g. $XDG_RUNTIME_DIR/upstart/15001
This is to support one upstart session per login session.

The will know the current session via environment variable.
Also we can implement `initctl list-sessions` command simply by iterating $XDG_RUNTIME_DIR/upstart/.

XDG_CACHE_HOME is not guaranteed to be cleared, while XDG_RUNTIME_DIR will always be fresh after reboots & complete logouts.

Dimitri John Ledkov (xnox) wrote :

> Sounds good. Yes, please update the spec.
>
> Please can you also update the doc as outlined in original comments. Also...
>
> * init/xdg.c:
> xdg_get_cache_home(): XDG_CACHE_HOME and ".cache" should be defined in
> init/paths.h for consistency.

Why? I only defined upstart specific constants in path.h, e.g. INIT_XDG_SUBDIR - the name of the subdirectory we use within all XDG_* locations.

XDG_* variables are not upstart specific and are compliant with the XDG spec.
Also their fallbacks "/etc/xdg/", "~/.config", "~/.cache" are defined in the XDG spec.
I am failing to see benefits or introducing #ifndef pointers to those names, since changing those will violate XDG specification.
And XDG specification is unlikely to change in a backwards incompatible way at this point.

Note that XDG_CONFIG_HOME, XDG_CONFIG_DIRS, "~/.config", "/etc/xdg/" are not defined in paths.h.

If libnih starts using XDG_* paths for anything, it might even make sense to move xdg_ helper functions into libnih.

I guess I can make a static array of those constants at the top of xdg.c for ease of understanding that these constants are externally specified.

James Hunt (jamesodhunt) wrote :

OK, you've convinced me on paths.h :-)

I've updated the spec such that we have a script which sets the appropriate XDG vars if not already set *and* creates them if they don't exist. It will then start the Session Init. However, I wonder if the Session Init should also attempt to create the directories returned by xdg_get_cache_home() and xdg_get_config_home() to handle the scenario that a user logs in multiple times and in the first session say deletes one or both of these directories.

I think that to be conformant to the XDG spec, the alluded-to script can as Dmitrijs says run 'initctl list-sessions' and if that returns nothing, remove XDG_RUNTIME_DIR before exiting.

After scrutinizing the XDG spec again, we do need to make some minor changes:

* init/xdg.c:
  - xdg_get_cache_home(): This must check that if XDG_CACHE_HOME is set that it also is an absolute path before we use it.
  - xdg_get_config_home(): Same logic as above for XDG_CONFIG_HOME.
  - get_user_upstart_dirs(): Same logic for XDG_CONFIG_DIRS.

Dimitri John Ledkov (xnox) wrote :

> OK, you've convinced me on paths.h :-)
>
> I've updated the spec such that we have a script which sets the appropriate
> XDG vars if not already set *and* creates them if they don't exist. It will

no, this is wrong again.
It's perfectly valid to not have XDG_HOME_* variables set, as by default the default fallbacks should be used.
It's only meant for a user to change them if they want to launch set of applications with "clean" config, cache.
The XDG_RUNTIME_DIR in ubuntu is already set by libpam-xdg-support
https://blueprints.launchpad.net/ubuntu/+spec/foundations-q-xdg-runtime-dir

So these variables should not be set, if they don't already exist.

Creating the directories if they don't yet exist is a good point. Especially brand new accounts, might not have those directories.
Oh and as per XDG spec we should create them with permissions 0700 if we need to access them.

The spec is unclear about XDG_RUNTIME_DIR, I'd like to assert if it doesn't exist. In ubuntu it exists in quantal and up. To be compliant with the spec we should gracefully fallback to some other place, but I don't know what that other place is a good to fallback to.

> then start the Session Init. However, I wonder if the Session Init should also
> attempt to create the directories returned by xdg_get_cache_home() and
> xdg_get_config_home() to handle the scenario that a user logs in multiple
> times and in the first session say deletes one or both of these directories.
>

I don't like the idea of creating empty directories, just to place inotify watch on it (for the $XDG_CONFIG_HOME/upstart).
We intend to generate logs everytime, so precreating $XDG_CACHE_HOME/upstart makes sense.

> I think that to be conformant to the XDG spec, the alluded-to script can as
> Dmitrijs says run 'initctl list-sessions' and if that returns nothing, remove
> XDG_RUNTIME_DIR before exiting.
>

I believe XDG_RUNTIME_DIR is cleaned up for us after the last logout. I'll check that. Or do you mean to clean up bits in the $XDG_RUNTIME_DIR/upstart/ that we created? E.g. remove pidfiles on exit?

(outside of this merge proposal as far as I can see)

> After scrutinizing the XDG spec again, we do need to make some minor changes:
>
> * init/xdg.c:
> - xdg_get_cache_home(): This must check that if XDG_CACHE_HOME is set that
> it also is an absolute path before we use it.
> - xdg_get_config_home(): Same logic as above for XDG_CONFIG_HOME.
> - get_user_upstart_dirs(): Same logic for XDG_CONFIG_DIRS.

All good points.

James Hunt (jamesodhunt) wrote :

> > OK, you've convinced me on paths.h :-)
> >
> > I've updated the spec such that we have a script which sets the appropriate
> > XDG vars if not already set *and* creates them if they don't exist. It will
>
> no, this is wrong again.
> It's perfectly valid to not have XDG_HOME_* variables set, as by default the default fallbacks should be used.
> It's only meant for a user to change them if they want to launch set of applications with "clean" config, cache.
> The XDG_RUNTIME_DIR in ubuntu is already set by libpam-xdg-support
> https://blueprints.launchpad.net/ubuntu/+spec/foundations-q-xdg-runtime-dir
>
> So these variables should not be set, if they don't already exist.
>
> Creating the directories if they don't yet exist is a good point. Especially brand new accounts, might not have those directories.

The reason for my specifying in the spec that we create the directories is that if they do not already exist, we end up with impotent inotify watches: meaning no job logging and no way for a user to create jobs *after* they create ~/.config/upstart/ manually. All very confusing from the users perspective. However, yes, seemingly we should not set them, implying Upstart needs to handle this.

> Oh and as per XDG spec we should create them with permissions 0700 if we need to access them.

Right.

>
> The spec is unclear about XDG_RUNTIME_DIR, I'd like to assert if it doesn't exist. In ubuntu it exists in quantal and up. To be compliant with the spec we should gracefully fallback to some other place, but I don't know what that other place is a good to fallback to.

Asserting is a little harsh. If it's not set, how about we display a warning and then fall back to ${TMPDIR}/${USER} and if that's not set, /tmp/${USER}? Steve?

>
> > then start the Session Init. However, I wonder if the Session Init should also
> > attempt to create the directories returned by xdg_get_cache_home() and
> > xdg_get_config_home() to handle the scenario that a user logs in multiple
> > times and in the first session say deletes one or both of these directories.

Lets go with this then and I'll revert the spec change.

> >
>
> I don't like the idea of creating empty directories, just to place inotify watch on it (for the $XDG_CONFIG_HOME/upstart).
> We intend to generate logs everytime, so precreating $XDG_CACHE_HOME/upstart makes sense.

See above: we need to do both as what is the point in creating the log directory if no jobs can be registered if the config directory does not exist? 1 inotify watch is a small price to pay for sane behaviour. Added to which there is precedent: we already create a watch for /etc/init.conf.

>
> > I think that to be conformant to the XDG spec, the alluded-to script can as
> > Dmitrijs says run 'initctl list-sessions' and if that returns nothing, remove
> > XDG_RUNTIME_DIR before exiting.
> >
>
> I believe XDG_RUNTIME_DIR is cleaned up for us after the last logout. I'll check that. Or do you mean to clean up bits in the $XDG_RUNTIME_DIR/upstart/ that we created? E.g. remove pidfiles on exit?

What is doing the cleaning up currently? And will that need to change when Upstart is in control?

Steve Langasek (vorlon) wrote :

On Thu, Jan 17, 2013 at 02:20:29PM -0000, James Hunt wrote:

> > The spec is unclear about XDG_RUNTIME_DIR, I'd like to assert if it
> > doesn't exist. In ubuntu it exists in quantal and up. To be compliant
> > with the spec we should gracefully fallback to some other place, but I
> > don't know what that other place is a good to fallback to.

> Asserting is a little harsh. If it's not set, how about we display a
> warning and then fall back to ${TMPDIR}/${USER} and if that's not set,
> /tmp/${USER}? Steve

I suggest consulting the desktop team, or looking at existing fd.o software,
for recommendations on a fallback path. Using ${TMPDIR:-/tmp}/${USER} has
some obvious security problems (best case: DoS) that are undesirable even in
a fallback.

I do agree that an assert() here is a bit harsh. In theory we should never
be without $XDG_RUNTIME_DIR in quantal and beyond; however, this is
implemented by way of the pam stack and relies on the local admin not
altering /etc/pam.d/common-session in an "unsupported" manner. I fear that
having upstart assert instead of opening a login session will be rather
undebuggable, and I doubt this is a good tradeoff for something that's
rather peripheral to the main functionality of upstart.

> > I believe XDG_RUNTIME_DIR is cleaned up for us after the last logout.
> > I'll check that. Or do you mean to clean up bits in the
> > $XDG_RUNTIME_DIR/upstart/ that we created? E.g. remove pidfiles on
> > exit?

> What is doing the cleaning up currently? And will that need to change when
> Upstart is in control?

pam_xdg_support, which is the same thing that creates the directory and sets
the env variable. This must not change under upstart user sessions.

lp:~xnox/upstart/user-log-dir updated on 2013-01-21
1426. By James Hunt on 2013-01-21

* init/log.c:log_clear_unflushed(): Simplify asserts.

Dimitri John Ledkov (xnox) wrote :

* Documentation is updated
* Checks for absolute paths added (i.e. must start with '/')
* XDG_HOME_* directories & subdirectories are created

* XDG_RUNTIME_DIR & fallback is not implemented. Need to consult desktop team on fallbacks (e.g. how other XDG compliant software handles it) and then this will be quick to add as a separate merge proposal.

I think this branch is complete for now.

James Hunt (jamesodhunt) wrote :

Hi Dmitrijs,

Just a few comments:

* init/xdg.c:
  - get_home_subdir(): Return NULL immediately if nih_sprintf() fails.
  - get_user_log_dir(): Return NULL immediately if nih_sprintf() fails.
  - create_dir():
    - for consistency, this should probably call
      init/system.c:int system_mkdir(const char *path, mode_t mode) passing
      @dir and 0700.
    - should assert @dir: I don't understand why it currently handles
      a NULL directory explicitly?
    - @dir param should be const.
    - Remove comment: the directory permissions must be 0700 according
      to the spec, which is an absolute value. Since we already reset
      umask(), the code will work as expected.
    - This (and/or system_mkdir()) should be documented explicitly as
      only creating the "leaf" directory (ie no recursive creation).

review: Needs Fixing
Dimitri John Ledkov (xnox) wrote :

On 22 January 2013 10:28, James Hunt <email address hidden> wrote:
>
> * init/xdg.c:
> - get_home_subdir(): Return NULL immediately if nih_sprintf() fails.
> - get_user_log_dir(): Return NULL immediately if nih_sprintf() fails.

Done.

> - create_dir():
> - for consistency, this should probably call
> init/system.c:int system_mkdir(const char *path, mode_t mode) passing
> @dir and 0700.
> - should assert @dir: I don't understand why it currently handles
> a NULL directory explicitly?

Well, it did so because I didn't return Null straight away when
nih_sprintfs failed in get_home_subdir() and get_user_log_dir().

> - @dir param should be const.
> - Remove comment: the directory permissions must be 0700 according
> to the spec, which is an absolute value. Since we already reset
> umask(), the code will work as expected.

Awesome. Didn't notice this.

> - This (and/or system_mkdir()) should be documented explicitly as
> only creating the "leaf" directory (ie no recursive creation).

Well... after changing get_home_subdir() & get_user_log_dir(), the
"system_mkdir()" is a wrapper with nih_assert around path argument....
I think I went overboard with this wrapper =) instead I just use mkdir
directly. I guess we could add further nih_system_error / warning
saying that we failed to create XDG paths, but imho that's just noise.

lp:~xnox/upstart/user-log-dir updated on 2013-01-23
1427. By James Hunt on 2013-01-23

* Merge of lp:~stgraber/upstart/upstart-session-socket.

1428. By Dimitri John Ledkov on 2013-01-23

Merge user-dirs

1429. By Dimitri John Ledkov on 2013-01-23

Normalise user_mode extern definitions

James Hunt (jamesodhunt) wrote :

Hi Dmitrijs,

Thanks - merged.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'ChangeLog'
2--- ChangeLog 2013-01-21 16:24:48 +0000
3+++ ChangeLog 2013-01-23 13:00:29 +0000
4@@ -1,3 +1,15 @@
5+2013-01-21 Dmitrijs Ledkovs <xnox@ubuntu.com>
6+
7+ * init/xdg.[ch]: add xdg_get_cache_home and get_user_log_dir
8+ functions. These retrieve XDG_CACHE_HOME and a subdir inside it
9+ for upstart.
10+ * init/tests/test_xdg.c: reuse test_get_config_home to test both
11+ xdg_get_cache_home and xdg_get_config_home. Add test for
12+ get_user_log_dir.
13+ * init/main.c: use get_user_log_dir to setup logging
14+ directory in user_mode. For now, command line argument is
15+ honoured, while the environment override is not.
16+
17 2013-01-21 James Hunt <james.hunt@ubuntu.com>
18
19 * init/log.c:log_clear_unflushed(): Simplify asserts.
20
21=== modified file 'init/Makefile.am'
22--- init/Makefile.am 2012-12-19 12:46:46 +0000
23+++ init/Makefile.am 2013-01-23 13:00:29 +0000
24@@ -177,7 +177,7 @@
25 system.o environ.o process.o \
26 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
27 parse_job.o parse_conf.o conf.o control.o \
28- session.o log.o state.o \
29+ session.o log.o state.o xdg.o \
30 com.ubuntu.Upstart.o \
31 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
32 $(NIH_LIBS) \
33@@ -191,7 +191,7 @@
34 system.o environ.o process.o \
35 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
36 parse_job.o parse_conf.o conf.o control.o \
37- session.o log.o state.o \
38+ session.o log.o state.o xdg.o \
39 com.ubuntu.Upstart.o \
40 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
41 $(NIH_LIBS) \
42@@ -205,7 +205,7 @@
43 system.o environ.o process.o \
44 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
45 parse_job.o parse_conf.o conf.o control.o \
46- session.o log.o state.o \
47+ session.o log.o state.o xdg.o \
48 com.ubuntu.Upstart.o \
49 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
50 $(NIH_LIBS) \
51@@ -219,7 +219,7 @@
52 system.o environ.o process.o \
53 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
54 parse_job.o parse_conf.o conf.o control.o \
55- session.o log.o state.o \
56+ session.o log.o state.o xdg.o \
57 com.ubuntu.Upstart.o \
58 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
59 $(NIH_LIBS) \
60@@ -233,7 +233,7 @@
61 system.o environ.o process.o \
62 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
63 parse_job.o parse_conf.o conf.o control.o \
64- session.o log.o state.o \
65+ session.o log.o state.o xdg.o \
66 com.ubuntu.Upstart.o \
67 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
68 $(NIH_LIBS) \
69@@ -247,7 +247,7 @@
70 system.o environ.o process.o \
71 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
72 parse_job.o parse_conf.o conf.o control.o \
73- session.o log.o state.o \
74+ session.o log.o state.o xdg.o \
75 com.ubuntu.Upstart.o \
76 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
77 $(NIH_LIBS) \
78@@ -261,7 +261,7 @@
79 system.o environ.o process.o \
80 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
81 parse_job.o parse_conf.o conf.o control.o \
82- session.o log.o state.o \
83+ session.o log.o state.o xdg.o \
84 com.ubuntu.Upstart.o \
85 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
86 $(NIH_LIBS) \
87@@ -275,7 +275,7 @@
88 system.o environ.o process.o \
89 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
90 parse_job.o parse_conf.o conf.o control.o \
91- session.o log.o state.o \
92+ session.o log.o state.o xdg.o \
93 com.ubuntu.Upstart.o \
94 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
95 $(NIH_LIBS) \
96@@ -289,7 +289,7 @@
97 system.o environ.o process.o \
98 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
99 parse_job.o parse_conf.o conf.o control.o \
100- session.o log.o state.o \
101+ session.o log.o state.o xdg.o \
102 com.ubuntu.Upstart.o \
103 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
104 $(NIH_LIBS) \
105@@ -303,7 +303,7 @@
106 system.o environ.o process.o \
107 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
108 parse_job.o parse_conf.o conf.o control.o \
109- session.o log.o state.o \
110+ session.o log.o state.o xdg.o \
111 com.ubuntu.Upstart.o \
112 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
113 $(NIH_LIBS) \
114@@ -317,7 +317,7 @@
115 system.o environ.o process.o \
116 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
117 parse_job.o parse_conf.o conf.o control.o \
118- session.o log.o state.o \
119+ session.o log.o state.o xdg.o \
120 com.ubuntu.Upstart.o \
121 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
122 $(NIH_LIBS) \
123@@ -331,7 +331,7 @@
124 system.o environ.o process.o \
125 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
126 parse_job.o parse_conf.o conf.o control.o \
127- session.o log.o state.o \
128+ session.o log.o state.o xdg.o \
129 com.ubuntu.Upstart.o \
130 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
131 $(NIH_LIBS) \
132@@ -345,7 +345,7 @@
133 system.o environ.o process.o \
134 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
135 parse_job.o parse_conf.o control.o \
136- session.o log.o state.o \
137+ session.o log.o state.o xdg.o \
138 com.ubuntu.Upstart.o \
139 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
140 $(NIH_LIBS) \
141@@ -366,7 +366,7 @@
142 system.o environ.o process.o \
143 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
144 parse_job.o parse_conf.o conf.o control.o \
145- session.o log.o state.o \
146+ session.o log.o state.o xdg.o \
147 com.ubuntu.Upstart.o \
148 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
149 $(NIH_LIBS) \
150
151=== modified file 'init/control.c'
152--- init/control.c 2013-01-22 15:51:01 +0000
153+++ init/control.c 2013-01-23 13:00:29 +0000
154@@ -76,13 +76,6 @@
155 int use_session_bus = FALSE;
156
157 /**
158- * user_mode:
159- *
160- * If TRUE, upstart runs in user session mode.
161- **/
162-int user_mode = FALSE;
163-
164-/**
165 * control_server_address:
166 *
167 * Address on which the control server may be reached.
168@@ -112,6 +105,8 @@
169 **/
170 NihList *control_conns = NULL;
171
172+/* External definitions */
173+extern int user_mode;
174
175 /**
176 * control_init:
177
178=== modified file 'init/job_process.c'
179--- init/job_process.c 2013-01-21 22:44:27 +0000
180+++ init/job_process.c 2013-01-23 13:00:29 +0000
181@@ -66,6 +66,7 @@
182 #include "job.h"
183 #include "errors.h"
184 #include "control.h"
185+#include "xdg.h"
186
187
188 /**
189@@ -2197,7 +2198,7 @@
190 nih_assert (class->name);
191
192 /* Override, primarily for tests */
193- if (getenv (LOGDIR_ENV)) {
194+ if (getenv (LOGDIR_ENV) && ! user_mode) {
195 dir = nih_strdup (NULL, getenv (LOGDIR_ENV));
196 nih_debug ("Using alternative directory '%s' for logs", dir);
197 } else {
198
199=== modified file 'init/main.c'
200--- init/main.c 2013-01-22 15:53:05 +0000
201+++ init/main.c 2013-01-23 13:00:29 +0000
202@@ -949,6 +949,11 @@
203 if (log_dir)
204 goto out;
205
206+ if (user_mode) {
207+ log_dir = get_user_log_dir ();
208+ return;
209+ }
210+
211 log_dir = JOB_LOGDIR;
212
213 dir = getenv (LOGDIR_ENV);
214
215=== modified file 'init/man/init.5'
216--- init/man/init.5 2013-01-16 19:20:54 +0000
217+++ init/man/init.5 2013-01-23 13:00:29 +0000
218@@ -149,11 +149,8 @@
219 of that job name: any subsequently searched directory that contains a
220 job of the same name will be ignored. The same applies for override
221 files: only the first override file found in the search order will be
222-applied. Note that an override file does not have to be in the same
223-directory as the job it overrides, but if not in the directory of the
224-job it overrides, it must be in an
225-.I earlier
226-directory to that which contains the job.
227+applied. Note that an override file can be in the same directory or
228+earlier to that directory which contains the job file.
229
230 Jobs in these locations are expected to launch the user's session.
231 Upstart will try to parent all spawned process with the aid of
232@@ -166,6 +163,12 @@
233 When running in User Session mode, Upstart will kill all job processes
234 on session logout or shutdown.
235
236+All log output will be in
237+.I $XDG_CACHE_HOME/upstart
238+which defaults to
239+.I $HOME/.cache/upstart
240+.
241+
242 .\"
243 .SS Configuration File Format
244 Each line begins with a configuration stanza and continues until either
245@@ -664,19 +667,23 @@
246 .B log
247 .RS
248 .B
249-Only applies to system jobs:
250+Only applies to system and user session jobs:
251 if specified by user jobs, the job will be considered to have specified
252 the value
253 .BR none "."
254
255-For system jobs, if \fBlog\fR is specified, standard input is connected
256+For system and user session jobs jobs, if \fBlog\fR is specified, standard input is connected
257 to
258 .IR /dev/null ","
259 and standard output and standard error are connected to a pseudo-tty
260 which logs all job output.
261
262 Output is logged to file
263-.IR /var/log/upstart/<job-log-file> "."
264+.IR /var/log/upstart/<job-log-file>
265+or
266+.IR $XDG_CACHE_HOME/upstart/<job-log-file>
267+for system and user session jobs respectively.
268+
269 If a job has specified \fBinstance\fR,
270 .I <job-log-file>
271 will equate to
272@@ -1019,18 +1026,30 @@
273 .TP
274 .I $HOME/.init/*.conf
275 User job configuration files.
276-Note that you may make the directory
277-.I $HOME/.init/
278-a symbolic link to
279-.BR $HOME/.config/upstart/ "."
280 .
281 .TP
282 .I $HOME/.init/*.override
283 User job override files.
284 .
285 .TP
286+.I $XDG_CONFIG_HOME/upstart/*.conf
287+User session job configuration files. See
288+.B User Session Mode
289+for other locations.
290+.
291+.TP
292+.I $XDG_CONFIG_HOME/upstart/*.override
293+User session job override files. See
294+.B User Session Mode
295+for other locations.
296+.
297+.TP
298 .I /var/log/upstart/*.log
299 Default location of system job output logs.
300+.
301+.TP
302+.I $XDG_CACHE_HOME/upstart/*.log
303+Default location of user session job output logs.
304 .RE
305 .\"
306 .SH AUTHOR
307
308=== modified file 'init/man/init.8'
309--- init/man/init.8 2012-12-18 17:40:49 +0000
310+++ init/man/init.8 2013-01-23 13:00:29 +0000
311@@ -67,6 +67,8 @@
312 .B \-\-confdir \fIdirectory\fP
313 Read job configuration files from a directory other than
314 \fI/etc/init\fP.
315+For user session mode, read job configuration files from this
316+directory at highest priority.
317 .\"
318 .TP
319 .B \-\-default-console \fIvalue\fP
320@@ -81,7 +83,8 @@
321 .TP
322 .B \-\-logdir \fIdirectory\fP
323 Write job output log files to a directory other than
324-\fI/var/log/upstart\fP.
325+\fI/var/log/upstart\fP (system mode) or \fI$XDG_CACHE_HOME/upstart\fP
326+(user session mode).
327 .\"
328 .TP
329 .B \-\-no\-log
330
331=== modified file 'init/tests/test_xdg.c'
332--- init/tests/test_xdg.c 2012-12-18 14:16:10 +0000
333+++ init/tests/test_xdg.c 2013-01-23 13:00:29 +0000
334@@ -22,12 +22,26 @@
335 #include <nih/string.h>
336 #include <nih/test.h>
337
338+#include <limits.h>
339 #include <stdlib.h>
340-#include <limits.h>
341+#include <sys/types.h>
342+#include <sys/stat.h>
343+#include <unistd.h>
344
345 #include "xdg.h"
346
347 void
348+_test_dir_created (char * dirname) {
349+ struct stat statbuf;
350+
351+ TEST_EQ (lstat (dirname, &statbuf), 0);
352+ TEST_TRUE (S_ISDIR (statbuf.st_mode));
353+
354+ /* Check that the created directory has 0700 permissions, as per XDG spec */
355+ TEST_EQ (0700, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
356+}
357+
358+void
359 test_get_home_subdir (void)
360 {
361 char dirname[PATH_MAX];
362@@ -40,7 +54,7 @@
363 TEST_EQ (unsetenv ("HOME"), 0);
364
365 TEST_ALLOC_FAIL {
366- dir = get_home_subdir ("test");
367+ dir = get_home_subdir ("test", FALSE);
368 TEST_EQ_P (dir, NULL);
369 }
370
371@@ -54,7 +68,7 @@
372 expected = NIH_MUST (nih_sprintf (NULL, "%s/test", dirname));
373 }
374
375- dir = get_home_subdir ("test");
376+ dir = get_home_subdir ("test", FALSE);
377
378 if (test_alloc_failed) {
379 TEST_EQ_P (dir, NULL);
380@@ -69,28 +83,29 @@
381 }
382
383 void
384-test_get_config_home (void)
385+_test_get_home (char * env_var_name, char * dir_name, char * (*function)(void))
386 {
387 char dirname[PATH_MAX];
388+ char onemore[PATH_MAX];
389 char * outname;
390 char * expected;
391
392- TEST_FUNCTION ("xdg_get_config_home");
393-
394 TEST_FEATURE ("with HOME set and without environment override");
395 TEST_FILENAME (dirname);
396 TEST_EQ (setenv ("HOME", dirname, 1), 0);
397- TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
398+ TEST_EQ (mkdir (dirname, 0755), 0);
399+ TEST_EQ (unsetenv (env_var_name), 0);
400 TEST_ALLOC_FAIL {
401 TEST_ALLOC_SAFE {
402- expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));
403+ expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
404 }
405
406 outname = NULL;
407- outname = xdg_get_config_home ();
408+ outname = function ();
409
410 if (! test_alloc_failed) {
411 TEST_EQ_STR (outname, expected);
412+ _test_dir_created (expected);
413 } else {
414 TEST_EQ_P (outname, NULL);
415 }
416@@ -98,83 +113,131 @@
417 if (outname)
418 nih_free (outname);
419
420- nih_free(expected);
421+ rmdir (expected);
422+ nih_free (expected);
423 }
424
425 TEST_FEATURE ("with HOME set and with empty environment override");
426- TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);
427-
428-
429- TEST_ALLOC_FAIL {
430- TEST_ALLOC_SAFE {
431- expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));
432- }
433- outname = NULL;
434- outname = xdg_get_config_home();
435-
436- if (test_alloc_failed) {
437- TEST_EQ_P (outname, NULL);
438- } else {
439- TEST_EQ_STR (outname, expected);
440- }
441- if (outname)
442- nih_free (outname);
443- nih_free(expected);
444+ TEST_EQ (setenv (env_var_name, "", 1), 0);
445+
446+
447+ TEST_ALLOC_FAIL {
448+ TEST_ALLOC_SAFE {
449+ expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
450+ }
451+ outname = NULL;
452+ outname = function ();
453+
454+ if (test_alloc_failed) {
455+ TEST_EQ_P (outname, NULL);
456+ } else {
457+ TEST_EQ_STR (outname, expected);
458+ _test_dir_created (expected);
459+ }
460+ if (outname)
461+ nih_free (outname);
462+ rmdir (expected);
463+ nih_free (expected);
464+ }
465+
466+ TEST_FEATURE ("with HOME set and with relative environment override");
467+ TEST_EQ (setenv (env_var_name, "../", 1), 0);
468+
469+
470+ TEST_ALLOC_FAIL {
471+ TEST_ALLOC_SAFE {
472+ expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
473+ }
474+ outname = NULL;
475+ outname = function ();
476+
477+ if (test_alloc_failed) {
478+ TEST_EQ_P (outname, NULL);
479+ } else {
480+ TEST_EQ_STR (outname, expected);
481+ _test_dir_created (expected);
482+ }
483+ if (outname)
484+ nih_free (outname);
485+ rmdir (expected);
486+ nih_free (expected);
487 }
488
489 TEST_FEATURE ("with HOME set and with environment override");
490- expected = NIH_MUST (nih_strdup (NULL, "/home/me/.config-test"));
491- TEST_EQ (setenv ("XDG_CONFIG_HOME", expected, 1), 0);
492+ TEST_FILENAME (onemore);
493+ expected = NIH_MUST (nih_sprintf (NULL, "%s", onemore));
494+ TEST_EQ (setenv (env_var_name, expected, 1), 0);
495
496 TEST_ALLOC_FAIL {
497 outname = NULL;
498- outname = xdg_get_config_home();
499+ outname = function ();
500
501 if (test_alloc_failed) {
502 TEST_EQ_P (outname, NULL);
503 } else {
504 TEST_EQ_STR (outname, expected);
505+ _test_dir_created (expected);
506 }
507 if (outname)
508 nih_free (outname);
509+ rmdir (expected);
510 }
511
512+ TEST_EQ (rmdir (dirname), 0);
513+
514 TEST_FEATURE ("without HOME set and with environment override");
515 TEST_EQ (unsetenv ("HOME"), 0);
516
517 TEST_ALLOC_FAIL {
518 outname = NULL;
519- outname = xdg_get_config_home();
520+ outname = function ();
521
522 if (test_alloc_failed) {
523 TEST_EQ_P (outname, NULL);
524 } else {
525 TEST_EQ_STR (outname, expected);
526+ _test_dir_created (expected);
527 }
528 if (outname)
529 nih_free (outname);
530+ rmdir (expected);
531 }
532 nih_free(expected);
533
534 TEST_FEATURE ("without HOME set and with empty environment override");
535- TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);
536+ TEST_EQ (setenv (env_var_name, "", 1), 0);
537
538 TEST_ALLOC_FAIL {
539 outname = NULL;
540- outname = xdg_get_config_home();
541+ outname = function ();
542 TEST_EQ_P (outname, NULL);
543 }
544
545 TEST_FEATURE ("without HOME set and without environment override");
546- TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
547+ TEST_EQ (unsetenv (env_var_name), 0);
548 TEST_ALLOC_FAIL {
549 outname = NULL;
550- outname = xdg_get_config_home();
551+ outname = function ();
552 TEST_EQ_P (outname, NULL);
553 }
554 }
555
556 void
557+test_get_config_home (void)
558+{
559+ TEST_FUNCTION ("xdg_get_config_home");
560+ _test_get_home ("XDG_CONFIG_HOME", ".config", &xdg_get_config_home);
561+
562+}
563+
564+void
565+test_get_cache_home (void)
566+{
567+ TEST_FUNCTION ("xdg_get_cache_home");
568+ _test_get_home ("XDG_CACHE_HOME", ".cache", &xdg_get_cache_home);
569+}
570+
571+void
572 test_get_config_dirs (void)
573 {
574 char **dirs = NULL;
575@@ -260,12 +323,12 @@
576 TEST_FEATURE ("with HOME set");
577 TEST_FILENAME (dirname);
578 TEST_EQ (setenv ("HOME", dirname, 1), 0);
579+ TEST_EQ (mkdir (dirname, 0755), 0);
580 TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
581 TEST_EQ (unsetenv ("XDG_CONFIG_DIRS"), 0);
582
583 TEST_ALLOC_FAIL {
584 TEST_ALLOC_SAFE {
585- dirs = NULL;
586 expected = nih_str_array_new (NULL);
587 path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));
588 assert (nih_str_array_add (&expected, NULL, NULL, path));
589@@ -282,15 +345,94 @@
590 TEST_EQ_P (dirs, NULL);
591 } else {
592 TEST_EQ_STR (dirs[0], expected[0]);
593+ //_test_dir_created (expected[0]);
594 TEST_EQ_STR (dirs[1], expected[1]);
595 TEST_EQ_STR (dirs[2], "/etc/xdg/upstart");
596 TEST_EQ_STR (dirs[3], SYSTEM_USERCONFDIR);
597 TEST_EQ (dirs[4], NULL);
598 nih_free (dirs);
599 }
600- nih_free(expected);
601- }
602-
603+ TEST_ALLOC_SAFE {
604+ rmdir (expected[0]);
605+ path = nih_sprintf (NULL, "%s/.config", dirname);
606+ rmdir (path);
607+ nih_free (path);
608+ nih_free (expected);
609+ }
610+ }
611+
612+ TEST_FEATURE ("with some invalid XDG_CONFIG_DIRS");
613+ TEST_EQ (setenv ("XDG_CONFIG_DIRS", "/etc/xdg/xdg-subdir:../haha:/etc/xdg", 1), 0);
614+
615+ TEST_ALLOC_FAIL {
616+ TEST_ALLOC_SAFE {
617+ expected = nih_str_array_new (NULL);
618+ path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));
619+ assert (nih_str_array_add (&expected, NULL, NULL, path));
620+ nih_free(path);
621+ path = NIH_MUST (nih_sprintf (NULL, "%s/.init", dirname));
622+ assert (nih_str_array_add (&expected, NULL, NULL, path));
623+ nih_free(path);
624+ }
625+
626+ dirs = NULL;
627+ dirs = get_user_upstart_dirs ();
628+
629+ if (test_alloc_failed) {
630+ TEST_EQ_P (dirs, NULL);
631+ } else {
632+ TEST_EQ_STR (dirs[0], expected[0]);
633+ _test_dir_created (expected[0]);
634+ TEST_EQ_STR (dirs[1], expected[1]);
635+ TEST_EQ_STR (dirs[2], "/etc/xdg/xdg-subdir/upstart");
636+ TEST_EQ_STR (dirs[3], "/etc/xdg/upstart");
637+ TEST_EQ_STR (dirs[4], SYSTEM_USERCONFDIR);
638+ TEST_EQ (dirs[5], NULL);
639+ nih_free (dirs);
640+ }
641+ TEST_ALLOC_SAFE {
642+ rmdir (expected[0]);
643+ path = nih_sprintf (NULL, "%s/.config", dirname);
644+ rmdir (path);
645+ nih_free (path);
646+ nih_free (expected);
647+ }
648+ }
649+ TEST_EQ (rmdir (dirname), 0);
650+}
651+
652+void
653+test_get_user_log_dir (void)
654+{
655+ char dirname[PATH_MAX];
656+ char *expected;
657+ char *path;
658+
659+ TEST_FUNCTION ("get_user_log_dir");
660+ TEST_FEATURE ("with HOME set");
661+ TEST_FILENAME (dirname);
662+ TEST_EQ (setenv ("HOME", dirname, 1), 0);
663+ TEST_EQ (mkdir (dirname, 0755), 0);
664+ TEST_EQ (unsetenv ("XDG_CACHE_HOME"), 0);
665+
666+ expected = nih_sprintf (NULL, "%s/.cache/upstart", dirname);
667+
668+ TEST_ALLOC_FAIL {
669+ path = get_user_log_dir ();
670+ if (test_alloc_failed) {
671+ TEST_EQ_P (path, NULL);
672+ } else {
673+ TEST_EQ_STR (path, expected);
674+ _test_dir_created (expected);
675+ nih_free (path);
676+ }
677+ }
678+ rmdir (expected);
679+ nih_free (expected);
680+ path = nih_sprintf (NULL, "%s/.cache", dirname);
681+ rmdir (path);
682+ nih_free (path);
683+ rmdir (dirname);
684 }
685
686 int
687@@ -301,6 +443,8 @@
688 test_get_config_home ();
689 test_get_config_dirs ();
690 test_get_user_upstart_dirs ();
691+ test_get_cache_home ();
692+ test_get_user_log_dir ();
693
694 return 0;
695 }
696
697=== modified file 'init/xdg.c'
698--- init/xdg.c 2012-12-18 16:31:55 +0000
699+++ init/xdg.c 2013-01-23 13:00:29 +0000
700@@ -24,6 +24,8 @@
701 #endif /* HAVE_CONFIG_H */
702
703 #include <stdlib.h>
704+#include <sys/stat.h>
705+#include <sys/types.h>
706
707 #include <nih/alloc.h>
708 #include <nih/logging.h>
709@@ -33,22 +35,37 @@
710 #include "xdg.h"
711
712 /**
713+ * user_mode:
714+ *
715+ * If TRUE, upstart runs in user session mode.
716+ **/
717+int user_mode = FALSE;
718+
719+/**
720 * get_home_subdir:
721- *
722- * Construct path to directory in user's HOME dir.
723+ * @suffix: sub-directory name
724+ * @create: flag to create sub-directory
725+ *
726+ * Construct path to @suffix directory in user's HOME dir. If @create
727+ * flag is TRUE, also attempt to create that directory. Errors upon
728+ * directory creation are ignored.
729 *
730 * Returns: newly-allocated path, or NULL on error.
731- */
732-
733+ **/
734 char *
735-get_home_subdir (const char * suffix)
736+get_home_subdir (const char * suffix, int create)
737 {
738 char *dir;
739- nih_assert (suffix && suffix[0]);
740+ nih_assert (suffix != NULL);
741+ nih_assert (suffix[0]);
742
743 dir = getenv ("HOME");
744- if (dir && dir[0]) {
745+ if (dir && dir[0] == '/') {
746 dir = nih_sprintf (NULL, "%s/%s", dir, suffix);
747+ if (! dir)
748+ return NULL;
749+ if (create)
750+ mkdir (dir, 0700);
751 return dir;
752 }
753
754@@ -56,6 +73,39 @@
755 }
756
757 /**
758+ * xdg_get_cache_home:
759+ *
760+ * Determine an XDG compliant XDG_CACHE_HOME
761+ *
762+ * Returns: newly-allocated path, or NULL on error.
763+ **/
764+char *
765+xdg_get_cache_home (void)
766+{
767+ nih_local char **env = NULL;
768+ char *dir;
769+
770+ dir = getenv ("XDG_CACHE_HOME");
771+
772+ if (dir && dir[0] == '/') {
773+ mkdir (dir, 0700);
774+ dir = nih_strdup (NULL, dir);
775+ return dir;
776+ }
777+
778+ /* Per XDG spec, we should only create dirs, if we are
779+ * attempting to write and the dir is not there. Here we
780+ * anticipate logging to happen really soon now, hence we
781+ * pre-create the cache dir. That does not protect us from
782+ * this directory disappering while upstart is running. =/
783+ * hence this dir should be created each time we try to write
784+ * log... */
785+ dir = get_home_subdir (".cache", TRUE);
786+
787+ return dir;
788+}
789+
790+/**
791 * xdg_get_config_home:
792 *
793 * Determine an XDG compliant XDG_CONFIG_HOME
794@@ -70,12 +120,17 @@
795
796 dir = getenv ("XDG_CONFIG_HOME");
797
798- if (dir && dir[0]) {
799+ if (dir && dir[0] == '/') {
800+ mkdir (dir, 0700);
801 dir = nih_strdup (NULL, dir);
802 return dir;
803 }
804
805- dir = get_home_subdir (".config");
806+ /* Per XDG spec, we should only create dirs, if we are
807+ * attempting to write to the dir. But we only read config
808+ * dir. But we rather create it, to place inotify watch on
809+ * it. */
810+ dir = get_home_subdir (".config", TRUE);
811
812 return dir;
813 }
814@@ -134,6 +189,7 @@
815 if (path && path[0]) {
816 if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR))
817 goto error;
818+ mkdir (path, 0700);
819 if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
820 goto error;
821 nih_free (path);
822@@ -141,7 +197,7 @@
823 }
824
825 /* Legacy User's: ~/.init */
826- path = get_home_subdir (USERCONFDIR);
827+ path = get_home_subdir (USERCONFDIR, FALSE);
828 if (! path)
829 goto error;
830
831@@ -158,6 +214,8 @@
832 goto error;
833
834 for (char **p = dirs; p && *p; p++) {
835+ if (*p[0] != '/')
836+ continue;
837 if (! nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR))
838 goto error;
839 if (! nih_str_array_add (&all_dirs, NULL, NULL, *p))
840@@ -185,3 +243,26 @@
841 return NULL;
842 }
843
844+/**
845+ * get_user_log_dir:
846+ *
847+ * Constructs an XDG compliant path to a cache directory in the user's
848+ * home directory. It can be used to store logs.
849+ *
850+ * Returns: newly-allocated array of paths, or NULL or error.
851+ **/
852+char *
853+get_user_log_dir (void)
854+{
855+ nih_local char *path = NULL;
856+ char *dir = NULL;
857+ path = xdg_get_cache_home ();
858+ if (path && path[0] == '/') {
859+ dir = nih_sprintf (NULL, "%s/%s", path, INIT_XDG_SUBDIR);
860+ if (! dir)
861+ return NULL;
862+ mkdir (dir, 0700);
863+ return dir;
864+ }
865+ return NULL;
866+}
867
868=== modified file 'init/xdg.h'
869--- init/xdg.h 2012-12-18 13:58:23 +0000
870+++ init/xdg.h 2013-01-23 13:00:29 +0000
871@@ -25,18 +25,24 @@
872
873 NIH_BEGIN_EXTERN
874
875-char * get_home_subdir (const char * suffix)
876+char * get_home_subdir (const char * suffix, int create)
877 __attribute__ ((malloc, warn_unused_result));
878
879 char * xdg_get_config_home (void)
880 __attribute__ ((malloc, warn_unused_result));
881
882+char * xdg_get_cache_home (void)
883+ __attribute__ ((malloc, warn_unused_result));
884+
885 char ** xdg_get_config_dirs (void)
886 __attribute__ ((malloc, warn_unused_result));
887
888 char ** get_user_upstart_dirs (void)
889 __attribute__ ((malloc, warn_unused_result));
890
891+char * get_user_log_dir (void)
892+ __attribute__ ((malloc, warn_unused_result));
893+
894 NIH_END_EXTERN
895
896 #endif /* INIT_XDG_H */

Subscribers

People subscribed via source and target branches