Merge commit 'upstream/1.8.2'
[debian/sudo] / common / fileops.c
1 /*
2  * Copyright (c) 1999-2005, 2007, 2009-2011
3  *      Todd C. Miller <Todd.Miller@courtesan.com>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  *
17  * Sponsored in part by the Defense Advanced Research Projects
18  * Agency (DARPA) and Air Force Research Laboratory, Air Force
19  * Materiel Command, USAF, under agreement number F39502-99-1-0512.
20  */
21
22 #include <config.h>
23
24 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/time.h>
27 #ifdef HAVE_FLOCK
28 # include <sys/file.h>
29 #endif /* HAVE_FLOCK */
30 #include <stdio.h>
31 #ifdef HAVE_STRING_H
32 # include <string.h>
33 #endif /* HAVE_STRING_H */
34 #ifdef HAVE_STRINGS_H
35 # include <strings.h>
36 #endif /* HAVE_STRINGS_H */
37 #include <ctype.h>
38 #include <limits.h>
39 #ifdef HAVE_UNISTD_H
40 # include <unistd.h>
41 #endif /* HAVE_UNISTD_H */
42 #include <fcntl.h>
43 #if TIME_WITH_SYS_TIME
44 # include <time.h>
45 #endif
46 #ifndef HAVE_TIMESPEC
47 # include "compat/timespec.h"
48 #endif
49
50 #include "missing.h"
51 #include "fileops.h"
52
53 #ifndef LINE_MAX
54 # define LINE_MAX 2048
55 #endif
56
57 /*
58  * Update the access and modify times on an fd or file.
59  */
60 int
61 touch(int fd, char *path, struct timeval *tvp)
62 {
63     struct timeval times[2];
64
65     if (tvp != NULL) {
66         times[0].tv_sec = times[1].tv_sec = tvp->tv_sec;
67         times[0].tv_usec = times[1].tv_usec = tvp->tv_usec;
68     }
69
70 #if defined(HAVE_FUTIME) || defined(HAVE_FUTIMES)
71     if (fd != -1)
72         return futimes(fd, tvp ? times : NULL);
73     else
74 #endif
75     if (path != NULL)
76         return utimes(path, tvp ? times : NULL);
77     else
78         return -1;
79 }
80
81 /*
82  * Lock/unlock a file.
83  */
84 #ifdef HAVE_LOCKF
85 int
86 lock_file(int fd, int lockit)
87 {
88     int op = 0;
89
90     switch (lockit) {
91         case SUDO_LOCK:
92             op = F_LOCK;
93             break;
94         case SUDO_TLOCK:
95             op = F_TLOCK;
96             break;
97         case SUDO_UNLOCK:
98             op = F_ULOCK;
99             break;
100     }
101     return lockf(fd, op, 0) == 0;
102 }
103 #elif HAVE_FLOCK
104 int
105 lock_file(int fd, int lockit)
106 {
107     int op = 0;
108
109     switch (lockit) {
110         case SUDO_LOCK:
111             op = LOCK_EX;
112             break;
113         case SUDO_TLOCK:
114             op = LOCK_EX | LOCK_NB;
115             break;
116         case SUDO_UNLOCK:
117             op = LOCK_UN;
118             break;
119     }
120     return flock(fd, op) == 0;
121 }
122 #else
123 int
124 lock_file(int fd, int lockit)
125 {
126 #ifdef F_SETLK
127     int func;
128     struct flock lock;
129
130     lock.l_start = 0;
131     lock.l_len = 0;
132     lock.l_pid = getpid();
133     lock.l_type = (lockit == SUDO_UNLOCK) ? F_UNLCK : F_WRLCK;
134     lock.l_whence = SEEK_SET;
135     func = (lockit == SUDO_LOCK) ? F_SETLKW : F_SETLK;
136
137     return fcntl(fd, func, &lock) == 0;
138 #else
139     return TRUE;
140 #endif
141 }
142 #endif
143
144 /*
145  * Read a line of input, remove comments and strip off leading
146  * and trailing spaces.  Returns static storage that is reused.
147  */
148 char *
149 sudo_parseln(FILE *fp)
150 {
151     size_t len;
152     char *cp = NULL;
153     static char buf[LINE_MAX];
154
155     if (fgets(buf, sizeof(buf), fp) != NULL) {
156         /* Remove comments */
157         if ((cp = strchr(buf, '#')) != NULL)
158             *cp = '\0';
159
160         /* Trim leading and trailing whitespace/newline */
161         len = strlen(buf);
162         while (len > 0 && isspace((unsigned char)buf[len - 1]))
163             buf[--len] = '\0';
164         for (cp = buf; isblank((unsigned char)*cp); cp++)
165             continue;
166     }
167     return cp;
168 }