]>
git.ipfire.org Git - thirdparty/systemd.git/blob - udev/udev-util.c
2 * Copyright (C) 2004-2008 Kay Sievers <kay.sievers@vrfy.org>
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.
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.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
32 int util_create_path(struct udev
*udev
, const char *path
)
34 char p
[UTIL_PATH_SIZE
];
39 util_strlcpy(p
, path
, sizeof(p
));
40 pos
= strrchr(p
, '/');
41 if (pos
== p
|| pos
== NULL
)
44 while (pos
[-1] == '/')
48 dbg(udev
, "stat '%s'\n", p
);
49 if (stat(p
, &stats
) == 0 && (stats
.st_mode
& S_IFMT
) == S_IFDIR
)
52 if (util_create_path(udev
, p
) != 0)
55 dbg(udev
, "mkdir '%s'\n", p
);
56 udev_selinux_setfscreatecon(udev
, p
, S_IFDIR
|0755);
58 udev_selinux_resetfscreatecon(udev
);
63 if (stat(p
, &stats
) == 0 && (stats
.st_mode
& S_IFMT
) == S_IFDIR
)
68 int util_delete_path(struct udev
*udev
, const char *path
)
70 char p
[UTIL_PATH_SIZE
];
75 pos
= strrchr(p
, '/');
76 if (pos
== p
|| pos
== NULL
)
81 pos
= strrchr(p
, '/');
83 /* don't remove the last one */
84 if ((pos
== p
) || (pos
== NULL
))
92 if (errno
== ENOTEMPTY
)
94 err(udev
, "rmdir(%s) failed: %m\n", p
);
97 dbg(udev
, "removed '%s'\n", p
);
102 /* Reset permissions on the device node, before unlinking it to make sure,
103 * that permisions of possible hard links will be removed too.
105 int util_unlink_secure(struct udev
*udev
, const char *filename
)
109 retval
= chown(filename
, 0, 0);
111 err(udev
, "chown(%s, 0, 0) failed: %m\n", filename
);
113 retval
= chmod(filename
, 0000);
115 err(udev
, "chmod(%s, 0000) failed: %m\n", filename
);
117 retval
= unlink(filename
);
122 err(udev
, "unlink(%s) failed: %m\n", filename
);
127 uid_t
util_lookup_user(struct udev
*udev
, const char *user
)
135 if (errno
== 0 || errno
== ENOENT
|| errno
== ESRCH
)
136 err(udev
, "specified user '%s' unknown\n", user
);
138 err(udev
, "error resolving user '%s': %m\n", user
);
145 extern gid_t
util_lookup_group(struct udev
*udev
, const char *group
)
151 gr
= getgrnam(group
);
153 if (errno
== 0 || errno
== ENOENT
|| errno
== ESRCH
)
154 err(udev
, "specified group '%s' unknown\n", group
);
156 err(udev
, "error resolving group '%s': %m\n", group
);
163 int util_run_program(struct udev
*udev
, const char *command
, char **envp
,
164 char *result
, size_t ressize
, size_t *reslen
)
167 int outpipe
[2] = {-1, -1};
168 int errpipe
[2] = {-1, -1};
170 char arg
[UTIL_PATH_SIZE
];
171 char program
[UTIL_PATH_SIZE
];
172 char *argv
[(sizeof(arg
) / 2) + 1];
177 /* build argv from command */
178 util_strlcpy(arg
, command
, sizeof(arg
));
180 if (strchr(arg
, ' ') != NULL
) {
183 while (pos
!= NULL
&& pos
[0] != '\0') {
184 if (pos
[0] == '\'') {
185 /* do not separate quotes */
187 argv
[i
] = strsep(&pos
, "\'");
188 while (pos
!= NULL
&& pos
[0] == ' ')
191 argv
[i
] = strsep(&pos
, " ");
193 dbg(udev
, "arg[%i] '%s'\n", i
, argv
[i
]);
201 info(udev
, "'%s'\n", command
);
203 /* prepare pipes from child to parent */
204 if (result
!= NULL
|| udev_get_log_priority(udev
) >= LOG_INFO
) {
205 if (pipe(outpipe
) != 0) {
206 err(udev
, "pipe failed: %m\n");
210 if (udev_get_log_priority(udev
) >= LOG_INFO
) {
211 if (pipe(errpipe
) != 0) {
212 err(udev
, "pipe failed: %m\n");
217 /* allow programs in /lib/udev/ to be called without the path */
218 if (strchr(argv
[0], '/') == NULL
) {
219 util_strlcpy(program
, UDEV_PREFIX
"/lib/udev/", sizeof(program
));
220 util_strlcat(program
, argv
[0], sizeof(program
));
227 /* child closes parent ends of pipes */
228 if (outpipe
[READ_END
] > 0)
229 close(outpipe
[READ_END
]);
230 if (errpipe
[READ_END
] > 0)
231 close(errpipe
[READ_END
]);
233 /* discard child output or connect to pipe */
234 devnull
= open("/dev/null", O_RDWR
);
236 dup2(devnull
, STDIN_FILENO
);
237 if (outpipe
[WRITE_END
] < 0)
238 dup2(devnull
, STDOUT_FILENO
);
239 if (errpipe
[WRITE_END
] < 0)
240 dup2(devnull
, STDERR_FILENO
);
243 err(udev
, "open /dev/null failed: %m\n");
244 if (outpipe
[WRITE_END
] > 0) {
245 dup2(outpipe
[WRITE_END
], STDOUT_FILENO
);
246 close(outpipe
[WRITE_END
]);
248 if (errpipe
[WRITE_END
] > 0) {
249 dup2(errpipe
[WRITE_END
], STDERR_FILENO
);
250 close(errpipe
[WRITE_END
]);
252 execve(argv
[0], argv
, envp
);
253 if (errno
== ENOENT
|| errno
== ENOTDIR
) {
254 /* may be on a filesytem which is not mounted right now */
255 info(udev
, "program '%s' not found\n", argv
[0]);
258 err(udev
, "exec of program '%s' failed\n", argv
[0]);
262 err(udev
, "fork of '%s' failed: %m\n", argv
[0]);
265 /* read from child if requested */
266 if (outpipe
[READ_END
] > 0 || errpipe
[READ_END
] > 0) {
270 /* parent closes child ends of pipes */
271 if (outpipe
[WRITE_END
] > 0)
272 close(outpipe
[WRITE_END
]);
273 if (errpipe
[WRITE_END
] > 0)
274 close(errpipe
[WRITE_END
]);
276 /* read child output */
277 while (outpipe
[READ_END
] > 0 || errpipe
[READ_END
] > 0) {
282 if (outpipe
[READ_END
] > 0)
283 FD_SET(outpipe
[READ_END
], &readfds
);
284 if (errpipe
[READ_END
] > 0)
285 FD_SET(errpipe
[READ_END
], &readfds
);
286 fdcount
= select(UDEV_MAX(outpipe
[READ_END
], errpipe
[READ_END
])+1, &readfds
, NULL
, NULL
, NULL
);
295 if (outpipe
[READ_END
] > 0 && FD_ISSET(outpipe
[READ_END
], &readfds
)) {
300 count
= read(outpipe
[READ_END
], inbuf
, sizeof(inbuf
)-1);
302 close(outpipe
[READ_END
]);
303 outpipe
[READ_END
] = -1;
305 err(udev
, "stdin read failed: %m\n");
312 /* store result for rule processing */
314 if (respos
+ count
< ressize
) {
315 memcpy(&result
[respos
], inbuf
, count
);
318 err(udev
, "ressize %ld too short\n", (long)ressize
);
323 while ((line
= strsep(&pos
, "\n")))
324 if (pos
|| line
[0] != '\0')
325 info(udev
, "'%s' (stdout) '%s'\n", argv
[0], line
);
329 if (errpipe
[READ_END
] > 0 && FD_ISSET(errpipe
[READ_END
], &readfds
)) {
334 count
= read(errpipe
[READ_END
], errbuf
, sizeof(errbuf
)-1);
336 close(errpipe
[READ_END
]);
337 errpipe
[READ_END
] = -1;
339 err(udev
, "stderr read failed: %m\n");
342 errbuf
[count
] = '\0';
344 while ((line
= strsep(&pos
, "\n")))
345 if (pos
|| line
[0] != '\0')
346 info(udev
, "'%s' (stderr) '%s'\n", argv
[0], line
);
349 if (outpipe
[READ_END
] > 0)
350 close(outpipe
[READ_END
]);
351 if (errpipe
[READ_END
] > 0)
352 close(errpipe
[READ_END
]);
354 /* return the childs stdout string */
356 result
[respos
] = '\0';
357 dbg(udev
, "result='%s'\n", result
);
362 waitpid(pid
, &status
, 0);
363 if (WIFEXITED(status
)) {
364 info(udev
, "'%s' returned with status %i\n", argv
[0], WEXITSTATUS(status
));
365 if (WEXITSTATUS(status
) != 0)
368 err(udev
, "'%s' abnormal exit\n", argv
[0]);