make-config.in: complete path (leftover of [807f64e2], 2015-12-26!)
[s-mailx.git] / dotlock.h
blobe9d80f988edcfc35583fb9e94e30f504bc675f8e
1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
2 *@ Creation of an exclusive "dotlock" file. This is (potentially) shared
3 *@ in between n_dotlock() and the privilege-separated "dotlocker"..
4 *@ (Which is why it doesn't use NYD or other utilities.)
5 *@ The code assumes it has been chdir(2)d into the target directory and
6 *@ that SIGPIPE is ignored (we react upon ERR_PIPE).
7 *@ It furtherly assumes that it can create a file name that is at least one
8 *@ byte longer than the dotlock file's name!
10 * Copyright (c) 2012 - 2018 Steffen (Daode) Nurpmeso <steffen@sdaoden.eu>.
11 * SPDX-License-Identifier: BSD-2-Clause
14 * Copyright (c) 1996 Christos Zoulas. All rights reserved.
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 * 1. Redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer.
21 * 2. Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
34 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 /* Jump in */
38 static enum n_dotlock_state a_dotlock_create(struct n_dotlock_info *dip);
40 /* Create a unique file. O_EXCL does not really work over NFS so we follow
41 * the following trick (inspired by S.R. van den Berg):
42 * - make a mostly unique filename and try to create it
43 * - link the unique filename to our target
44 * - get the link count of the target
45 * - unlink the mostly unique filename
46 * - if the link count was 2, then we are ok; else we've failed */
47 static enum n_dotlock_state a_dotlock__create_excl(struct n_dotlock_info *dip,
48 char const *lname);
50 static enum n_dotlock_state
51 a_dotlock_create(struct n_dotlock_info *dip){
52 /* Use PATH_MAX not NAME_MAX to catch those "we proclaim the minimum value"
53 * problems (SunOS), since the pathconf(3) value came too late! */
54 char lname[PATH_MAX +1];
55 sigset_t nset, oset;
56 size_t tries;
57 ssize_t w;
58 enum n_dotlock_state rv, xrv;
60 /* (Callee ensured this doesn't end up as plain "di_lock_name") */
61 snprintf(lname, sizeof lname, "%s.%s.%s",
62 dip->di_randstr, dip->di_lock_name, dip->di_hostname);
64 sigfillset(&nset);
66 for(tries = 0;; ++tries){
67 sigprocmask(SIG_BLOCK, &nset, &oset);
68 rv = a_dotlock__create_excl(dip, lname);
69 sigprocmask(SIG_SETMASK, &oset, NULL);
71 if(rv == n_DLS_NONE || (rv & n_DLS_ABANDON))
72 break;
73 if(dip->di_pollmsecs == 0 || tries >= DOTLOCK_TRIES){
74 rv |= n_DLS_ABANDON;
75 break;
78 xrv = n_DLS_PING;
79 w = write(STDOUT_FILENO, &xrv, sizeof xrv);
80 if(w == -1 && n_err_no == n_ERR_PIPE){
81 rv = n_DLS_DUNNO | n_DLS_ABANDON;
82 break;
84 n_msleep(dip->di_pollmsecs, FAL0);
86 return rv;
89 static enum n_dotlock_state
90 a_dotlock__create_excl(struct n_dotlock_info *dip, char const *lname){
91 struct stat stb;
92 int fd, e;
93 size_t tries;
94 enum n_dotlock_state rv = n_DLS_NONE;
96 /* We try to create the unique filename */
97 for(tries = 0;; ++tries){
98 fd = open(lname,
99 #ifdef O_SYNC
100 (O_WRONLY | O_CREAT | O_EXCL | O_SYNC),
101 #else
102 (O_WRONLY | O_CREAT | O_EXCL),
103 #endif
104 S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
105 if(fd != -1){
106 #ifdef n_PRIVSEP_SOURCE
107 if(dip->di_stb != NULL &&
108 fchown(fd, dip->di_stb->st_uid, dip->di_stb->st_gid)){
109 int x = n_err_no;
110 close(fd);
111 n_err_no = x;
112 goto jbados;
114 #endif
115 close(fd);
116 break;
117 }else if((e = n_err_no) != n_ERR_EXIST){
118 rv = (e == n_ERR_ROFS) ? n_DLS_ROFS | n_DLS_ABANDON : n_DLS_NOPERM;
119 goto jleave;
120 }else if(tries >= DOTLOCK_TRIES){
121 rv = n_DLS_EXIST;
122 goto jleave;
126 /* We link the name to the fname */
127 if(link(lname, dip->di_lock_name) == -1)
128 goto jbados;
130 /* Note that we stat our own exclusively created name, not the
131 * destination, since the destination can be affected by others */
132 if(stat(lname, &stb) == -1)
133 goto jbados;
135 unlink(lname);
137 /* If the number of links was two (one for the unique file and one for
138 * the lock), we've won the race */
139 if(stb.st_nlink != 2)
140 rv = n_DLS_EXIST;
141 jleave:
142 return rv;
143 jbados:
144 rv = (n_err_no == n_ERR_EXIST) ? n_DLS_EXIST : n_DLS_NOPERM | n_DLS_ABANDON;
145 unlink(lname);
146 goto jleave;
149 /* s-it-mode */