daemon: debug segv correct use of dereferencing NULL.
[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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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       close (fd_cwd);
80       return NULL;
81     }
82     /* Because of the way this function is intended to be used,
83      * we actually expect to see errors here, and they are not fatal.
84      */
85     if (r >= 0) {
86       link[r] = '\0';
87       str = link;
88     } else
89       str = "";
90     if (add_string (&ret, &size, &alloc, str) == -1) {
91       close (fd_cwd);
92       return NULL;
93     }
94   }
95
96   close (fd_cwd);
97
98   if (add_string (&ret, &size, &alloc, NULL) == -1)
99     return NULL;
100
101   return ret;
102 }
103
104 static int
105 _link (const char *flag, int symbolic, const char *target, const char *linkname)
106 {
107   int r;
108   char *err;
109   char *buf_linkname;
110   char *buf_target;
111
112   /* Prefix linkname with sysroot. */
113   buf_linkname = sysroot_path (linkname);
114   if (!buf_linkname) {
115     reply_with_perror ("malloc");
116     return -1;
117   }
118
119   /* Only prefix target if it's _not_ a symbolic link, and if
120    * the target is absolute.  Note that the resulting link will
121    * always be "broken" from the p.o.v. of the appliance, ie:
122    * /a -> /b but the path as seen here is /sysroot/b
123    */
124   buf_target = NULL;
125   if (!symbolic && target[0] == '/') {
126     buf_target = sysroot_path (target);
127     if (!buf_target) {
128       reply_with_perror ("malloc");
129       free (buf_linkname);
130       return -1;
131     }
132   }
133
134   if (flag)
135     r = command (NULL, &err,
136                  "ln", flag, "--", /* target could begin with '-' */
137                  buf_target ? : target, buf_linkname, NULL);
138   else
139     r = command (NULL, &err,
140                  "ln", "--",
141                  buf_target ? : target, buf_linkname, NULL);
142   free (buf_linkname);
143   free (buf_target);
144   if (r == -1) {
145     reply_with_error ("ln%s%s: %s: %s: %s",
146                       flag ? " " : "",
147                       flag ? : "",
148                       target, linkname, err);
149     free (err);
150     return -1;
151   }
152
153   free (err);
154
155   return 0;
156 }
157
158 int
159 do_ln (const char *target, const char *linkname)
160 {
161   return _link (NULL, 0, target, linkname);
162 }
163
164 int
165 do_ln_f (const char *target, const char *linkname)
166 {
167   return _link ("-f", 0, target, linkname);
168 }
169
170 int
171 do_ln_s (const char *target, const char *linkname)
172 {
173   return _link ("-s", 1, target, linkname);
174 }
175
176 int
177 do_ln_sf (const char *target, const char *linkname)
178 {
179   return _link ("-sf", 1, target, linkname);
180 }