daemon: count_strings function returns size_t
[libguestfs.git] / daemon / link.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <limits.h>
27
28 #include "daemon.h"
29 #include "actions.h"
30
31 char *
32 do_readlink (const char *path)
33 {
34   ssize_t r;
35   char *ret;
36   char link[PATH_MAX];
37
38   CHROOT_IN;
39   r = readlink (path, link, sizeof link);
40   CHROOT_OUT;
41   if (r == -1) {
42     reply_with_perror ("readlink");
43     return NULL;
44   }
45
46   ret = strndup (link, r);
47   if (ret == NULL) {
48     reply_with_perror ("strndup");
49     return NULL;
50   }
51
52   return ret;                   /* caller frees */
53 }
54
55 char **
56 do_readlinklist (const char *path, char *const *names)
57 {
58   int fd_cwd;
59   size_t i;
60   ssize_t r;
61   char link[PATH_MAX];
62   const char *str;
63   char **ret = NULL;
64   int size = 0, alloc = 0;
65
66   CHROOT_IN;
67   fd_cwd = open (path, O_RDONLY | O_DIRECTORY);
68   CHROOT_OUT;
69
70   if (fd_cwd == -1) {
71     reply_with_perror ("open: %s", path);
72     return NULL;
73   }
74
75   for (i = 0; names[i] != NULL; ++i) {
76     r = readlinkat (fd_cwd, names[i], link, sizeof link);
77     if (r >= PATH_MAX) {
78       reply_with_perror ("readlinkat: returned link is too long");
79       free_strings (ret);
80       close (fd_cwd);
81       return NULL;
82     }
83     /* Because of the way this function is intended to be used,
84      * we actually expect to see errors here, and they are not fatal.
85      */
86     if (r >= 0) {
87       link[r] = '\0';
88       str = link;
89     } else
90       str = "";
91     if (add_string (&ret, &size, &alloc, str) == -1) {
92       close (fd_cwd);
93       return NULL;
94     }
95   }
96
97   close (fd_cwd);
98
99   if (add_string (&ret, &size, &alloc, NULL) == -1)
100     return NULL;
101
102   return ret;
103 }
104
105 static int
106 _link (const char *flag, int symbolic, const char *target, const char *linkname)
107 {
108   int r;
109   char *err;
110   char *buf_linkname;
111   char *buf_target;
112
113   /* Prefix linkname with sysroot. */
114   buf_linkname = sysroot_path (linkname);
115   if (!buf_linkname) {
116     reply_with_perror ("malloc");
117     return -1;
118   }
119
120   /* Only prefix target if it's _not_ a symbolic link, and if
121    * the target is absolute.  Note that the resulting link will
122    * always be "broken" from the p.o.v. of the appliance, ie:
123    * /a -> /b but the path as seen here is /sysroot/b
124    */
125   buf_target = NULL;
126   if (!symbolic && target[0] == '/') {
127     buf_target = sysroot_path (target);
128     if (!buf_target) {
129       reply_with_perror ("malloc");
130       free (buf_linkname);
131       return -1;
132     }
133   }
134
135   if (flag)
136     r = command (NULL, &err,
137                  "ln", flag, "--", /* target could begin with '-' */
138                  buf_target ? : target, buf_linkname, NULL);
139   else
140     r = command (NULL, &err,
141                  "ln", "--",
142                  buf_target ? : target, buf_linkname, NULL);
143   free (buf_linkname);
144   free (buf_target);
145   if (r == -1) {
146     reply_with_error ("ln%s%s: %s: %s: %s",
147                       flag ? " " : "",
148                       flag ? : "",
149                       target, linkname, err);
150     free (err);
151     return -1;
152   }
153
154   free (err);
155
156   return 0;
157 }
158
159 int
160 do_ln (const char *target, const char *linkname)
161 {
162   return _link (NULL, 0, target, linkname);
163 }
164
165 int
166 do_ln_f (const char *target, const char *linkname)
167 {
168   return _link ("-f", 0, target, linkname);
169 }
170
171 int
172 do_ln_s (const char *target, const char *linkname)
173 {
174   return _link ("-s", 1, target, linkname);
175 }
176
177 int
178 do_ln_sf (const char *target, const char *linkname)
179 {
180   return _link ("-sf", 1, target, linkname);
181 }