summaryrefslogtreecommitdiff
path: root/src/misc/s6-linux-init-umountall.c
blob: 24b22fc90fa60eaf2bbbac2a6edb2ab4ee679c4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/* ISC license. */

#include <string.h>
#include <sys/mount.h>

#include <skalibs/bytestr.h>
#include <skalibs/buffer.h>
#include <skalibs/strerr2.h>
#include <skalibs/stralloc.h>
#include <skalibs/djbunix.h>
#include <skalibs/skamisc.h>

#define BUFSIZE 4096
#define MAXLINES 512

int main (int argc, char const *const *argv)
{
  stralloc mountpoints[MAXLINES] ;
  char buf[BUFSIZE] ;
  buffer b ;
  stralloc sa = STRALLOC_ZERO ;
  unsigned int line = 0 ;
  int e = 0 ;
  int r ;
  int fd ;

  PROG = "s6-linux-init-umountall" ;


 /*
    We need to go through /proc/mounts *in reverse order*, because later mounts
    may depend on earlier mounts.
    The getmntent() family of functions has obviously not been designed for that
    use case at all, and it is actually more difficult to use it than to do the
    /proc/mounts parsing by hand. So, we do it by hand with skalibs functions.
    That's how you can tell a good API from a terrible one.
 */

  fd = open_readb("/proc/mounts") ;
  if (fd < 0) strerr_diefu1sys(111, "open /proc/mounts") ;
  memset(mountpoints, 0, sizeof(mountpoints)) ;
  buffer_init(&b, &buffer_read, fd, buf, BUFSIZE) ;
  for (;;)
  {
    size_t n, p ;
    if (line >= MAXLINES) strerr_dief1x(111, "/proc/mounts too big") ;
    sa.len = 0 ;
    r = skagetln(&b, &sa, '\n') ;
    if (r <= 0) break ;
    p = byte_chr(sa.s, sa.len, ' ') ;
    if (p >= sa.len) strerr_dief1x(111, "bad /proc/mounts format") ;
    p++ ;
    n = byte_chr(sa.s + p, sa.len - p, ' ') ;
    if (n == sa.len - p) strerr_dief1x(111, "bad /proc/mounts format") ;
    if (!stralloc_catb(&mountpoints[line], sa.s + p, n) || !stralloc_0(&mountpoints[line]))
      strerr_diefu1sys(111, "store mount point") ;
    line++ ;
  }
  fd_close(fd) ;
  stralloc_free(&sa) ;
  if (r < 0) strerr_diefu1sys(111, "read /proc/mounts") ;

  while (line--)
    if (umount(mountpoints[line].s) == -1)
    {
      e++ ;
      strerr_warnwu2sys("umount ", mountpoints[line].s) ;
    }
  return e ;
}