pkg_alternatives: pass if the desired symlink already exists
[project/opkg-lede.git] / libopkg / pkg_alternatives.c
index 890b510669374350f288d5e58c42a0f4102adea4..50e9d128ef20b6bda30ed6e7129e82ad79cdec44 100644 (file)
 #include <stdio.h>
 #include <sys/types.h>         /* stat */
 #include <sys/stat.h>
+#include <libgen.h>                    /* dirname */
 #include <unistd.h>
 
+#include "file_util.h"
 #include "libbb/libbb.h"
 #include "opkg_message.h"
 #include "pkg.h"
@@ -76,9 +78,27 @@ static int pkg_alternatives_update_path(pkg_t *pkg, const pkg_vec_t *installed,
                } else if (errno != ENOENT) {
                        goto out;
                }
-               r = symlink(the_alt->altpath, path_in_dest);
-               if (r)
-                       opkg_msg(ERROR, "failed symlinking %s -> %s\n", path_in_dest, the_alt->altpath);
+               {
+                       char *path_copy = xstrdup(path_in_dest);
+                       char *path_parent = dirname(path_copy);
+
+                       r = file_mkdir_hier(path_parent, 0755);
+                       free(path_copy);
+                       if (r) {
+                               goto out;
+                       }
+                       r = symlink(the_alt->altpath, path_in_dest);
+                       if (r && errno == EEXIST) {
+                               /*
+                                * the strcmp & unlink check above will make sure that if EEXIST
+                                * happens, the symlink target also matches
+                                */
+                               r = 0;
+                       }
+                       if (r) {
+                               opkg_perror(ERROR, "failed symlinking %s -> %s", path_in_dest, the_alt->altpath);
+                       }
+               }
        } else {
                unlink(path_in_dest);
                r = 0;