4

I have an array of strings in C. These strings store the paths of filesystems that need to be unmounted.

For example...
mountlist[0] = "/proc"
mountlist[1] = "/dev"
mountlist[2] = "/dev/shm"
and so on...

I need to unmount the nested filesystems before the filesystems they are mounted over (so /dev/shm needs to be unmounted before /dev). I was thinking that the easiest way to do this would be to sort the strings by length, longest first. I have the number of strings in the array stored in the integer i.

With the code that I've been able to come up with so far, given that strnum is an integer of the string I need to access, the strings are accessible with mountlist[strnum] and the corresponding length is stored in length[strnum].

In conclusion, how can I sort the strings in array by greatest to least length? I don't need to actually sort the strings, I just need to access them in the right order. I can't figure out how to write it, but I was thinking of code that creates an int array with the number of each string array in the right order (the example above would be {2, 0, 1}), so if that array was named sort then mountlist[sort[0]] would be the longest string. With such an array, the corresponding for loop would be:

for (int q = 0; q < i; q++) {
    umount(mountlist[sort[q]]);
}
Billy
  • 1,177
  • 2
  • 15
  • 35
  • 2
    do you know about `qsort()`? – Fureeish Aug 29 '18 at 13:53
  • @Fureeish No, I'll look it up. – Billy Aug 29 '18 at 13:59
  • If the order is based on the length it may fail. Example: if you have `"/dev/shm"` and `"/somenonnested"`, latter will be unmounted before `"/dev/shm"` because it's length is longer... – Jabberwocky Aug 29 '18 at 14:00
  • Duplicate of https://stackoverflow.com/a/27003340/4288486 ? – João Neto Aug 29 '18 at 14:05
  • @Jabberwocky Good point. I'll probably leave `/dev` in tact, now that I think about it. – Billy Aug 29 '18 at 14:07
  • You should probably take into account the number of `/` characters rather than the string length. But the sorting problems itself remains the same. If you have more than 2 nesting levels you may need to build a tree and unmount the leaves bottum up. – Jabberwocky Aug 29 '18 at 14:08
  • Usually, sorting the names in reverse order gives you the result you require. – Jonathan Leffler Aug 29 '18 at 14:17
  • 2
    `"/path"` will always be lexicographically less than `"/path/contained"` where `/path` is a directory, and `contained` is something in that directory. So it is not necessary to sort by string length - sorting in reverse-lexicographical order will be sufficient – Peter Aug 29 '18 at 14:24
  • Can you record the path names in the array in the sequence of mounting, and then unmount in reverse order? – Weather Vane Aug 29 '18 at 14:27
  • @WeatherVane No, this program is only responsible for unmounting, not mounting. – Billy Aug 29 '18 at 15:23
  • @jabberwocky: if you have `/foo/bar`, `/foo` and `/unrelatedlongname`, why would it be a problem if the last one were unmounted first? The only order dependence is between the first two. – rici Aug 29 '18 at 15:26
  • @rici I think that @jabberwocky was pointing out that certain long paths are probably dependent on `/dev` (i.e. block devices), but I decided not to unmount `/dev` so you're right, it won't be a problem. – Billy Aug 29 '18 at 15:28
  • @billy: although I wouldn't recommend unmounting `/dev`, there is no dependency. Devices don't exist because they are in `/dev`. The devices are there, regardless. `/dev` lets you refer to them, nothing more. – rici Aug 29 '18 at 15:33
  • @rici Good to know. I always wondered about that, since `/` can't be unmounted I thought that must have meant that `/dev` couldn't have been either. – Billy Aug 29 '18 at 21:17
  • @billy: actually you can unmount the filesystem mounted on `/`, but that doesn't make `/` go away. If you were to unmount `/dev`, you'd probably find that there still is a `/dev`, which will be an ordinary (and probably empty) directory in the root filesystem. – rici Aug 29 '18 at 23:08
  • Of course, to unmount the root filesystem, you'd first have to make sure no process was using it. That would be tricky. :-) – rici Aug 29 '18 at 23:09

2 Answers2

3

You can just use qsort with a custom comparator:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int cmp(const void *first, const void *second) { 
    const char **firstCast = (const char ** )first;
    const char **secondCast = (const char **) second;
    return strcmp(*secondCast, *firstCast);
}
int main(void) {
    const char *a[3];
    a[0] = "longest";
    a[1] = "short";
    a[2] = "medium";
    qsort(a, 3, sizeof(char *), cmp);
    for (int i = 0 ; i < 3; i++) {
        printf("%s\n", a[i]);
    }
}
Ahmed Agiza
  • 360
  • 1
  • 7
  • He wants the sorting based on string lengths (which may not be the right choice btw, see my comment to the question), not based on string comparision. – Jabberwocky Aug 29 '18 at 14:11
1

If you don't want to depend on anything "external" like qsort, which may or not be available in your environment, this should do it:

for (int j = 0; j < i; ++j) sort[j] = j;

for (int j = 0; j < i - 1; ++j) {
    int longest = j;
    for (int k = j + 1; k < i; ++k) {
        if (length[sort[k]] > length[sort[longest]]) longest = k;
    }
    int tmp = sort[longest];
    sort[longest] = sort[j];
    sort[j] = tmp;
}
  • qsort is included in the [C standard](https://port70.net/~nsz/c/c11/n1570.html#7.22.5.2) so there is no question about it being available. – rici Aug 29 '18 at 15:23