Merge branch 'debian'
[hcoop/debian/exim4.git] / src / directory.c
... / ...
CommitLineData
1/*************************************************
2* Exim - an Internet mail transport agent *
3*************************************************/
4
5/* Copyright (c) University of Cambridge 1995 - 2009 */
6/* Copyright (c) The Exim Maintainers 2010 - 2018 */
7/* See the file NOTICE for conditions of use and distribution. */
8
9#include "exim.h"
10
11
12/*************************************************
13* Attempt to create a directory *
14*************************************************/
15
16/* All the directories that Exim ever creates for itself are within the spool
17directory as defined by spool_directory. We are prepared to create as many as
18necessary from that directory downwards, inclusive. However, directory creation
19can also be required in appendfile and sieve filters. The making function
20therefore has a parent argument, below which the new directories are to go. It
21can be NULL if the name is absolute.
22
23If a non-root uid has been specified for exim, and we are currently running as
24root, ensure the directory is owned by the non-root id if the parent is the
25spool directory.
26
27Arguments:
28 parent parent directory name; if NULL the name must be absolute
29 name directory name within the parent that we want
30 mode mode for the new directory
31 panic if TRUE, panic on failure
32
33Returns: panic on failure if panic is set; otherwise return FALSE;
34 TRUE on success.
35*/
36
37BOOL
38directory_make(const uschar *parent, const uschar *name,
39 int mode, BOOL panic)
40{
41BOOL use_chown = parent == spool_directory && geteuid() == root_uid;
42uschar * p;
43uschar c = 1;
44struct stat statbuf;
45uschar * path;
46
47if (parent)
48 {
49 path = string_sprintf("%s%s%s", parent, US"/", name);
50 p = path + Ustrlen(parent);
51 }
52else
53 {
54 path = string_copy(name);
55 p = path + 1;
56 }
57
58/* Walk the path creating any missing directories */
59
60while (c && *p)
61 {
62 while (*p && *p != '/') p++;
63 c = *p;
64 *p = '\0';
65 if (Ustat(path, &statbuf) != 0)
66 {
67 if (mkdir(CS path, mode) < 0 && errno != EEXIST)
68 { p = US"create"; goto bad; }
69
70 /* Set the ownership if necessary. */
71
72 if (use_chown && Uchown(path, exim_uid, exim_gid))
73 { p = US"set owner on"; goto bad; }
74
75 /* It appears that any mode bits greater than 0777 are ignored by
76 mkdir(), at least on some operating systems. Therefore, if the mode
77 contains any such bits, do an explicit mode setting. */
78
79 if (mode & 0777000) (void) Uchmod(path, mode);
80 }
81 *p++ = c;
82 }
83
84return TRUE;
85
86bad:
87 if (panic) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
88 "Failed to %s directory \"%s\": %s\n", p, path, strerror(errno));
89 return FALSE;
90}
91
92/* End of directory.c */