]> pd.if.org Git - zpackage/blob - zpm-add.c
add files for zpm-add rewrite
[zpackage] / zpm-add.c
1 #define _POSIX_C_SOURCE 200809L
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include <string.h>
5
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <dirent.h>
9 #include <unistd.h>
10 #include <pwd.h>
11 #include <grp.h>
12 #include <errno.h>
13 #include <fcntl.h>
14
15 #include "zpm.h"
16 #include "sqlite/sqlite3.h"
17
18 struct opts {
19         char *package, *version;
20         int release;
21         int complete, addcontent, isconfig, opt_l, recursive, verbose;
22         int followsymlinks;
23         int xargs, noclear;
24         mode_t clmode;
25
26         char *cltype, *clhash, *clmtime, *prefix, *strip, *cltarget;
27         char *clgroup, *cluser;
28 };
29
30 #if 0
31 static void warn(char *fmt, ...) {
32         va_list args;
33
34         va_start(args, fmt);
35         vfprintf(stderr, fmt, args);
36         va_end(args);
37         fprintf(stderr, "\n");
38 }
39 #endif
40
41 static int dieval = EXIT_FAILURE;
42
43 static void die(char *fmt, ...) {
44         va_list args;
45
46         va_start(args, fmt);
47         vfprintf(stderr, fmt, args);
48         va_end(args);
49         fprintf(stderr, "\n");
50         exit(dieval);
51 }
52
53 char *cleanpath(char *path, char *strip, char *prefix) {
54         char *s = path;
55         char *t = s;
56         size_t len = 0;
57         char *new;
58
59         if (strip) {
60                 len = strlen(strip);
61                 if (strncmp(path, strip, len)) {
62                         /* strip is not a prefix */
63                         return 0;
64                 }
65                 s += len;
66         }
67
68         len += strlen(s)+1;
69
70         new = malloc(len);
71         memset(new, 0, len);
72
73         if (!new) {
74                 return NULL;
75         }
76         t = new;
77
78         if (prefix) {
79                 strcpy(new, prefix);
80                 t = new + strlen(prefix);
81         }
82
83         /* skip leading curdir */
84         if (*s && *s == '.' && s[1] && s[1] == '/') {
85                 s += 2;
86         }
87
88         /* skip leading slashes */
89         while (*s == '/') {
90                 s++;
91         }
92
93         if (*t != '/') {
94                 *t++ = '/';
95         }
96
97         for (; *s; s++) {
98                 /* skip multiple slashes */
99                 if (*s == '/' && s[1] && s[1] == '/') {
100                         continue;
101                 }
102                 /* skip trailing slash */
103                 if (*s == '/' && !s[1]) {
104                         continue;
105                 }
106
107                 /* skip curdirs */
108                 if (*s == '/' && s[1] && s[1] == '.' && s[2] && s[2] == '/') {
109                         s += 1;
110                         continue;
111                 }
112
113                 if (*s == '/' && s[1] && s[1] == '.' && s[2] == 0) {
114                         s += 1;
115                         continue;
116                 }
117
118                 *t++ = *s;
119         }
120         *t = 0;
121
122         return new;
123 }
124
125 char *getuser(uid_t uid) {
126         struct passwd *pw;
127
128         pw = getpwuid(uid);
129         if (pw) {
130                 return strdup(pw->pw_name);
131         }
132         return 0;
133 }
134
135 char *getgroup(uid_t uid) {
136         struct passwd *pw;
137
138         pw = getpwuid(uid);
139         if (pw) {
140                 return strdup(pw->pw_name);
141         }
142         return 0;
143 }
144
145 void free_file(struct zpm_file *file) {
146         free(file->path);
147         free(file->owner);
148         free(file->group);
149         free(file->target);
150         file->path = file->owner = file->group = file->target = 0;
151 }
152
153 int stat_file(struct zpm_file *file, char *path, struct opts *opt) {
154                 struct stat st;
155                 int rv;
156
157                 file->data = path;
158
159                 errno = 0;
160                 if (opt->followsymlinks) {
161                         rv = stat(path, &st);
162                 } else {
163                         rv = lstat(path, &st);
164                 }
165
166                 if (rv == -1) {
167                         return 0;
168                 }
169
170                 switch (st.st_mode & S_IFMT) {
171                         case S_IFBLK: file->type = 'b'; break;
172                         case S_IFCHR: file->type = 'c'; break;
173                         case S_IFDIR: file->type = 'd'; break;
174                         case S_IFIFO: file->type = 'p'; break;
175                         case S_IFLNK: file->type = 'l'; break;
176                         case S_IFREG: file->type = 'r'; break;
177                         case S_IFSOCK: file->type = 's'; break;
178                         default: file->type = 0; break;
179                 }
180
181                 file->configuration = opt->isconfig;
182
183                 if (file->type == 0) {
184                         return 0;
185                 }
186
187                 if (file->type == 'l') {
188                         if (opt->cltarget) {
189                                 file->target = strdup(opt->cltarget);
190                         } else {
191                                 char linkval[4096];
192                                 size_t n;
193                                 n = readlink(path, linkval, sizeof linkval);
194                                 if (n >= sizeof linkval) {
195                                         return 0;
196                                 }
197                                 file->target = strdup(linkval);
198                         }
199                 }
200                 
201                 /* strip and prefix */
202                 file->path = cleanpath(path, opt->strip, opt->prefix);
203                 if (file->path == 0) {
204                         free_file(file);
205                         return 0;
206                 }
207
208                 if (opt->clmode) {
209                         file->mode = opt->clmode;
210                 } else {
211                         file->mode = st.st_mode;
212                 }
213
214                 if (opt->cluser) {
215                         file->owner = strdup(opt->cluser);
216                 } else {
217                         file->owner = getuser(st.st_uid);
218                 }
219
220                 if (file->owner == 0) {
221                         free_file(file);
222                         return 0;
223                 }
224
225                 if (opt->clgroup) {
226                         file->group = strdup(opt->clgroup);
227                 } else {
228                         file->group = getgroup(st.st_gid);
229                 }
230                 if (file->group == 0) {
231                         free_file(file);
232                         return 0;
233                 }
234
235                 file->mtime = st.st_mtime;
236
237                 return 1;
238 }
239
240 int add_file(struct zpm *zpm, struct zpm_file *file, struct opts *opt);
241
242 int add_dir(struct zpm *zpm, char *path, struct opts *opt) {
243         DIR *dir;
244         struct dirent *de;
245         struct zpm_file file = { 0 };
246
247         dir = opendir(path);
248
249         if (!dir) {
250                 zpm_seterror(zpm, "can't open dir %s: %s", path, strerror(errno));
251                 return 0;
252         }
253
254         while ((de = readdir(dir))) {
255                 if (!strcmp(de->d_name, ".")) {
256                         continue;
257                 }
258                 if (!strcmp(de->d_name, "..")) {
259                         continue;
260                 }
261                 
262                 if (!stat_file(&file, de->d_name, opt)) {
263                         zpm_seterror(zpm, "stat %s failed: %s",
264                                         de->d_name, strerror(errno));
265                         return 0;
266                 }
267
268                 if (!add_file(zpm, &file, opt)) {
269                         free_file(&file);
270                         return 0;
271                 }
272                 free_file(&file);
273         }
274         return 1;
275 }
276
277 int add_file(struct zpm *zpm, struct zpm_file *file, struct opts *opt) {
278         char hash[ZPM_HASH_STRLEN+1];
279
280         if (file->type == 'r') {
281                 if (opt->addcontent) {
282                         if (zpm_import(zpm, file->data, 0, hash)) {
283                                 strcpy(file->hash, hash);
284                         } else {
285                                 return 0;
286                         }
287                 } else {
288                         zpm_hash(file->data, hash, 0);
289                         strcpy(file->hash, hash);
290                 }
291         }
292
293         zpm_db_run(zpm, "insert or replace into packagefiles "
294                         "(package,version,release,path,mode,mtime,username,"
295                         "groupname,filetype,hash,configuration,target)"
296                        " values "
297                        "(%Q, %Q, %d, %Q, %o, %d, %Q, %Q, '%c', %Q, %d, %Q)",
298                         opt->package, opt->version, opt->release, file->path,
299                         file->mode, (int)file->mtime, file->owner, file->group,
300                         file->type,
301                         file->hash, file->configuration, file->target
302                   );
303
304         if (zpm->error) {
305                 return 0;
306         }
307
308         if (opt->verbose > 1) {
309                 printf("%c%o %s:%s %s\n", file->type, file->mode, file->owner, file->group, file->path);
310         } else if (opt->verbose > 0) {
311
312                 printf("%s\n", file->path);
313
314         }
315
316         if (opt->recursive && file->type == 'd') {
317                 if (!add_dir(zpm, file->data, opt)) {
318                         return 0;
319                 }
320         }
321
322         return 1;
323 }
324
325 int main(int ac, char **av) {
326         struct zpm zpm;
327         struct opts opt = { 0 };
328         int i;
329         int option;
330
331         char hash[ZPM_HASH_STRLEN+1];
332
333         char *dbfile = getenv("ZPMDB");
334
335         if (!dbfile) {
336                 dbfile = "/var/lib/zpm/local.db";
337         }
338
339         opt.addcontent = 1;
340
341         while ((option = getopt(ac, av, ":f:vr:l:P:S:cu:g:NCm:M:T:H:F:zxh")) != -1) {
342                 switch (option) {
343                         case 'C': opt.complete = 1; break;
344                         case 'F': opt.cltype = optarg; break;
345                         case 'H': opt.clhash = optarg; break;
346                         case 'M': opt.clmtime = optarg; break;
347                         case 'N': opt.addcontent = 0; break;
348                         case 'P': opt.prefix = optarg; break;
349                         case 'S': opt.strip = optarg; break;
350                         case 'T': opt.cltarget = optarg; break;
351                         case 'c': opt.isconfig = 1; break;
352                         case 'f': dbfile = optarg; break;
353                         case 'g': opt.clgroup = optarg; break;
354                         case 'h': opt.followsymlinks = 1; break;
355                         case 'l': opt.opt_l = 1; break;
356                         case 'm': opt.clmode = strtol(optarg, NULL, 8); break;
357                         case 'r': opt.recursive = 1; break;
358                         case 'u': opt.cluser = optarg; break;
359                         case 'v': opt.verbose++; break;
360                         case 'x': opt.xargs = 1; dieval = 255; break;
361                         case 'z': opt.noclear = 1; break;
362                         default:
363                                   exit(EXIT_FAILURE);
364                                   break;
365                 }
366         }
367
368         if (ac < optind) {
369                 exit(EXIT_FAILURE);
370         }
371
372         if (!zpm_open(&zpm, dbfile)) {
373                 die("can't open zpm db %s", dbfile);
374         }
375
376 #if 0
377         i = sqlite3_config(SQLITE_CONFIG_MMAP_SIZE,98222080);
378         if (i != SQLITE_OK) {
379                 exit(3);
380         }
381 #endif
382
383         /* package is first arg */
384         char *pkgstr;
385         char *pkgid;
386         pkgstr = av[optind++];
387         pkgid = zpm_findpkg(&zpm, pkgstr, NULL);
388         /* TODO if not found, error */
389         if (!pkgid) {
390                 die("package %s not found\n", pkgstr);
391         }
392
393         char package[128];
394         char version[64];
395         int release;
396
397         zpm_parse_package(pkgid, package, version, &release);
398         opt.package = package;
399         opt.version = version;
400         opt.release = release;
401
402         if (opt.verbose) {
403                 printf("adding to %s %s\n", dbfile, pkgid);
404         }
405         fflush(stdout);
406
407         //zpm_begin(&zpm);
408
409         struct zpm_file file;
410         for (i=optind; av[i]; i++) {
411                 if (!stat_file(&file, av[i], &opt)) {
412                         die("can't stat %s: %s", av[i], strerror(errno));
413                 }
414                 file.data = av[i];
415                 if (add_file(&zpm, &file, &opt)) {
416                         free_file(&file);
417                 } else {
418                         die("error: %s", zpm.errmsg);
419                 }
420         }
421
422         if (opt.complete) {
423                 zpm_db_run(&zpm, "update packages set build_time = %d where package = %Q and version = %Q and release = %d", time(NULL), package, version, release);
424                 zpm_package_hash(&zpm, pkgid, hash);
425                 zpm_package_sethash(&zpm, pkgid, hash);
426         } else if (!opt.noclear) {
427                 zpm_db_run(&zpm, "update packages set build_time = null, hash = null where package = %Q and version = %Q and release = %d", package, version, release);
428         }
429         /* TODO error check */
430
431         //zpm_commit(&zpm);
432         zpm_close(&zpm);
433         return 0;
434 }