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

Proposed by Dimitri John Ledkov
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 Approve
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.
Revision history for this message
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
1425. By James Hunt

* 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).

Revision history for this message
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.

Revision history for this message
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

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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.

Revision history for this message
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?

Revision history for this message
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
1426. By James Hunt

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

Revision history for this message
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.

Revision history for this message
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
Revision history for this message
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
1427. By James Hunt

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

1428. By Dimitri John Ledkov

Merge user-dirs

1429. By Dimitri John Ledkov

Normalise user_mode extern definitions

Revision history for this message
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
=== modified file 'ChangeLog'
--- ChangeLog 2013-01-21 16:24:48 +0000
+++ ChangeLog 2013-01-23 13:00:29 +0000
@@ -1,3 +1,15 @@
12013-01-21 Dmitrijs Ledkovs <xnox@ubuntu.com>
2
3 * init/xdg.[ch]: add xdg_get_cache_home and get_user_log_dir
4 functions. These retrieve XDG_CACHE_HOME and a subdir inside it
5 for upstart.
6 * init/tests/test_xdg.c: reuse test_get_config_home to test both
7 xdg_get_cache_home and xdg_get_config_home. Add test for
8 get_user_log_dir.
9 * init/main.c: use get_user_log_dir to setup logging
10 directory in user_mode. For now, command line argument is
11 honoured, while the environment override is not.
12
12013-01-21 James Hunt <james.hunt@ubuntu.com>132013-01-21 James Hunt <james.hunt@ubuntu.com>
214
3 * init/log.c:log_clear_unflushed(): Simplify asserts.15 * init/log.c:log_clear_unflushed(): Simplify asserts.
416
=== modified file 'init/Makefile.am'
--- init/Makefile.am 2012-12-19 12:46:46 +0000
+++ init/Makefile.am 2013-01-23 13:00:29 +0000
@@ -177,7 +177,7 @@
177 system.o environ.o process.o \177 system.o environ.o process.o \
178 job_class.o job_process.o job.o event.o event_operator.o blocked.o \178 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
179 parse_job.o parse_conf.o conf.o control.o \179 parse_job.o parse_conf.o conf.o control.o \
180 session.o log.o state.o \180 session.o log.o state.o xdg.o \
181 com.ubuntu.Upstart.o \181 com.ubuntu.Upstart.o \
182 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \182 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
183 $(NIH_LIBS) \183 $(NIH_LIBS) \
@@ -191,7 +191,7 @@
191 system.o environ.o process.o \191 system.o environ.o process.o \
192 job_class.o job_process.o job.o event.o event_operator.o blocked.o \192 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
193 parse_job.o parse_conf.o conf.o control.o \193 parse_job.o parse_conf.o conf.o control.o \
194 session.o log.o state.o \194 session.o log.o state.o xdg.o \
195 com.ubuntu.Upstart.o \195 com.ubuntu.Upstart.o \
196 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \196 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
197 $(NIH_LIBS) \197 $(NIH_LIBS) \
@@ -205,7 +205,7 @@
205 system.o environ.o process.o \205 system.o environ.o process.o \
206 job_class.o job_process.o job.o event.o event_operator.o blocked.o \206 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
207 parse_job.o parse_conf.o conf.o control.o \207 parse_job.o parse_conf.o conf.o control.o \
208 session.o log.o state.o \208 session.o log.o state.o xdg.o \
209 com.ubuntu.Upstart.o \209 com.ubuntu.Upstart.o \
210 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \210 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
211 $(NIH_LIBS) \211 $(NIH_LIBS) \
@@ -219,7 +219,7 @@
219 system.o environ.o process.o \219 system.o environ.o process.o \
220 job_class.o job_process.o job.o event.o event_operator.o blocked.o \220 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
221 parse_job.o parse_conf.o conf.o control.o \221 parse_job.o parse_conf.o conf.o control.o \
222 session.o log.o state.o \222 session.o log.o state.o xdg.o \
223 com.ubuntu.Upstart.o \223 com.ubuntu.Upstart.o \
224 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \224 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
225 $(NIH_LIBS) \225 $(NIH_LIBS) \
@@ -233,7 +233,7 @@
233 system.o environ.o process.o \233 system.o environ.o process.o \
234 job_class.o job_process.o job.o event.o event_operator.o blocked.o \234 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
235 parse_job.o parse_conf.o conf.o control.o \235 parse_job.o parse_conf.o conf.o control.o \
236 session.o log.o state.o \236 session.o log.o state.o xdg.o \
237 com.ubuntu.Upstart.o \237 com.ubuntu.Upstart.o \
238 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \238 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
239 $(NIH_LIBS) \239 $(NIH_LIBS) \
@@ -247,7 +247,7 @@
247 system.o environ.o process.o \247 system.o environ.o process.o \
248 job_class.o job_process.o job.o event.o event_operator.o blocked.o \248 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
249 parse_job.o parse_conf.o conf.o control.o \249 parse_job.o parse_conf.o conf.o control.o \
250 session.o log.o state.o \250 session.o log.o state.o xdg.o \
251 com.ubuntu.Upstart.o \251 com.ubuntu.Upstart.o \
252 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \252 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
253 $(NIH_LIBS) \253 $(NIH_LIBS) \
@@ -261,7 +261,7 @@
261 system.o environ.o process.o \261 system.o environ.o process.o \
262 job_class.o job_process.o job.o event.o event_operator.o blocked.o \262 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
263 parse_job.o parse_conf.o conf.o control.o \263 parse_job.o parse_conf.o conf.o control.o \
264 session.o log.o state.o \264 session.o log.o state.o xdg.o \
265 com.ubuntu.Upstart.o \265 com.ubuntu.Upstart.o \
266 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \266 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
267 $(NIH_LIBS) \267 $(NIH_LIBS) \
@@ -275,7 +275,7 @@
275 system.o environ.o process.o \275 system.o environ.o process.o \
276 job_class.o job_process.o job.o event.o event_operator.o blocked.o \276 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
277 parse_job.o parse_conf.o conf.o control.o \277 parse_job.o parse_conf.o conf.o control.o \
278 session.o log.o state.o \278 session.o log.o state.o xdg.o \
279 com.ubuntu.Upstart.o \279 com.ubuntu.Upstart.o \
280 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \280 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
281 $(NIH_LIBS) \281 $(NIH_LIBS) \
@@ -289,7 +289,7 @@
289 system.o environ.o process.o \289 system.o environ.o process.o \
290 job_class.o job_process.o job.o event.o event_operator.o blocked.o \290 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
291 parse_job.o parse_conf.o conf.o control.o \291 parse_job.o parse_conf.o conf.o control.o \
292 session.o log.o state.o \292 session.o log.o state.o xdg.o \
293 com.ubuntu.Upstart.o \293 com.ubuntu.Upstart.o \
294 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \294 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
295 $(NIH_LIBS) \295 $(NIH_LIBS) \
@@ -303,7 +303,7 @@
303 system.o environ.o process.o \303 system.o environ.o process.o \
304 job_class.o job_process.o job.o event.o event_operator.o blocked.o \304 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
305 parse_job.o parse_conf.o conf.o control.o \305 parse_job.o parse_conf.o conf.o control.o \
306 session.o log.o state.o \306 session.o log.o state.o xdg.o \
307 com.ubuntu.Upstart.o \307 com.ubuntu.Upstart.o \
308 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \308 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
309 $(NIH_LIBS) \309 $(NIH_LIBS) \
@@ -317,7 +317,7 @@
317 system.o environ.o process.o \317 system.o environ.o process.o \
318 job_class.o job_process.o job.o event.o event_operator.o blocked.o \318 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
319 parse_job.o parse_conf.o conf.o control.o \319 parse_job.o parse_conf.o conf.o control.o \
320 session.o log.o state.o \320 session.o log.o state.o xdg.o \
321 com.ubuntu.Upstart.o \321 com.ubuntu.Upstart.o \
322 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \322 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
323 $(NIH_LIBS) \323 $(NIH_LIBS) \
@@ -331,7 +331,7 @@
331 system.o environ.o process.o \331 system.o environ.o process.o \
332 job_class.o job_process.o job.o event.o event_operator.o blocked.o \332 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
333 parse_job.o parse_conf.o conf.o control.o \333 parse_job.o parse_conf.o conf.o control.o \
334 session.o log.o state.o \334 session.o log.o state.o xdg.o \
335 com.ubuntu.Upstart.o \335 com.ubuntu.Upstart.o \
336 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \336 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
337 $(NIH_LIBS) \337 $(NIH_LIBS) \
@@ -345,7 +345,7 @@
345 system.o environ.o process.o \345 system.o environ.o process.o \
346 job_class.o job_process.o job.o event.o event_operator.o blocked.o \346 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
347 parse_job.o parse_conf.o control.o \347 parse_job.o parse_conf.o control.o \
348 session.o log.o state.o \348 session.o log.o state.o xdg.o \
349 com.ubuntu.Upstart.o \349 com.ubuntu.Upstart.o \
350 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \350 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
351 $(NIH_LIBS) \351 $(NIH_LIBS) \
@@ -366,7 +366,7 @@
366 system.o environ.o process.o \366 system.o environ.o process.o \
367 job_class.o job_process.o job.o event.o event_operator.o blocked.o \367 job_class.o job_process.o job.o event.o event_operator.o blocked.o \
368 parse_job.o parse_conf.o conf.o control.o \368 parse_job.o parse_conf.o conf.o control.o \
369 session.o log.o state.o \369 session.o log.o state.o xdg.o \
370 com.ubuntu.Upstart.o \370 com.ubuntu.Upstart.o \
371 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \371 com.ubuntu.Upstart.Job.o com.ubuntu.Upstart.Instance.o \
372 $(NIH_LIBS) \372 $(NIH_LIBS) \
373373
=== modified file 'init/control.c'
--- init/control.c 2013-01-22 15:51:01 +0000
+++ init/control.c 2013-01-23 13:00:29 +0000
@@ -76,13 +76,6 @@
76int use_session_bus = FALSE;76int use_session_bus = FALSE;
7777
78/**78/**
79 * user_mode:
80 *
81 * If TRUE, upstart runs in user session mode.
82 **/
83int user_mode = FALSE;
84
85/**
86 * control_server_address:79 * control_server_address:
87 *80 *
88 * Address on which the control server may be reached.81 * Address on which the control server may be reached.
@@ -112,6 +105,8 @@
112 **/105 **/
113NihList *control_conns = NULL;106NihList *control_conns = NULL;
114107
108/* External definitions */
109extern int user_mode;
115110
116/**111/**
117 * control_init:112 * control_init:
118113
=== modified file 'init/job_process.c'
--- init/job_process.c 2013-01-21 22:44:27 +0000
+++ init/job_process.c 2013-01-23 13:00:29 +0000
@@ -66,6 +66,7 @@
66#include "job.h"66#include "job.h"
67#include "errors.h"67#include "errors.h"
68#include "control.h"68#include "control.h"
69#include "xdg.h"
6970
7071
71/**72/**
@@ -2197,7 +2198,7 @@
2197 nih_assert (class->name);2198 nih_assert (class->name);
21982199
2199 /* Override, primarily for tests */2200 /* Override, primarily for tests */
2200 if (getenv (LOGDIR_ENV)) {2201 if (getenv (LOGDIR_ENV) && ! user_mode) {
2201 dir = nih_strdup (NULL, getenv (LOGDIR_ENV));2202 dir = nih_strdup (NULL, getenv (LOGDIR_ENV));
2202 nih_debug ("Using alternative directory '%s' for logs", dir);2203 nih_debug ("Using alternative directory '%s' for logs", dir);
2203 } else {2204 } else {
22042205
=== modified file 'init/main.c'
--- init/main.c 2013-01-22 15:53:05 +0000
+++ init/main.c 2013-01-23 13:00:29 +0000
@@ -949,6 +949,11 @@
949 if (log_dir)949 if (log_dir)
950 goto out;950 goto out;
951951
952 if (user_mode) {
953 log_dir = get_user_log_dir ();
954 return;
955 }
956
952 log_dir = JOB_LOGDIR;957 log_dir = JOB_LOGDIR;
953958
954 dir = getenv (LOGDIR_ENV);959 dir = getenv (LOGDIR_ENV);
955960
=== modified file 'init/man/init.5'
--- init/man/init.5 2013-01-16 19:20:54 +0000
+++ init/man/init.5 2013-01-23 13:00:29 +0000
@@ -149,11 +149,8 @@
149of that job name: any subsequently searched directory that contains a149of that job name: any subsequently searched directory that contains a
150job of the same name will be ignored. The same applies for override150job of the same name will be ignored. The same applies for override
151files: only the first override file found in the search order will be151files: only the first override file found in the search order will be
152applied. Note that an override file does not have to be in the same152applied. Note that an override file can be in the same directory or
153directory as the job it overrides, but if not in the directory of the153earlier to that directory which contains the job file.
154job it overrides, it must be in an
155.I earlier
156directory to that which contains the job.
157154
158Jobs in these locations are expected to launch the user's session.155Jobs in these locations are expected to launch the user's session.
159Upstart will try to parent all spawned process with the aid of156Upstart will try to parent all spawned process with the aid of
@@ -166,6 +163,12 @@
166When running in User Session mode, Upstart will kill all job processes163When running in User Session mode, Upstart will kill all job processes
167on session logout or shutdown.164on session logout or shutdown.
168165
166All log output will be in
167.I $XDG_CACHE_HOME/upstart
168which defaults to
169.I $HOME/.cache/upstart
170.
171
169.\"172.\"
170.SS Configuration File Format173.SS Configuration File Format
171Each line begins with a configuration stanza and continues until either174Each line begins with a configuration stanza and continues until either
@@ -664,19 +667,23 @@
664.B log667.B log
665.RS668.RS
666.B669.B
667Only applies to system jobs:670Only applies to system and user session jobs:
668if specified by user jobs, the job will be considered to have specified671if specified by user jobs, the job will be considered to have specified
669the value672the value
670.BR none "."673.BR none "."
671674
672For system jobs, if \fBlog\fR is specified, standard input is connected675For system and user session jobs jobs, if \fBlog\fR is specified, standard input is connected
673to676to
674.IR /dev/null ","677.IR /dev/null ","
675and standard output and standard error are connected to a pseudo-tty678and standard output and standard error are connected to a pseudo-tty
676which logs all job output.679which logs all job output.
677680
678Output is logged to file681Output is logged to file
679.IR /var/log/upstart/<job-log-file> "."682.IR /var/log/upstart/<job-log-file>
683or
684.IR $XDG_CACHE_HOME/upstart/<job-log-file>
685for system and user session jobs respectively.
686
680If a job has specified \fBinstance\fR,687If a job has specified \fBinstance\fR,
681.I <job-log-file>688.I <job-log-file>
682will equate to689will equate to
@@ -1019,18 +1026,30 @@
1019.TP1026.TP
1020.I $HOME/.init/*.conf1027.I $HOME/.init/*.conf
1021User job configuration files.1028User job configuration files.
1022Note that you may make the directory
1023.I $HOME/.init/
1024a symbolic link to
1025.BR $HOME/.config/upstart/ "."
1026.1029.
1027.TP1030.TP
1028.I $HOME/.init/*.override1031.I $HOME/.init/*.override
1029User job override files.1032User job override files.
1030.1033.
1031.TP1034.TP
1035.I $XDG_CONFIG_HOME/upstart/*.conf
1036User session job configuration files. See
1037.B User Session Mode
1038for other locations.
1039.
1040.TP
1041.I $XDG_CONFIG_HOME/upstart/*.override
1042User session job override files. See
1043.B User Session Mode
1044for other locations.
1045.
1046.TP
1032.I /var/log/upstart/*.log1047.I /var/log/upstart/*.log
1033Default location of system job output logs.1048Default location of system job output logs.
1049.
1050.TP
1051.I $XDG_CACHE_HOME/upstart/*.log
1052Default location of user session job output logs.
1034.RE1053.RE
1035.\"1054.\"
1036.SH AUTHOR1055.SH AUTHOR
10371056
=== modified file 'init/man/init.8'
--- init/man/init.8 2012-12-18 17:40:49 +0000
+++ init/man/init.8 2013-01-23 13:00:29 +0000
@@ -67,6 +67,8 @@
67.B \-\-confdir \fIdirectory\fP67.B \-\-confdir \fIdirectory\fP
68Read job configuration files from a directory other than68Read job configuration files from a directory other than
69\fI/etc/init\fP.69\fI/etc/init\fP.
70For user session mode, read job configuration files from this
71directory at highest priority.
70.\"72.\"
71.TP73.TP
72.B \-\-default-console \fIvalue\fP74.B \-\-default-console \fIvalue\fP
@@ -81,7 +83,8 @@
81.TP83.TP
82.B \-\-logdir \fIdirectory\fP84.B \-\-logdir \fIdirectory\fP
83Write job output log files to a directory other than85Write job output log files to a directory other than
84\fI/var/log/upstart\fP.86\fI/var/log/upstart\fP (system mode) or \fI$XDG_CACHE_HOME/upstart\fP
87(user session mode).
85.\"88.\"
86.TP89.TP
87.B \-\-no\-log90.B \-\-no\-log
8891
=== modified file 'init/tests/test_xdg.c'
--- init/tests/test_xdg.c 2012-12-18 14:16:10 +0000
+++ init/tests/test_xdg.c 2013-01-23 13:00:29 +0000
@@ -22,12 +22,26 @@
22#include <nih/string.h>22#include <nih/string.h>
23#include <nih/test.h>23#include <nih/test.h>
2424
25#include <limits.h>
25#include <stdlib.h>26#include <stdlib.h>
26#include <limits.h>27#include <sys/types.h>
28#include <sys/stat.h>
29#include <unistd.h>
2730
28#include "xdg.h"31#include "xdg.h"
2932
30void33void
34_test_dir_created (char * dirname) {
35 struct stat statbuf;
36
37 TEST_EQ (lstat (dirname, &statbuf), 0);
38 TEST_TRUE (S_ISDIR (statbuf.st_mode));
39
40 /* Check that the created directory has 0700 permissions, as per XDG spec */
41 TEST_EQ (0700, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO));
42}
43
44void
31test_get_home_subdir (void)45test_get_home_subdir (void)
32{46{
33 char dirname[PATH_MAX];47 char dirname[PATH_MAX];
@@ -40,7 +54,7 @@
40 TEST_EQ (unsetenv ("HOME"), 0);54 TEST_EQ (unsetenv ("HOME"), 0);
4155
42 TEST_ALLOC_FAIL {56 TEST_ALLOC_FAIL {
43 dir = get_home_subdir ("test");57 dir = get_home_subdir ("test", FALSE);
44 TEST_EQ_P (dir, NULL);58 TEST_EQ_P (dir, NULL);
45 }59 }
4660
@@ -54,7 +68,7 @@
54 expected = NIH_MUST (nih_sprintf (NULL, "%s/test", dirname));68 expected = NIH_MUST (nih_sprintf (NULL, "%s/test", dirname));
55 }69 }
5670
57 dir = get_home_subdir ("test");71 dir = get_home_subdir ("test", FALSE);
5872
59 if (test_alloc_failed) {73 if (test_alloc_failed) {
60 TEST_EQ_P (dir, NULL);74 TEST_EQ_P (dir, NULL);
@@ -69,28 +83,29 @@
69}83}
7084
71void85void
72test_get_config_home (void)86_test_get_home (char * env_var_name, char * dir_name, char * (*function)(void))
73{87{
74 char dirname[PATH_MAX];88 char dirname[PATH_MAX];
89 char onemore[PATH_MAX];
75 char * outname;90 char * outname;
76 char * expected;91 char * expected;
7792
78 TEST_FUNCTION ("xdg_get_config_home");
79
80 TEST_FEATURE ("with HOME set and without environment override");93 TEST_FEATURE ("with HOME set and without environment override");
81 TEST_FILENAME (dirname);94 TEST_FILENAME (dirname);
82 TEST_EQ (setenv ("HOME", dirname, 1), 0);95 TEST_EQ (setenv ("HOME", dirname, 1), 0);
83 TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);96 TEST_EQ (mkdir (dirname, 0755), 0);
97 TEST_EQ (unsetenv (env_var_name), 0);
84 TEST_ALLOC_FAIL {98 TEST_ALLOC_FAIL {
85 TEST_ALLOC_SAFE {99 TEST_ALLOC_SAFE {
86 expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));100 expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
87 }101 }
88102
89 outname = NULL;103 outname = NULL;
90 outname = xdg_get_config_home ();104 outname = function ();
91105
92 if (! test_alloc_failed) {106 if (! test_alloc_failed) {
93 TEST_EQ_STR (outname, expected);107 TEST_EQ_STR (outname, expected);
108 _test_dir_created (expected);
94 } else {109 } else {
95 TEST_EQ_P (outname, NULL);110 TEST_EQ_P (outname, NULL);
96 }111 }
@@ -98,83 +113,131 @@
98 if (outname)113 if (outname)
99 nih_free (outname);114 nih_free (outname);
100115
101 nih_free(expected);116 rmdir (expected);
117 nih_free (expected);
102 }118 }
103119
104 TEST_FEATURE ("with HOME set and with empty environment override");120 TEST_FEATURE ("with HOME set and with empty environment override");
105 TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);121 TEST_EQ (setenv (env_var_name, "", 1), 0);
106122
107123
108 TEST_ALLOC_FAIL {124 TEST_ALLOC_FAIL {
109 TEST_ALLOC_SAFE {125 TEST_ALLOC_SAFE {
110 expected = NIH_MUST (nih_sprintf (NULL, "%s/.config", dirname));126 expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
111 }127 }
112 outname = NULL;128 outname = NULL;
113 outname = xdg_get_config_home();129 outname = function ();
114130
115 if (test_alloc_failed) {131 if (test_alloc_failed) {
116 TEST_EQ_P (outname, NULL);132 TEST_EQ_P (outname, NULL);
117 } else {133 } else {
118 TEST_EQ_STR (outname, expected);134 TEST_EQ_STR (outname, expected);
119 }135 _test_dir_created (expected);
120 if (outname)136 }
121 nih_free (outname);137 if (outname)
122 nih_free(expected);138 nih_free (outname);
139 rmdir (expected);
140 nih_free (expected);
141 }
142
143 TEST_FEATURE ("with HOME set and with relative environment override");
144 TEST_EQ (setenv (env_var_name, "../", 1), 0);
145
146
147 TEST_ALLOC_FAIL {
148 TEST_ALLOC_SAFE {
149 expected = NIH_MUST (nih_sprintf (NULL, "%s/%s", dirname, dir_name));
150 }
151 outname = NULL;
152 outname = function ();
153
154 if (test_alloc_failed) {
155 TEST_EQ_P (outname, NULL);
156 } else {
157 TEST_EQ_STR (outname, expected);
158 _test_dir_created (expected);
159 }
160 if (outname)
161 nih_free (outname);
162 rmdir (expected);
163 nih_free (expected);
123 }164 }
124165
125 TEST_FEATURE ("with HOME set and with environment override");166 TEST_FEATURE ("with HOME set and with environment override");
126 expected = NIH_MUST (nih_strdup (NULL, "/home/me/.config-test"));167 TEST_FILENAME (onemore);
127 TEST_EQ (setenv ("XDG_CONFIG_HOME", expected, 1), 0);168 expected = NIH_MUST (nih_sprintf (NULL, "%s", onemore));
169 TEST_EQ (setenv (env_var_name, expected, 1), 0);
128170
129 TEST_ALLOC_FAIL {171 TEST_ALLOC_FAIL {
130 outname = NULL;172 outname = NULL;
131 outname = xdg_get_config_home();173 outname = function ();
132174
133 if (test_alloc_failed) {175 if (test_alloc_failed) {
134 TEST_EQ_P (outname, NULL);176 TEST_EQ_P (outname, NULL);
135 } else {177 } else {
136 TEST_EQ_STR (outname, expected);178 TEST_EQ_STR (outname, expected);
179 _test_dir_created (expected);
137 }180 }
138 if (outname)181 if (outname)
139 nih_free (outname);182 nih_free (outname);
183 rmdir (expected);
140 }184 }
141185
186 TEST_EQ (rmdir (dirname), 0);
187
142 TEST_FEATURE ("without HOME set and with environment override");188 TEST_FEATURE ("without HOME set and with environment override");
143 TEST_EQ (unsetenv ("HOME"), 0);189 TEST_EQ (unsetenv ("HOME"), 0);
144190
145 TEST_ALLOC_FAIL {191 TEST_ALLOC_FAIL {
146 outname = NULL;192 outname = NULL;
147 outname = xdg_get_config_home();193 outname = function ();
148194
149 if (test_alloc_failed) {195 if (test_alloc_failed) {
150 TEST_EQ_P (outname, NULL);196 TEST_EQ_P (outname, NULL);
151 } else {197 } else {
152 TEST_EQ_STR (outname, expected);198 TEST_EQ_STR (outname, expected);
199 _test_dir_created (expected);
153 }200 }
154 if (outname)201 if (outname)
155 nih_free (outname);202 nih_free (outname);
203 rmdir (expected);
156 }204 }
157 nih_free(expected);205 nih_free(expected);
158206
159 TEST_FEATURE ("without HOME set and with empty environment override");207 TEST_FEATURE ("without HOME set and with empty environment override");
160 TEST_EQ (setenv ("XDG_CONFIG_HOME", "", 1), 0);208 TEST_EQ (setenv (env_var_name, "", 1), 0);
161209
162 TEST_ALLOC_FAIL {210 TEST_ALLOC_FAIL {
163 outname = NULL;211 outname = NULL;
164 outname = xdg_get_config_home();212 outname = function ();
165 TEST_EQ_P (outname, NULL);213 TEST_EQ_P (outname, NULL);
166 }214 }
167215
168 TEST_FEATURE ("without HOME set and without environment override");216 TEST_FEATURE ("without HOME set and without environment override");
169 TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);217 TEST_EQ (unsetenv (env_var_name), 0);
170 TEST_ALLOC_FAIL {218 TEST_ALLOC_FAIL {
171 outname = NULL;219 outname = NULL;
172 outname = xdg_get_config_home();220 outname = function ();
173 TEST_EQ_P (outname, NULL);221 TEST_EQ_P (outname, NULL);
174 }222 }
175}223}
176224
177void225void
226test_get_config_home (void)
227{
228 TEST_FUNCTION ("xdg_get_config_home");
229 _test_get_home ("XDG_CONFIG_HOME", ".config", &xdg_get_config_home);
230
231}
232
233void
234test_get_cache_home (void)
235{
236 TEST_FUNCTION ("xdg_get_cache_home");
237 _test_get_home ("XDG_CACHE_HOME", ".cache", &xdg_get_cache_home);
238}
239
240void
178test_get_config_dirs (void)241test_get_config_dirs (void)
179{242{
180 char **dirs = NULL;243 char **dirs = NULL;
@@ -260,12 +323,12 @@
260 TEST_FEATURE ("with HOME set");323 TEST_FEATURE ("with HOME set");
261 TEST_FILENAME (dirname);324 TEST_FILENAME (dirname);
262 TEST_EQ (setenv ("HOME", dirname, 1), 0);325 TEST_EQ (setenv ("HOME", dirname, 1), 0);
326 TEST_EQ (mkdir (dirname, 0755), 0);
263 TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);327 TEST_EQ (unsetenv ("XDG_CONFIG_HOME"), 0);
264 TEST_EQ (unsetenv ("XDG_CONFIG_DIRS"), 0);328 TEST_EQ (unsetenv ("XDG_CONFIG_DIRS"), 0);
265329
266 TEST_ALLOC_FAIL {330 TEST_ALLOC_FAIL {
267 TEST_ALLOC_SAFE {331 TEST_ALLOC_SAFE {
268 dirs = NULL;
269 expected = nih_str_array_new (NULL);332 expected = nih_str_array_new (NULL);
270 path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));333 path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));
271 assert (nih_str_array_add (&expected, NULL, NULL, path));334 assert (nih_str_array_add (&expected, NULL, NULL, path));
@@ -282,15 +345,94 @@
282 TEST_EQ_P (dirs, NULL);345 TEST_EQ_P (dirs, NULL);
283 } else {346 } else {
284 TEST_EQ_STR (dirs[0], expected[0]);347 TEST_EQ_STR (dirs[0], expected[0]);
348 //_test_dir_created (expected[0]);
285 TEST_EQ_STR (dirs[1], expected[1]);349 TEST_EQ_STR (dirs[1], expected[1]);
286 TEST_EQ_STR (dirs[2], "/etc/xdg/upstart");350 TEST_EQ_STR (dirs[2], "/etc/xdg/upstart");
287 TEST_EQ_STR (dirs[3], SYSTEM_USERCONFDIR);351 TEST_EQ_STR (dirs[3], SYSTEM_USERCONFDIR);
288 TEST_EQ (dirs[4], NULL);352 TEST_EQ (dirs[4], NULL);
289 nih_free (dirs);353 nih_free (dirs);
290 }354 }
291 nih_free(expected);355 TEST_ALLOC_SAFE {
292 }356 rmdir (expected[0]);
293357 path = nih_sprintf (NULL, "%s/.config", dirname);
358 rmdir (path);
359 nih_free (path);
360 nih_free (expected);
361 }
362 }
363
364 TEST_FEATURE ("with some invalid XDG_CONFIG_DIRS");
365 TEST_EQ (setenv ("XDG_CONFIG_DIRS", "/etc/xdg/xdg-subdir:../haha:/etc/xdg", 1), 0);
366
367 TEST_ALLOC_FAIL {
368 TEST_ALLOC_SAFE {
369 expected = nih_str_array_new (NULL);
370 path = NIH_MUST (nih_sprintf (NULL, "%s/.config/upstart", dirname));
371 assert (nih_str_array_add (&expected, NULL, NULL, path));
372 nih_free(path);
373 path = NIH_MUST (nih_sprintf (NULL, "%s/.init", dirname));
374 assert (nih_str_array_add (&expected, NULL, NULL, path));
375 nih_free(path);
376 }
377
378 dirs = NULL;
379 dirs = get_user_upstart_dirs ();
380
381 if (test_alloc_failed) {
382 TEST_EQ_P (dirs, NULL);
383 } else {
384 TEST_EQ_STR (dirs[0], expected[0]);
385 _test_dir_created (expected[0]);
386 TEST_EQ_STR (dirs[1], expected[1]);
387 TEST_EQ_STR (dirs[2], "/etc/xdg/xdg-subdir/upstart");
388 TEST_EQ_STR (dirs[3], "/etc/xdg/upstart");
389 TEST_EQ_STR (dirs[4], SYSTEM_USERCONFDIR);
390 TEST_EQ (dirs[5], NULL);
391 nih_free (dirs);
392 }
393 TEST_ALLOC_SAFE {
394 rmdir (expected[0]);
395 path = nih_sprintf (NULL, "%s/.config", dirname);
396 rmdir (path);
397 nih_free (path);
398 nih_free (expected);
399 }
400 }
401 TEST_EQ (rmdir (dirname), 0);
402}
403
404void
405test_get_user_log_dir (void)
406{
407 char dirname[PATH_MAX];
408 char *expected;
409 char *path;
410
411 TEST_FUNCTION ("get_user_log_dir");
412 TEST_FEATURE ("with HOME set");
413 TEST_FILENAME (dirname);
414 TEST_EQ (setenv ("HOME", dirname, 1), 0);
415 TEST_EQ (mkdir (dirname, 0755), 0);
416 TEST_EQ (unsetenv ("XDG_CACHE_HOME"), 0);
417
418 expected = nih_sprintf (NULL, "%s/.cache/upstart", dirname);
419
420 TEST_ALLOC_FAIL {
421 path = get_user_log_dir ();
422 if (test_alloc_failed) {
423 TEST_EQ_P (path, NULL);
424 } else {
425 TEST_EQ_STR (path, expected);
426 _test_dir_created (expected);
427 nih_free (path);
428 }
429 }
430 rmdir (expected);
431 nih_free (expected);
432 path = nih_sprintf (NULL, "%s/.cache", dirname);
433 rmdir (path);
434 nih_free (path);
435 rmdir (dirname);
294}436}
295437
296int438int
@@ -301,6 +443,8 @@
301 test_get_config_home ();443 test_get_config_home ();
302 test_get_config_dirs ();444 test_get_config_dirs ();
303 test_get_user_upstart_dirs ();445 test_get_user_upstart_dirs ();
446 test_get_cache_home ();
447 test_get_user_log_dir ();
304448
305 return 0;449 return 0;
306}450}
307451
=== modified file 'init/xdg.c'
--- init/xdg.c 2012-12-18 16:31:55 +0000
+++ init/xdg.c 2013-01-23 13:00:29 +0000
@@ -24,6 +24,8 @@
24#endif /* HAVE_CONFIG_H */24#endif /* HAVE_CONFIG_H */
2525
26#include <stdlib.h>26#include <stdlib.h>
27#include <sys/stat.h>
28#include <sys/types.h>
2729
28#include <nih/alloc.h>30#include <nih/alloc.h>
29#include <nih/logging.h>31#include <nih/logging.h>
@@ -33,22 +35,37 @@
33#include "xdg.h"35#include "xdg.h"
3436
35/**37/**
38 * user_mode:
39 *
40 * If TRUE, upstart runs in user session mode.
41 **/
42int user_mode = FALSE;
43
44/**
36 * get_home_subdir:45 * get_home_subdir:
37 *46 * @suffix: sub-directory name
38 * Construct path to directory in user's HOME dir.47 * @create: flag to create sub-directory
48 *
49 * Construct path to @suffix directory in user's HOME dir. If @create
50 * flag is TRUE, also attempt to create that directory. Errors upon
51 * directory creation are ignored.
39 * 52 *
40 * Returns: newly-allocated path, or NULL on error.53 * Returns: newly-allocated path, or NULL on error.
41 */54 **/
42
43char *55char *
44get_home_subdir (const char * suffix)56get_home_subdir (const char * suffix, int create)
45{57{
46 char *dir;58 char *dir;
47 nih_assert (suffix && suffix[0]);59 nih_assert (suffix != NULL);
60 nih_assert (suffix[0]);
48 61
49 dir = getenv ("HOME");62 dir = getenv ("HOME");
50 if (dir && dir[0]) {63 if (dir && dir[0] == '/') {
51 dir = nih_sprintf (NULL, "%s/%s", dir, suffix);64 dir = nih_sprintf (NULL, "%s/%s", dir, suffix);
65 if (! dir)
66 return NULL;
67 if (create)
68 mkdir (dir, 0700);
52 return dir;69 return dir;
53 }70 }
5471
@@ -56,6 +73,39 @@
56}73}
5774
58/**75/**
76 * xdg_get_cache_home:
77 *
78 * Determine an XDG compliant XDG_CACHE_HOME
79 *
80 * Returns: newly-allocated path, or NULL on error.
81 **/
82char *
83xdg_get_cache_home (void)
84{
85 nih_local char **env = NULL;
86 char *dir;
87
88 dir = getenv ("XDG_CACHE_HOME");
89
90 if (dir && dir[0] == '/') {
91 mkdir (dir, 0700);
92 dir = nih_strdup (NULL, dir);
93 return dir;
94 }
95
96 /* Per XDG spec, we should only create dirs, if we are
97 * attempting to write and the dir is not there. Here we
98 * anticipate logging to happen really soon now, hence we
99 * pre-create the cache dir. That does not protect us from
100 * this directory disappering while upstart is running. =/
101 * hence this dir should be created each time we try to write
102 * log... */
103 dir = get_home_subdir (".cache", TRUE);
104
105 return dir;
106}
107
108/**
59 * xdg_get_config_home:109 * xdg_get_config_home:
60 *110 *
61 * Determine an XDG compliant XDG_CONFIG_HOME111 * Determine an XDG compliant XDG_CONFIG_HOME
@@ -70,12 +120,17 @@
70120
71 dir = getenv ("XDG_CONFIG_HOME");121 dir = getenv ("XDG_CONFIG_HOME");
72 122
73 if (dir && dir[0]) {123 if (dir && dir[0] == '/') {
124 mkdir (dir, 0700);
74 dir = nih_strdup (NULL, dir);125 dir = nih_strdup (NULL, dir);
75 return dir;126 return dir;
76 }127 }
77128
78 dir = get_home_subdir (".config");129 /* Per XDG spec, we should only create dirs, if we are
130 * attempting to write to the dir. But we only read config
131 * dir. But we rather create it, to place inotify watch on
132 * it. */
133 dir = get_home_subdir (".config", TRUE);
79134
80 return dir;135 return dir;
81}136}
@@ -134,6 +189,7 @@
134 if (path && path[0]) {189 if (path && path[0]) {
135 if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR))190 if (! nih_strcat_sprintf (&path, NULL, "/%s", INIT_XDG_SUBDIR))
136 goto error;191 goto error;
192 mkdir (path, 0700);
137 if (! nih_str_array_add (&all_dirs, NULL, NULL, path))193 if (! nih_str_array_add (&all_dirs, NULL, NULL, path))
138 goto error;194 goto error;
139 nih_free (path);195 nih_free (path);
@@ -141,7 +197,7 @@
141 }197 }
142198
143 /* Legacy User's: ~/.init */199 /* Legacy User's: ~/.init */
144 path = get_home_subdir (USERCONFDIR);200 path = get_home_subdir (USERCONFDIR, FALSE);
145 if (! path)201 if (! path)
146 goto error;202 goto error;
147203
@@ -158,6 +214,8 @@
158 goto error;214 goto error;
159215
160 for (char **p = dirs; p && *p; p++) {216 for (char **p = dirs; p && *p; p++) {
217 if (*p[0] != '/')
218 continue;
161 if (! nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR))219 if (! nih_strcat_sprintf (p, NULL, "/%s", INIT_XDG_SUBDIR))
162 goto error;220 goto error;
163 if (! nih_str_array_add (&all_dirs, NULL, NULL, *p))221 if (! nih_str_array_add (&all_dirs, NULL, NULL, *p))
@@ -185,3 +243,26 @@
185 return NULL;243 return NULL;
186}244}
187245
246/**
247 * get_user_log_dir:
248 *
249 * Constructs an XDG compliant path to a cache directory in the user's
250 * home directory. It can be used to store logs.
251 *
252 * Returns: newly-allocated array of paths, or NULL or error.
253 **/
254char *
255get_user_log_dir (void)
256{
257 nih_local char *path = NULL;
258 char *dir = NULL;
259 path = xdg_get_cache_home ();
260 if (path && path[0] == '/') {
261 dir = nih_sprintf (NULL, "%s/%s", path, INIT_XDG_SUBDIR);
262 if (! dir)
263 return NULL;
264 mkdir (dir, 0700);
265 return dir;
266 }
267 return NULL;
268}
188269
=== modified file 'init/xdg.h'
--- init/xdg.h 2012-12-18 13:58:23 +0000
+++ init/xdg.h 2013-01-23 13:00:29 +0000
@@ -25,18 +25,24 @@
2525
26NIH_BEGIN_EXTERN26NIH_BEGIN_EXTERN
2727
28char * get_home_subdir (const char * suffix)28char * get_home_subdir (const char * suffix, int create)
29 __attribute__ ((malloc, warn_unused_result));29 __attribute__ ((malloc, warn_unused_result));
3030
31char * xdg_get_config_home (void)31char * xdg_get_config_home (void)
32 __attribute__ ((malloc, warn_unused_result));32 __attribute__ ((malloc, warn_unused_result));
3333
34char * xdg_get_cache_home (void)
35 __attribute__ ((malloc, warn_unused_result));
36
34char ** xdg_get_config_dirs (void)37char ** xdg_get_config_dirs (void)
35 __attribute__ ((malloc, warn_unused_result));38 __attribute__ ((malloc, warn_unused_result));
3639
37char ** get_user_upstart_dirs (void)40char ** get_user_upstart_dirs (void)
38 __attribute__ ((malloc, warn_unused_result));41 __attribute__ ((malloc, warn_unused_result));
3942
43char * get_user_log_dir (void)
44 __attribute__ ((malloc, warn_unused_result));
45
40NIH_END_EXTERN46NIH_END_EXTERN
4147
42#endif /* INIT_XDG_H */48#endif /* INIT_XDG_H */

Subscribers

People subscribed via source and target branches