mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-22 07:03:38 +00:00
daemon: Reimplement ‘file’ API in OCaml.
‘file’ is a small, self-contained API which runs a single command, so it's a good test case for reimplementing APIs.
This commit is contained in:
@@ -243,6 +243,7 @@ guestfsd_CFLAGS = \
|
||||
SOURCES_MLI = \
|
||||
chroot.mli \
|
||||
sysroot.mli \
|
||||
file.mli \
|
||||
utils.mli
|
||||
|
||||
SOURCES_ML = \
|
||||
@@ -252,6 +253,7 @@ SOURCES_ML = \
|
||||
optgroups.ml \
|
||||
sysroot.ml \
|
||||
chroot.ml \
|
||||
file.ml \
|
||||
callbacks.ml \
|
||||
daemon.ml
|
||||
|
||||
|
||||
@@ -445,85 +445,6 @@ do_pwrite_device (const char *device, const char *content, size_t size,
|
||||
return pwrite_fd (fd, content, size, offset, device, 1);
|
||||
}
|
||||
|
||||
/* This runs the 'file' command. */
|
||||
char *
|
||||
do_file (const char *path)
|
||||
{
|
||||
CLEANUP_FREE char *buf = NULL;
|
||||
const char *display_path = path;
|
||||
const int is_dev = STRPREFIX (path, "/dev/");
|
||||
struct stat statbuf;
|
||||
|
||||
if (!is_dev) {
|
||||
buf = sysroot_path (path);
|
||||
if (!buf) {
|
||||
reply_with_perror ("malloc");
|
||||
return NULL;
|
||||
}
|
||||
path = buf;
|
||||
|
||||
/* For non-dev, check this is a regular file, else just return the
|
||||
* file type as a string (RHBZ#582484).
|
||||
*/
|
||||
if (lstat (path, &statbuf) == -1) {
|
||||
reply_with_perror ("lstat: %s", display_path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (! S_ISREG (statbuf.st_mode)) {
|
||||
char *ret;
|
||||
|
||||
if (S_ISDIR (statbuf.st_mode))
|
||||
ret = strdup ("directory");
|
||||
else if (S_ISCHR (statbuf.st_mode))
|
||||
ret = strdup ("character device");
|
||||
else if (S_ISBLK (statbuf.st_mode))
|
||||
ret = strdup ("block device");
|
||||
else if (S_ISFIFO (statbuf.st_mode))
|
||||
ret = strdup ("FIFO");
|
||||
else if (S_ISLNK (statbuf.st_mode))
|
||||
ret = strdup ("symbolic link");
|
||||
else if (S_ISSOCK (statbuf.st_mode))
|
||||
ret = strdup ("socket");
|
||||
else
|
||||
ret = strdup ("unknown, not regular file");
|
||||
|
||||
if (ret == NULL)
|
||||
reply_with_perror ("strdup");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Which flags to use? For /dev paths, follow links because
|
||||
* /dev/VG/LV is a symbolic link.
|
||||
*/
|
||||
const char *flags = is_dev ? "-zbsL" : "-zb";
|
||||
|
||||
char *out;
|
||||
CLEANUP_FREE char *err = NULL;
|
||||
int r = command (&out, &err, "file", flags, path, NULL);
|
||||
|
||||
if (r == -1) {
|
||||
free (out);
|
||||
reply_with_error ("%s: %s", display_path, err);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* We need to remove the trailing \n from output of file(1). */
|
||||
size_t len = strlen (out);
|
||||
if (len > 0 && out[len-1] == '\n')
|
||||
out[--len] = '\0';
|
||||
|
||||
/* Some upstream versions of file add a space at the end of the
|
||||
* output. This is fixed in the Fedora version, but we might as
|
||||
* well fix it here too. (RHBZ#928995).
|
||||
*/
|
||||
if (len > 0 && out[len-1] == ' ')
|
||||
out[--len] = '\0';
|
||||
|
||||
return out; /* caller frees */
|
||||
}
|
||||
|
||||
/* zcat | file */
|
||||
char *
|
||||
do_zfile (const char *method, const char *path)
|
||||
|
||||
59
daemon/file.ml
Normal file
59
daemon/file.ml
Normal file
@@ -0,0 +1,59 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2017 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*)
|
||||
|
||||
open Unix
|
||||
open Printf
|
||||
|
||||
open Std_utils
|
||||
|
||||
open Utils
|
||||
|
||||
(* This runs the [file] command. *)
|
||||
let file path =
|
||||
let is_dev = String.is_prefix path "/dev/" in
|
||||
|
||||
(* For non-dev, check this is a regular file, else just return the
|
||||
* file type as a string (RHBZ#582484).
|
||||
*)
|
||||
if not is_dev then (
|
||||
let chroot = Chroot.create ~name:(sprintf "file: %s" path) () in
|
||||
|
||||
let statbuf = Chroot.f chroot lstat path in
|
||||
match statbuf.st_kind with
|
||||
| S_DIR -> "directory"
|
||||
| S_CHR -> "character device"
|
||||
| S_BLK -> "block device"
|
||||
| S_FIFO -> "FIFO"
|
||||
| S_LNK -> "symbolic link"
|
||||
| S_SOCK -> "socket"
|
||||
| S_REG ->
|
||||
(* Regular file, so now run [file] on it. *)
|
||||
let out = command "file" ["-zb"; Sysroot.sysroot_path path] in
|
||||
|
||||
(* We need to remove the trailing \n from output of file(1).
|
||||
*
|
||||
* Some upstream versions of file add a space at the end of the
|
||||
* output. This is fixed in the Fedora version, but we might as
|
||||
* well fix it here too. (RHBZ#928995).
|
||||
*)
|
||||
String.trimr out
|
||||
)
|
||||
else (* it's a device *) (
|
||||
let out = command "file" ["-zbsL"; path] in
|
||||
String.trimr out
|
||||
)
|
||||
19
daemon/file.mli
Normal file
19
daemon/file.mli
Normal file
@@ -0,0 +1,19 @@
|
||||
(* guestfs-inspection
|
||||
* Copyright (C) 2009-2017 Red Hat Inc.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*)
|
||||
|
||||
val file : string -> string
|
||||
@@ -2321,6 +2321,7 @@ and physical volumes." };
|
||||
{ defaults with
|
||||
name = "file"; added = (1, 9, 1);
|
||||
style = RString (RPlainString, "description"), [String (Dev_or_Path, "path")], [];
|
||||
impl = OCaml "File.file";
|
||||
tests = [
|
||||
InitISOFS, Always, TestResultString (
|
||||
[["file"; "/empty"]], "empty"), [];
|
||||
|
||||
Reference in New Issue
Block a user