1 /* $Rev$ */
2
3 #include <sys/stat.h>
4 #include <errno.h>
5 #include <fcntl.h>
6 #include <stdio.h>
7 #include <string.h>
8 #include <unistd.h>
9
10 #include "install.h"
11
12 #define COPY "copy"
13 #define COPYBUF_SIZE 8192
14
15 char copybuf[COPYBUF_SIZE];
16 char tmpdst[1024];
17 char *src;
18 char *dst;
19 int uid;
20 int gid;
21 unsigned int perm;
22
complain(const char * s)23 void complain(const char *s)
24 {
25 if (s)
26 printf("error: %s: %s\n", s, install_error(errno));
27 else
28 printf("error: %s\n", install_error(errno));
29 }
say()30 void say()
31 {
32 int t_uid;
33 int t_gid;
34 t_uid = (uid == -1) ? (int) getuid() : uid;
35 t_gid = (gid == -1) ? (int) getgid() : gid;
36 printf(COPY" %s %s %d:%d %o\n", src, dst, t_uid, t_gid, perm);
37 fflush(0);
38 }
copy()39 int copy()
40 {
41 int srcfd;
42 int dstfd;
43 int r;
44 int w;
45 int code;
46
47 if (snprintf(tmpdst, 1024, "%s.tmp", dst) < 0) return 112;
48 srcfd = open(src, O_RDONLY);
49 if (srcfd == -1) { complain("open"); return 113; }
50 dstfd = open(tmpdst, O_WRONLY | O_TRUNC | O_CREAT, 0600);
51 if (dstfd == -1) { complain("open"); code = 114; goto ERR; }
52
53 for (;;) {
54 r = read(srcfd, copybuf, COPYBUF_SIZE);
55 if (r == -1) { complain("read"); code = 115; goto ERR; }
56 if (r == 0) break;
57 while (r) {
58 w = write(dstfd, copybuf, r);
59 if (w == -1) { complain("read"); code = 116; goto ERR; }
60 if (w == 0) break;
61 r -= w;
62 }
63 }
64
65 if (fsync(dstfd) == -1) { complain("fsync"); code = 117; goto ERR; }
66 if (chmod(tmpdst, perm) == -1) { complain("chmod"); code = 118; goto ERR; }
67 if (chown(tmpdst, uid, gid) == -1) {
68 complain("chown"); code = 119; goto ERR;
69 }
70 if (rename(tmpdst, dst) == -1) { complain("rename"); code = 120; goto ERR; }
71 if (close(dstfd) == -1) complain("close");
72 if (close(srcfd) == -1) complain("close");
73 return 0;
74 ERR:
75 if (unlink(tmpdst) == -1) complain("unlink");
76 return code;
77 }
78
main(int argc,char * argv[])79 int main(int argc, char *argv[])
80 {
81 --argc;
82 ++argv;
83
84 if (argc < 5) return 111;
85
86 src = argv[0];
87 dst = argv[1];
88 if (!sscanf(argv[2], "%d", &uid)) return 111;
89 if (!sscanf(argv[3], "%d", &gid)) return 111;
90 if (!sscanf(argv[4], "%o", &perm)) return 111;
91
92 say();
93
94 if (argc < 6) return copy();
95 return 0;
96 }
97