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