summaryrefslogtreecommitdiff
path: root/src/timefile.c
blob: 5163d32579695056154f298f5454bf3536874c9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* -*- c-file-style: "java"; indent-tabs-mode: nil; tab-width: 4; fill-column: 78 -*-
 *
 * distcc -- A simple distributed compiler system
 *
 * Copyright (C) 2003 by Martin Pool <mbp@samba.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 */


/**
 * @file
 *
 * @brief Track timeouts by setting the mtime of a file.
 *
 * distcc needs to set timeouts to backoff from unreachable hosts.  As a very
 * simple and robust way of keeping track of this, we simply touch a file in
 * our state directory, whenever we fail to connect.  Future invocations can
 * look at how recently the host failed when deciding whether to use it again.
 **/


#include <config.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>

#include <sys/stat.h>
#include <sys/file.h>

#include "distcc.h"
#include "trace.h"
#include "util.h"
#include "exitcode.h"
#include "snprintf.h"
#include "lock.h"
#include "timefile.h"


/**
 * Record the current time against the specified function and host.
 **/
int dcc_mark_timefile(const char *lockname,
                      const struct dcc_hostdef *host)
{
    char *filename;
    int fd;
    int ret;

    if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename)))
        return ret;

    if ((ret = dcc_open_lockfile(filename, &fd))) {
        free(filename);
        return ret;
    }

    /* Merely opening it with O_WRONLY is not necessarily enough to set its
     * mtime to the current time. */
    if (write(fd, "x", 1) != 1) {
        rs_log_error("write to %s failed: %s", lockname, strerror(errno));
        dcc_close(fd);
        return EXIT_IO_ERROR;
    }

    dcc_close(fd);

    rs_trace("mark %s", filename);

    free(filename);

    return 0;
}



/**
 * Remove the specified timestamp.
 **/
int dcc_remove_timefile(const char *lockname,
                        const struct dcc_hostdef *host)
{
    char *filename;
    int ret = 0;

    if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename)))
        return ret;

    if (unlink(filename) == 0) {
        rs_trace("remove %s", filename);
    } else {
        if (errno == ENOENT) {
            /* it's ok if somebody else already removed it */
        } else {
            rs_log_error("unlink %s failed: %s", filename, strerror(errno));
            ret = EXIT_IO_ERROR;
        }
    }

    free(filename);

    return 0;
}



/**
 * Return the mtime for a timestamp file.
 *
 * If the timestamp doesn't exist then we count it as time zero.
 **/
int dcc_check_timefile(const char *lockname,
                       const struct dcc_hostdef *host,
                       time_t *mtime)
{
    char *filename;
    struct stat sb;
    int ret;

    if ((ret = dcc_make_lock_filename(lockname, host, 0, &filename)))
        return ret;

    if (stat(filename, &sb) == -1) {
        *mtime = (time_t) 0;
        if (errno == ENOENT) {
            /* just no record for this file; that's fine. */
            free(filename);
            return 0;
        } else {
            rs_log_error("stat %s failed: %s", filename, strerror(errno));
            free(filename);
            return EXIT_IO_ERROR;
        }
    }

    *mtime = sb.st_mtime;

    free(filename);

    return 0;
}