12cfa24ee0964c83cf464f1b7e0f5cbb4e9e74cc
[src/app-framework-main.git] / src / wgtpkg-workdir.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #define _GNU_SOURCE
18
19 #include <unistd.h>
20 #include <string.h>
21 #include <dirent.h>
22 #include <syslog.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27
28 #include "wgtpkg.h"
29
30 static int mode = 0700;
31 static char workdir[PATH_MAX];
32
33 /* removes recursively the content of a directory */
34 static int clean_dirfd(int dirfd)
35 {
36         int cr, fd;
37         DIR *dir;
38         struct dirent *ent;
39         struct {
40                 struct dirent entry;
41                 char spare[PATH_MAX];
42         } entry;
43
44         dir = fdopendir(dirfd);
45         if (dir == NULL) {
46                 syslog(LOG_ERR, "opendir failed in clean_dirfd");
47                 return -1;
48         }
49
50         cr = -1;
51         for (;;) {
52                 if (readdir_r(dir, &entry.entry, &ent) != 0) {
53                         syslog(LOG_ERR, "readdir_r failed in clean_dirfd");
54                         goto error;
55                 }
56                 if (ent == NULL)
57                         break;
58                 if (ent->d_name[0] == '.' && (ent->d_name[1] == 0
59                                 || (ent->d_name[1] == '.' && ent->d_name[2] == 0)))
60                         continue;
61                 cr = unlinkat(dirfd, ent->d_name, 0);
62                 if (!cr)
63                         continue;
64                 if (errno != EISDIR) {
65                         syslog(LOG_ERR, "unlink of %s failed in clean_dirfd", ent->d_name);
66                         goto error;
67                 }
68                 fd = openat(dirfd, ent->d_name, O_DIRECTORY|O_RDONLY);
69                 if (fd < 0) {
70                         syslog(LOG_ERR, "opening directory %s failed in clean_dirfd", ent->d_name);
71                         goto error;
72                 }
73                 cr = clean_dirfd(fd);
74                 close(fd);
75                 if (cr)
76                         goto error;
77                 cr = unlinkat(dirfd, ent->d_name, AT_REMOVEDIR);
78                 if (cr) {
79                         syslog(LOG_ERR, "rmdir of %s failed in clean_dirfd", ent->d_name);
80                         goto error;
81                 }
82         }
83         cr = 0;
84 error:
85         closedir(dir);
86         return cr;
87 }
88
89 /* removes recursively the content of a directory */
90 static int clean_dir(const char *directory)
91 {
92         int fd, rc;
93
94         fd = openat(AT_FDCWD, directory, O_DIRECTORY|O_RDONLY);
95         if (fd < 0) {
96                 syslog(LOG_ERR, "opening directory %s failed in clean_dir", directory);
97                 return fd;
98         }
99         rc = clean_dirfd(fd);
100         close(fd);
101         return rc;
102 }
103
104 /* removes the content of the working directory */
105 int enter_workdir(int clean)
106 {
107         int rc = chdir(workdir);
108         if (rc)
109                 syslog(LOG_ERR, "entring workdir %s failed", workdir);
110         else if (clean)
111                 rc = clean_dir(workdir);
112         return rc;
113 }
114
115 /* removes the working directory */
116 void remove_workdir()
117 {
118         enter_workdir(1);
119         chdir("..");
120         rmdir(workdir);
121 }
122
123 int set_workdir(const char *name, int create)
124 {
125         int rc;
126         size_t length;
127         struct stat s;
128
129         /* check the length */
130         length = strlen(name);
131         if (length >= sizeof workdir) {
132                 syslog(LOG_ERR, "workdir name too long");
133                 errno = EINVAL;
134                 return -1;
135         }
136
137         rc = stat(name, &s);
138         if (rc) {
139                 if (!create) {
140                         syslog(LOG_ERR, "no workdir %s", name);
141                         return -1;
142                 }
143                 rc = mkdir(name, mode);
144                 if (rc) {
145                         syslog(LOG_ERR, "can't create workdir %s", name);
146                         return -1;
147                 }
148
149         } else if (!S_ISDIR(s.st_mode)) {
150                 syslog(LOG_ERR, "%s isn't a directory", name);
151                 errno = ENOTDIR;
152                 return -1;
153         }
154         memcpy(workdir, name, 1+length);
155         return 0;
156 }
157
158 int make_workdir_base(const char *root, const char *prefix, int reuse)
159 {
160         int i, n, r, l;
161
162         n = snprintf(workdir, sizeof workdir, "%s/%s", root, prefix);
163         if (n >= sizeof workdir) {
164                 syslog(LOG_ERR, "workdir prefix too long");
165                 errno = EINVAL;
166                 return -1;
167         }
168         r = (int)(sizeof workdir) - n;
169
170         /* create a temporary directory */
171         for (i = 0 ; ; i++) {
172                 if (i == INT_MAX) {
173                         syslog(LOG_ERR, "exhaustion of workdirs");
174                         return -1;
175                 }
176                 l = snprintf(workdir + n, r, "%d", i);
177                 if (l >= r) {
178                         syslog(LOG_ERR, "computed workdir too long");
179                         errno = EINVAL;
180                         return -1;
181                 }
182                 if (!mkdir(workdir, mode))
183                         break;
184                 if (errno != EEXIST) {
185                         syslog(LOG_ERR, "error in creation of workdir %s: %m", workdir);
186                         return -1;
187                 }
188                 if (reuse)
189                         break;
190         }
191
192         return 0;
193 }
194
195 int make_workdir(int reuse)
196 {
197         return make_workdir_base(".", "PACK", reuse);
198 }
199
200 int workdirfd()
201 {
202         int result = open(workdir, O_PATH|O_DIRECTORY);
203         if (result < 0)
204                 syslog(LOG_ERR, "can't get fd for workdir %.*s: %m", PATH_MAX, workdir);
205         return result;
206 }
207
208 int move_workdir(const char *dest, int parents, int force)
209 {
210         
211 }
212