common: Remove readdir
[platform/core/system/storaged.git] / src / block / utils.c
1 /*
2  * storaged
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <time.h>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include <dirent.h>
30 #include <ctype.h>
31 #include <string.h>
32 #include <stdarg.h>
33 #include <errno.h>
34 #include <poll.h>
35 #include <mntent.h>
36 #include <system_info.h>
37 #include <sys/mount.h>
38 #include <sys/time.h>
39 #include "log.h"
40 #include "common.h"
41
42 int print_open_files(const char *mount_point)
43 {
44         DIR *dp;
45         struct dirent entry;
46         struct dirent *dir;
47
48         DIR *dp_child;
49         struct dirent *dir_child;
50
51         int pid = -1, fd;
52         int ret;
53         char buf[PATH_MAX];
54         char buf2[PATH_MAX];
55
56         char cmdline[PATH_MAX];
57         char check_path[PATH_MAX];
58
59         int len = strlen(mount_point);
60
61         dp = opendir("/proc");
62         if (!dp) {
63                 _E("FAIL: open /proc");
64                 return -1;
65         }
66
67         while (1) {
68                 ret = readdir_r(dp, &entry, &dir);
69                 if (dir == NULL)
70                         break;
71                 if (ret != 0)
72                         break;
73
74                 if (!isdigit(dir->d_name[0]))
75                         continue;
76
77                 pid = atoi(dir->d_name);
78                 snprintf(buf, PATH_MAX, "/proc/%d/cmdline", pid);
79
80                 fd = open(buf, O_RDONLY);
81                 if (fd < 0)
82                         continue;
83                 ret = read(fd, cmdline, PATH_MAX);
84                 close(fd);
85
86                 if (ret < 0 || ret >= PATH_MAX)
87                         continue;
88                 cmdline[ret] = '\0';
89
90                 snprintf(buf, PATH_MAX, "/proc/%d/fd", pid);
91                 dp_child = opendir(buf);
92                 if (!dp_child)
93                         continue;
94                 while (1) {
95                         ret = readdir_r(dp, &entry, &dir_child);
96                         if (dir_child == NULL)
97                                 break;
98                         if (ret != 0)
99                                 break;
100
101                         snprintf(check_path, PATH_MAX, "%s/%s", buf, dir_child->d_name);
102
103                         if (readlink(check_path, buf2, PATH_MAX) < 0)
104                                 continue;
105
106                         if (strncmp(buf2, mount_point, len) == 0)
107                                 _D("Process %s : Opened files - %s", cmdline, buf2);
108                 }
109                 closedir(dp_child);
110         }
111
112         closedir(dp);
113         return 0;
114 }
115
116 int terminate_process(const char *partition, bool force)
117 {
118         const char *argv[7] = {"/usr/bin/fuser", "-m", "-k", "-s", NULL, NULL, NULL};
119         int argc;
120
121         if (force)
122                 argv[4] = "-SIGKILL";
123         else
124                 argv[4] = "-SIGTERM";
125         argv[5] = partition;
126         argc = sizeof(argv) / sizeof(argv[0]);
127         return run_child(argc, argv);
128 }
129
130 int mount_check(const char *path)
131 {
132         int ret = false;
133         struct mntent *mnt;
134         const char *table = "/etc/mtab";
135         FILE *fp;
136         int len;
137
138         fp = setmntent(table, "r");
139         if (!fp)
140                 return ret;
141
142         len = strlen(path) + 1;
143         while (1) {
144                 mnt = getmntent(fp);
145                 if (mnt == NULL)
146                         break;
147                 if (!strncmp(mnt->mnt_dir, path, len)) {
148                         ret = true;
149                         break;
150                 }
151         }
152         endmntent(fp);
153         return ret;
154 }
155
156 int umount_partition(const char *path, const bool force)
157 {
158         int retry = 0, ret = -1;
159         struct timespec time = {0,};
160
161         sync();
162         while (ret && retry < 2) {
163                 switch (retry++) {
164                 case 0:
165                         /* Second, kill app with SIGTERM */
166                         _I("Kill app with SIGTERM");
167                         terminate_process(path, false);
168                         time.tv_nsec = 500 * NANO_SECOND_MULTIPLIER;
169                         nanosleep(&time, NULL);
170                         ret = umount2(path, 0);
171                         break;
172                 case 1:
173                         /* Last time, kill app with SIGKILL */
174                         _I("Kill app with SIGKILL");
175                         terminate_process(path, true);
176                         time.tv_nsec = 200 * NANO_SECOND_MULTIPLIER;
177                         nanosleep(&time, NULL);
178                         ret = umount2(path, 0);
179                         break;
180                 }
181                 _I("ret %d retry %d", ret, retry);
182         }
183         if (ret) {
184                 if (force)
185                         ret = umount2(path, MNT_DETACH);
186                 else
187                         ret = umount2(path, 0);
188         }
189         if (ret)
190                 _I("Failed to unmount %s", path);
191         else
192                 _I("%s unmounted successfully", path);
193         return ret;
194 }