diff options
Diffstat (limited to 'e2fsprogs')
-rw-r--r-- | e2fsprogs/README | 3 | ||||
-rw-r--r-- | e2fsprogs/chattr.c | 305 | ||||
-rw-r--r-- | e2fsprogs/e2fsbb.h | 38 | ||||
-rw-r--r-- | e2fsprogs/e2p/README | 4 | ||||
-rw-r--r-- | e2fsprogs/e2p/e2p.h | 52 | ||||
-rw-r--r-- | e2fsprogs/e2p/feature.c | 190 | ||||
-rw-r--r-- | e2fsprogs/e2p/fgetflags.c | 92 | ||||
-rw-r--r-- | e2fsprogs/e2p/fgetversion.c | 62 | ||||
-rw-r--r-- | e2fsprogs/e2p/fsetflags.c | 96 | ||||
-rw-r--r-- | e2fsprogs/e2p/fsetversion.c | 60 | ||||
-rw-r--r-- | e2fsprogs/e2p/getflags.c | 66 | ||||
-rw-r--r-- | e2fsprogs/e2p/getversion.c | 37 | ||||
-rw-r--r-- | e2fsprogs/e2p/hashstr.c | 70 | ||||
-rw-r--r-- | e2fsprogs/e2p/iod.c | 72 | ||||
-rw-r--r-- | e2fsprogs/e2p/ls.c | 276 | ||||
-rw-r--r-- | e2fsprogs/e2p/mntopts.c | 136 | ||||
-rw-r--r-- | e2fsprogs/e2p/ostype.c | 73 | ||||
-rw-r--r-- | e2fsprogs/e2p/parse_num.c | 64 | ||||
-rw-r--r-- | e2fsprogs/e2p/pe.c | 37 | ||||
-rw-r--r-- | e2fsprogs/e2p/pf.c | 74 | ||||
-rw-r--r-- | e2fsprogs/e2p/ps.c | 29 | ||||
-rw-r--r-- | e2fsprogs/e2p/setflags.c | 72 | ||||
-rw-r--r-- | e2fsprogs/e2p/setversion.c | 36 | ||||
-rw-r--r-- | e2fsprogs/e2p/uuid.c | 79 | ||||
-rw-r--r-- | e2fsprogs/lsattr.c | 193 |
25 files changed, 2216 insertions, 0 deletions
diff --git a/e2fsprogs/README b/e2fsprogs/README new file mode 100644 index 000000000..fac090193 --- /dev/null +++ b/e2fsprogs/README @@ -0,0 +1,3 @@ +This is a pretty straight rip from the e2fsprogs pkg. + +See README's in subdirs for specific info. diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c new file mode 100644 index 000000000..7abc83176 --- /dev/null +++ b/e2fsprogs/chattr.c @@ -0,0 +1,305 @@ +/* + * chattr.c - Change file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + * 93/11/13 - Replace stat() calls by lstat() to avoid loops + * 94/02/27 - Integrated in Ted's distribution + * 98/12/29 - Ignore symlinks when working recursively (G M Sipe) + * 98/12/29 - Display version info only when -V specified (G M Sipe) + */ + +#include <sys/types.h> +#include <dirent.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <ext2fs/ext2_fs.h> + +#ifdef __GNUC__ +#define EXT2FS_ATTR(x) __attribute__(x) +#else +#define EXT2FS_ATTR(x) +#endif + +#ifndef S_ISLNK /* So we can compile even with gcc-warn */ +# ifdef __S_IFLNK +# define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK) +# else +# define S_ISLNK(mode) 0 +# endif +#endif + +#include "e2fsbb.h" +#include "e2p/e2p.h" + +static int add; +static int rem; +static int set; +static int set_version; + +static unsigned long version; + +static int recursive; +static int verbose; + +static unsigned long af; +static unsigned long rf; +static unsigned long sf; + +#ifdef _LFS64_LARGEFILE +#define LSTAT lstat64 +#define STRUCT_STAT struct stat64 +#else +#define LSTAT lstat +#define STRUCT_STAT struct stat +#endif + +#if 0 +static void fatal_error(const char * fmt_string, int errcode) +{ + fprintf (stderr, fmt_string, program_name); + exit (errcode); +} + +#define usage() fatal_error(_("usage: %s [-RV] [-+=AacDdijsSu] [-v version] files...\n"), \ + 1) +#endif + +struct flags_char { + unsigned long flag; + char optchar; +}; + +static const struct flags_char flags_array[] = { + { EXT2_NOATIME_FL, 'A' }, + { EXT2_SYNC_FL, 'S' }, + { EXT2_DIRSYNC_FL, 'D' }, + { EXT2_APPEND_FL, 'a' }, + { EXT2_COMPR_FL, 'c' }, + { EXT2_NODUMP_FL, 'd' }, + { EXT2_IMMUTABLE_FL, 'i' }, + { EXT3_JOURNAL_DATA_FL, 'j' }, + { EXT2_SECRM_FL, 's' }, + { EXT2_UNRM_FL, 'u' }, + { EXT2_NOTAIL_FL, 't' }, + { EXT2_TOPDIR_FL, 'T' }, + { 0, 0 } +}; + +static unsigned long get_flag(char c) +{ + const struct flags_char *fp; + + for (fp = flags_array; fp->flag != 0; fp++) { + if (fp->optchar == c) + return fp->flag; + } + return 0; +} + + +static int decode_arg (int * i, int argc, char ** argv) +{ + char * p; + char * tmp; + unsigned long fl; + + switch (argv[*i][0]) + { + case '-': + for (p = &argv[*i][1]; *p; p++) { + if (*p == 'R') { + recursive = 1; + continue; + } + if (*p == 'V') { + verbose = 1; + continue; + } + if (*p == 'v') { + (*i)++; + if (*i >= argc) + usage (); + version = strtol (argv[*i], &tmp, 0); + if (*tmp) { + com_err (program_name, 0, + _("bad version - %s\n"), + argv[*i]); + usage (); + } + set_version = 1; + continue; + } + if ((fl = get_flag(*p)) == 0) + usage(); + rf |= fl; + rem = 1; + } + break; + case '+': + add = 1; + for (p = &argv[*i][1]; *p; p++) { + if ((fl = get_flag(*p)) == 0) + usage(); + af |= fl; + } + break; + case '=': + set = 1; + for (p = &argv[*i][1]; *p; p++) { + if ((fl = get_flag(*p)) == 0) + usage(); + sf |= fl; + } + break; + default: + return EOF; + break; + } + return 1; +} + +static int chattr_dir_proc (const char *, struct dirent *, void *); + +static void change_attributes (const char * name) +{ + unsigned long flags; + STRUCT_STAT st; + + if (LSTAT (name, &st) == -1) { + com_err (program_name, errno, _("while trying to stat %s"), + name); + return; + } + if (S_ISLNK(st.st_mode) && recursive) + return; + + /* Don't try to open device files, fifos etc. We probably + ought to display an error if the file was explicitly given + on the command line (whether or not recursive was + requested). */ + if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && + !S_ISDIR(st.st_mode)) + return; + + if (set) { + if (verbose) { + printf (_("Flags of %s set as "), name); + print_flags (stdout, sf, 0); + printf ("\n"); + } + if (fsetflags (name, sf) == -1) + perror (name); + } else { + if (fgetflags (name, &flags) == -1) + com_err (program_name, errno, + _("while reading flags on %s"), name); + else { + if (rem) + flags &= ~rf; + if (add) + flags |= af; + if (verbose) { + printf (_("Flags of %s set as "), name); + print_flags (stdout, flags, 0); + printf ("\n"); + } + if (!S_ISDIR(st.st_mode)) + flags &= ~EXT2_DIRSYNC_FL; + if (fsetflags (name, flags) == -1) + com_err (program_name, errno, + _("while setting flags on %s"), name); + } + } + if (set_version) { + if (verbose) + printf (_("Version of %s set as %lu\n"), name, version); + if (fsetversion (name, version) == -1) + com_err (program_name, errno, + _("while setting version on %s"), name); + } + if (S_ISDIR(st.st_mode) && recursive) + iterate_on_dir (name, chattr_dir_proc, NULL); +} + +static int chattr_dir_proc (const char * dir_name, struct dirent * de, + void * private EXT2FS_ATTR((unused))) +{ + if (strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) { + char *path; + + path = malloc(strlen (dir_name) + 1 + strlen (de->d_name) + 1); + if (!path) + fatal_error(_("Couldn't allocate path variable " + "in chattr_dir_proc"), 1); + sprintf (path, "%s/%s", dir_name, de->d_name); + change_attributes (path); + free(path); + } + return 0; +} + +int chattr_main (int argc, char ** argv) +{ + int i, j; + int end_arg = 0; + +#ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); + setlocale(LC_CTYPE, ""); + bindtextdomain(NLS_CAT_NAME, LOCALEDIR); + textdomain(NLS_CAT_NAME); +#endif +#if 0 + if (argc && *argv) + program_name = *argv; +#endif + i = 1; + while (i < argc && !end_arg) { + /* '--' arg should end option processing */ + if (strcmp(argv[i], "--") == 0) { + i++; + end_arg = 1; + } else if (decode_arg (&i, argc, argv) == EOF) + end_arg = 1; + else + i++; + } + if (i >= argc) + usage (); + if (set && (add || rem)) { + fputs(_("= is incompatible with - and +\n"), stderr); + exit (1); + } + if ((rf & af) != 0) { + fputs("Can't both set and unset same flag.\n", stderr); + exit (1); + } + if (!(add || rem || set || set_version)) { + fputs(_("Must use '-v', =, - or +\n"), stderr); + exit (1); + } +#if 0 + if (verbose) + fprintf (stderr, "chattr %s (%s)\n", + E2FSPROGS_VERSION, E2FSPROGS_DATE); +#endif + for (j = i; j < argc; j++) + change_attributes (argv[j]); + exit(0); +} diff --git a/e2fsprogs/e2fsbb.h b/e2fsprogs/e2fsbb.h new file mode 100644 index 000000000..358cfe099 --- /dev/null +++ b/e2fsprogs/e2fsbb.h @@ -0,0 +1,38 @@ +/* + * File: e2fsbb.h + * + * Redefine a bunch of e2fsprogs stuff to use busybox routines + * instead. This makes upgrade between e2fsprogs versions easy. + */ + +#ifndef __E2FSBB_H__ +#define __E2FSBB_H__ 1 + +#include "libbb.h" + +/* version we've last synced against */ +#define E2FSPROGS_VERSION "1.37" +#define E2FSPROGS_DATE "21-Mar-2005" + +/* make sure com_err.h isnt included before us */ +#ifdef __COM_ERR_H__ +#error You should not have included com_err.h ! +#endif +#define __COM_ERR_H__ + +/* com_err crap */ +#define com_err(w, c, fmt, args...) bb_error_msg(fmt, ## args) +typedef long errcode_t; +#define ERRCODE_RANGE 8 +#define error_message(code) strerror((int) (code & ((1<<ERRCODE_RANGE)-1))) + +/* NLS crap */ +#define _(x) x + +/* misc crap */ +#define fputs(msg, fd) bb_error_msg(msg) +#define fatal_error(msg, err) bb_error_msg_and_die(msg) +#define usage() bb_show_usage() +#define perror(msg) bb_perror_msg(msg) + +#endif /* __E2FSBB_H__ */ diff --git a/e2fsprogs/e2p/README b/e2fsprogs/e2p/README new file mode 100644 index 000000000..769947340 --- /dev/null +++ b/e2fsprogs/e2p/README @@ -0,0 +1,4 @@ +Simply copy the 'e2p' dir from e2fsprogs/lib/ and then delete the extra +files we don't need (Makefile.in, e2p.pc.in, etc...). Remove all of the +_LARGEFILE* define's from the few source files that use it since we'll be +appending it ourselves to CFLAGS when we compile. All done ! :) diff --git a/e2fsprogs/e2p/e2p.h b/e2fsprogs/e2p/e2p.h new file mode 100644 index 000000000..d208b46a8 --- /dev/null +++ b/e2fsprogs/e2p/e2p.h @@ -0,0 +1,52 @@ +#include <sys/types.h> /* Needed by dirent.h on netbsd */ +#include <stdio.h> +#include <dirent.h> + +#include <ext2fs/ext2_fs.h> + +#define E2P_FEATURE_COMPAT 0 +#define E2P_FEATURE_INCOMPAT 1 +#define E2P_FEATURE_RO_INCOMPAT 2 + + +/* `options' for print_flags() */ + +#define PFOPT_LONG 1 /* Must be 1 for compatibility with `int long_format'. */ + + +int fgetflags (const char * name, unsigned long * flags); +int fgetversion (const char * name, unsigned long * version); +int fsetflags (const char * name, unsigned long flags); +int fsetversion (const char * name, unsigned long version); +int getflags (int fd, unsigned long * flags); +int getversion (int fd, unsigned long * version); +int iterate_on_dir (const char * dir_name, + int (*func) (const char *, struct dirent *, void *), + void * private); +void list_super(struct ext2_super_block * s); +void list_super2(struct ext2_super_block * s, FILE *f); +void print_fs_errors (FILE * f, unsigned short errors); +void print_flags (FILE * f, unsigned long flags, unsigned options); +void print_fs_state (FILE * f, unsigned short state); +int setflags (int fd, unsigned long flags); +int setversion (int fd, unsigned long version); + +const char *e2p_feature2string(int compat, unsigned int mask); +int e2p_string2feature(char *string, int *compat, unsigned int *mask); +int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array); + +int e2p_is_null_uuid(void *uu); +void e2p_uuid_to_str(void *uu, char *out); +const char *e2p_uuid2str(void *uu); + +const char *e2p_hash2string(int num); +int e2p_string2hash(char *string); + +const char *e2p_mntopt2string(unsigned int mask); +int e2p_string2mntopt(char *string, unsigned int *mask); +int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok); + +unsigned long parse_num_blocks(const char *arg, int log_block_size); + +char *e2p_os2string(int os_type); +int e2p_string2os(char *str); diff --git a/e2fsprogs/e2p/feature.c b/e2fsprogs/e2p/feature.c new file mode 100644 index 000000000..ef11d93b7 --- /dev/null +++ b/e2fsprogs/e2p/feature.c @@ -0,0 +1,190 @@ +/* + * feature.c --- convert between features and strings + * + * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "e2p.h" + +struct feature { + int compat; + unsigned int mask; + const char *string; +}; + +static struct feature feature_list[] = { + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_PREALLOC, + "dir_prealloc" }, + { E2P_FEATURE_COMPAT, EXT3_FEATURE_COMPAT_HAS_JOURNAL, + "has_journal" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_IMAGIC_INODES, + "imagic_inodes" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_EXT_ATTR, + "ext_attr" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, + "dir_index" }, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, + "resize_inode" }, + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, + "sparse_super" }, + { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_LARGE_FILE, + "large_file" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_COMPRESSION, + "compression" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_FILETYPE, + "filetype" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_RECOVER, + "needs_recovery" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_JOURNAL_DEV, + "journal_dev" }, + { E2P_FEATURE_INCOMPAT, EXT3_FEATURE_INCOMPAT_EXTENTS, + "extents" }, + { E2P_FEATURE_INCOMPAT, EXT2_FEATURE_INCOMPAT_META_BG, + "meta_bg" }, + { 0, 0, 0 }, +}; + +const char *e2p_feature2string(int compat, unsigned int mask) +{ + struct feature *f; + static char buf[20]; + char fchar; + int fnum; + + for (f = feature_list; f->string; f++) { + if ((compat == f->compat) && + (mask == f->mask)) + return f->string; + } + switch (compat) { + case E2P_FEATURE_COMPAT: + fchar = 'C'; + break; + case E2P_FEATURE_INCOMPAT: + fchar = 'I'; + break; + case E2P_FEATURE_RO_INCOMPAT: + fchar = 'R'; + break; + default: + fchar = '?'; + break; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "FEATURE_%c%d", fchar, fnum); + return buf; +} + +int e2p_string2feature(char *string, int *compat_type, unsigned int *mask) +{ + struct feature *f; + char *eptr; + int num; + + for (f = feature_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *compat_type = f->compat; + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "FEATURE_", 8)) + return 1; + + switch (string[8]) { + case 'c': + case 'C': + *compat_type = E2P_FEATURE_COMPAT; + break; + case 'i': + case 'I': + *compat_type = E2P_FEATURE_INCOMPAT; + break; + case 'r': + case 'R': + *compat_type = E2P_FEATURE_RO_INCOMPAT; + break; + default: + return 1; + } + if (string[9] == 0) + return 1; + num = strtol(string+9, &eptr, 10); + if (num > 32 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} + +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp) && *cp != ',') + cp++; + return cp; +} + +/* + * Edit a feature set array as requested by the user. The ok_array, + * if set, allows the application to limit what features the user is + * allowed to set or clear using this function. + */ +int e2p_edit_feature(const char *str, __u32 *compat_array, __u32 *ok_array) +{ + char *cp, *buf, *next; + int neg; + unsigned int mask; + int compat_type; + + buf = malloc(strlen(str)+1); + if (!buf) + return 1; + strcpy(buf, str); + cp = buf; + while (cp && *cp) { + neg = 0; + cp = skip_over_blanks(cp); + next = skip_over_word(cp); + if (*next == 0) + next = 0; + else + *next = 0; + switch (*cp) { + case '-': + case '^': + neg++; + case '+': + cp++; + break; + } + if (e2p_string2feature(cp, &compat_type, &mask)) + return 1; + if (ok_array && !(ok_array[compat_type] & mask)) + return 1; + if (neg) + compat_array[compat_type] &= ~mask; + else + compat_array[compat_type] |= mask; + cp = next ? next+1 : 0; + } + return 0; +} + diff --git a/e2fsprogs/e2p/fgetflags.c b/e2fsprogs/e2p/fgetflags.c new file mode 100644 index 000000000..6db729e08 --- /dev/null +++ b/e2fsprogs/e2p/fgetflags.c @@ -0,0 +1,92 @@ +/* + * fgetflags.c - Get a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#if HAVE_EXT2_IOCTLS +#include <fcntl.h> +#include <sys/ioctl.h> +#endif + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fgetflags (const char * name, unsigned long * flags) +{ + struct stat buf; +#if HAVE_STAT_FLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS) + + if (stat (name, &buf) == -1) + return -1; + + *flags = 0; +#ifdef UF_IMMUTABLE + if (buf.st_flags & UF_IMMUTABLE) + *flags |= EXT2_IMMUTABLE_FL; +#endif +#ifdef UF_APPEND + if (buf.st_flags & UF_APPEND) + *flags |= EXT2_APPEND_FL; +#endif +#ifdef UF_NODUMP + if (buf.st_flags & UF_NODUMP) + *flags |= EXT2_NODUMP_FL; +#endif + + return 0; +#else +#if HAVE_EXT2_IOCTLS + int fd, r, f, save_errno = 0; + + if (!stat(name, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + goto notsupp; + } +#if !APPLE_DARWIN + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + r = ioctl (fd, EXT2_IOC_GETFLAGS, &f); + if (r == -1) + save_errno = errno; + *flags = f; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#else + f = -1; + save_errno = syscall(SYS_fsctl, name, EXT2_IOC_GETFLAGS, &f, 0); + *flags = f; + return (save_errno); +#endif +#endif /* HAVE_EXT2_IOCTLS */ +#endif +notsupp: + errno = EOPNOTSUPP; + return -1; +} diff --git a/e2fsprogs/e2p/fgetversion.c b/e2fsprogs/e2p/fgetversion.c new file mode 100644 index 000000000..351a7d5d0 --- /dev/null +++ b/e2fsprogs/e2p/fgetversion.c @@ -0,0 +1,62 @@ +/* + * fgetversion.c - Get a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> +#include <sys/ioctl.h> + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fgetversion (const char * name, unsigned long * version) +{ +#if HAVE_EXT2_IOCTLS +#if !APPLE_DARWIN + int fd, r, ver, save_errno = 0; + + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + r = ioctl (fd, EXT2_IOC_GETVERSION, &ver); + if (r == -1) + save_errno = errno; + *version = ver; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#else + int ver=-1, err; + err = syscall(SYS_fsctl, name, EXT2_IOC_GETVERSION, &ver, 0); + *version = ver; + return(err); +#endif +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff --git a/e2fsprogs/e2p/fsetflags.c b/e2fsprogs/e2p/fsetflags.c new file mode 100644 index 000000000..40e7292dd --- /dev/null +++ b/e2fsprogs/e2p/fsetflags.c @@ -0,0 +1,96 @@ +/* + * fsetflags.c - Set a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#if HAVE_EXT2_IOCTLS +#include <fcntl.h> +#include <sys/ioctl.h> +#endif + +#include "e2p.h" + +/* + * Deal with lame glibc's that define this function without actually + * implementing it. Can you say "attractive nuisance", boys and girls? + * I knew you could! + */ +#ifdef __linux__ +#undef HAVE_CHFLAGS +#endif + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fsetflags (const char * name, unsigned long flags) +{ + struct stat buf; +#if HAVE_CHFLAGS && !(APPLE_DARWIN && HAVE_EXT2_IOCTLS) + unsigned long bsd_flags = 0; + +#ifdef UF_IMMUTABLE + if (flags & EXT2_IMMUTABLE_FL) + bsd_flags |= UF_IMMUTABLE; +#endif +#ifdef UF_APPEND + if (flags & EXT2_APPEND_FL) + bsd_flags |= UF_APPEND; +#endif +#ifdef UF_NODUMP + if (flags & EXT2_NODUMP_FL) + bsd_flags |= UF_NODUMP; +#endif + + return chflags (name, bsd_flags); +#else +#if HAVE_EXT2_IOCTLS + int fd, r, f, save_errno = 0; + + if (!stat(name, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + goto notsupp; + } +#if !APPLE_DARWIN + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + f = (int) flags; + r = ioctl (fd, EXT2_IOC_SETFLAGS, &f); + if (r == -1) + save_errno = errno; + close (fd); + if (save_errno) + errno = save_errno; +#else + f = (int) flags; + return syscall(SYS_fsctl, name, EXT2_IOC_SETFLAGS, &f, 0); +#endif + return r; +#endif /* HAVE_EXT2_IOCTLS */ +#endif +notsupp: + errno = EOPNOTSUPP; + return -1; +} diff --git a/e2fsprogs/e2p/fsetversion.c b/e2fsprogs/e2p/fsetversion.c new file mode 100644 index 000000000..93243d6e0 --- /dev/null +++ b/e2fsprogs/e2p/fsetversion.c @@ -0,0 +1,60 @@ +/* + * fsetversion.c - Set a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <fcntl.h> +#include <sys/ioctl.h> + +#include "e2p.h" + +#ifdef O_LARGEFILE +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK|O_LARGEFILE) +#else +#define OPEN_FLAGS (O_RDONLY|O_NONBLOCK) +#endif + +int fsetversion (const char * name, unsigned long version) +{ +#if HAVE_EXT2_IOCTLS +#if !APPLE_DARWIN + int fd, r, ver, save_errno = 0; + + fd = open (name, OPEN_FLAGS); + if (fd == -1) + return -1; + ver = (int) version; + r = ioctl (fd, EXT2_IOC_SETVERSION, &ver); + if (r == -1) + save_errno = errno; + close (fd); + if (save_errno) + errno = save_errno; + return r; +#else + int ver = (int)version; + return syscall(SYS_fsctl, name, EXT2_IOC_SETVERSION, &ver, 0); +#endif +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff --git a/e2fsprogs/e2p/getflags.c b/e2fsprogs/e2p/getflags.c new file mode 100644 index 000000000..acf7a122b --- /dev/null +++ b/e2fsprogs/e2p/getflags.c @@ -0,0 +1,66 @@ +/* + * getflags.c - Get a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#if HAVE_EXT2_IOCTLS +#include <sys/ioctl.h> +#endif + +#include "e2p.h" + +int getflags (int fd, unsigned long * flags) +{ + struct stat buf; +#if HAVE_STAT_FLAGS + + if (fstat (fd, &buf) == -1) + return -1; + + *flags = 0; +#ifdef UF_IMMUTABLE + if (buf.st_flags & UF_IMMUTABLE) + *flags |= EXT2_IMMUTABLE_FL; +#endif +#ifdef UF_APPEND + if (buf.st_flags & UF_APPEND) + *flags |= EXT2_APPEND_FL; +#endif +#ifdef UF_NODUMP + if (buf.st_flags & UF_NODUMP) + *flags |= EXT2_NODUMP_FL; +#endif + + return 0; +#else +#if HAVE_EXT2_IOCTLS + int r, f; + + if (!fstat(fd, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) + goto notsupp; + r = ioctl (fd, EXT2_IOC_GETFLAGS, &f); + *flags = f; + return r; +#endif /* HAVE_EXT2_IOCTLS */ +#endif +notsupp: + errno = EOPNOTSUPP; + return -1; +} diff --git a/e2fsprogs/e2p/getversion.c b/e2fsprogs/e2p/getversion.c new file mode 100644 index 000000000..38b7d0fb0 --- /dev/null +++ b/e2fsprogs/e2p/getversion.c @@ -0,0 +1,37 @@ +/* + * getversion.c - Get a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/ioctl.h> + +#include "e2p.h" + +int getversion (int fd, unsigned long * version) +{ +#if HAVE_EXT2_IOCTLS + int r, ver; + + r = ioctl (fd, EXT2_IOC_GETVERSION, &ver); + *version = ver; + return 0; +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff --git a/e2fsprogs/e2p/hashstr.c b/e2fsprogs/e2p/hashstr.c new file mode 100644 index 000000000..b257eb26c --- /dev/null +++ b/e2fsprogs/e2p/hashstr.c @@ -0,0 +1,70 @@ +/* + * feature.c --- convert between features and strings + * + * Copyright (C) 1999 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "e2p.h" + +struct hash { + int num; + const char *string; +}; + +static struct hash hash_list[] = { + { EXT2_HASH_LEGACY, "legacy" }, + { EXT2_HASH_HALF_MD4, "half_md4" }, + { EXT2_HASH_TEA, "tea" }, + { 0, 0 }, +}; + +const char *e2p_hash2string(int num) +{ + struct hash *p; + static char buf[20]; + + for (p = hash_list; p->string; p++) { + if (num == p->num) + return p->string; + } + sprintf(buf, "HASHALG_%d", num); + return buf; +} + +/* + * Returns the hash algorithm, or -1 on error + */ +int e2p_string2hash(char *string) +{ + struct hash *p; + char *eptr; + int num; + + for (p = hash_list; p->string; p++) { + if (!strcasecmp(string, p->string)) { + return p->num; + } + } + if (strncasecmp(string, "HASHALG_", 8)) + return -1; + + if (string[8] == 0) + return -1; + num = strtol(string+8, &eptr, 10); + if (num > 255 || num < 0) + return -1; + if (*eptr) + return -1; + return num; +} + diff --git a/e2fsprogs/e2p/iod.c b/e2fsprogs/e2p/iod.c new file mode 100644 index 000000000..808d3a39d --- /dev/null +++ b/e2fsprogs/e2p/iod.c @@ -0,0 +1,72 @@ +/* + * iod.c - Iterate a function on each entry of a directory + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include "e2p.h" +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <string.h> + +int iterate_on_dir (const char * dir_name, + int (*func) (const char *, struct dirent *, void *), + void * private) +{ + DIR * dir; + struct dirent *de, *dep; + int max_len = -1, len; + +#if HAVE_PATHCONF && defined(_PC_NAME_MAX) + max_len = pathconf(dir_name, _PC_NAME_MAX); +#endif + if (max_len == -1) { +#ifdef _POSIX_NAME_MAX + max_len = _POSIX_NAME_MAX; +#else +#ifdef NAME_MAX + max_len = NAME_MAX; +#else + max_len = 256; +#endif /* NAME_MAX */ +#endif /* _POSIX_NAME_MAX */ + } + max_len += sizeof(struct dirent); + + de = malloc(max_len+1); + if (!de) + return -1; + memset(de, 0, max_len+1); + + dir = opendir (dir_name); + if (dir == NULL) { + free(de); + return -1; + } + while ((dep = readdir (dir))) { + len = sizeof(struct dirent); +#ifdef HAVE_RECLEN_DIRENT + if (len < dep->d_reclen) + len = dep->d_reclen; + if (len > max_len) + len = max_len; +#endif + memcpy(de, dep, len); + (*func) (dir_name, de, private); + } + free(de); + closedir(dir); + return 0; +} diff --git a/e2fsprogs/e2p/ls.c b/e2fsprogs/e2p/ls.c new file mode 100644 index 000000000..e8d9d482d --- /dev/null +++ b/e2fsprogs/e2p/ls.c @@ -0,0 +1,276 @@ +/* + * ls.c - List the contents of an ext2fs superblock + * + * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Copyright (C) 1995, 1996, 1997 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <grp.h> +#include <pwd.h> +#include <time.h> + +#include "e2p.h" + +static void print_user (unsigned short uid, FILE *f) +{ + struct passwd *pw; + + fprintf(f, "%u ", uid); + pw = getpwuid (uid); + if (pw == NULL) + fprintf(f, "(user unknown)\n"); + else + fprintf(f, "(user %s)\n", pw->pw_name); +} + +static void print_group (unsigned short gid, FILE *f) +{ + struct group *gr; + + fprintf(f, "%u ", gid); + gr = getgrgid (gid); + if (gr == NULL) + fprintf(f, "(group unknown)\n"); + else + fprintf(f, "(group %s)\n", gr->gr_name); +} + +#define MONTH_INT (86400 * 30) +#define WEEK_INT (86400 * 7) +#define DAY_INT (86400) +#define HOUR_INT (60 * 60) +#define MINUTE_INT (60) + +static const char *interval_string(unsigned int secs) +{ + static char buf[256], tmp[80]; + int hr, min, num; + + buf[0] = 0; + + if (secs == 0) + return "<none>"; + + if (secs >= MONTH_INT) { + num = secs / MONTH_INT; + secs -= num*MONTH_INT; + sprintf(buf, "%d month%s", num, (num>1) ? "s" : ""); + } + if (secs >= WEEK_INT) { + num = secs / WEEK_INT; + secs -= num*WEEK_INT; + sprintf(tmp, "%s%d week%s", buf[0] ? ", " : "", + num, (num>1) ? "s" : ""); + strcat(buf, tmp); + } + if (secs >= DAY_INT) { + num = secs / DAY_INT; + secs -= num*DAY_INT; + sprintf(tmp, "%s%d day%s", buf[0] ? ", " : "", + num, (num>1) ? "s" : ""); + strcat(buf, tmp); + } + if (secs > 0) { + hr = secs / HOUR_INT; + secs -= hr*HOUR_INT; + min = secs / MINUTE_INT; + secs -= min*MINUTE_INT; + sprintf(tmp, "%s%d:%02d:%02d", buf[0] ? ", " : "", + hr, min, secs); + strcat(buf, tmp); + } + return buf; +} + +static void print_features(struct ext2_super_block * s, FILE *f) +{ +#ifdef EXT2_DYNAMIC_REV + int i, j, printed=0; + __u32 *mask = &s->s_feature_compat, m; + + fprintf(f, "Filesystem features: "); + for (i=0; i <3; i++,mask++) { + for (j=0,m=1; j < 32; j++, m<<=1) { + if (*mask & m) { + fprintf(f, " %s", e2p_feature2string(i, m)); + printed++; + } + } + } + if (printed == 0) + fprintf(f, " (none)"); + fprintf(f, "\n"); +#endif +} + +static void print_mntopts(struct ext2_super_block * s, FILE *f) +{ +#ifdef EXT2_DYNAMIC_REV + int i, printed=0; + __u32 mask = s->s_default_mount_opts, m; + + fprintf(f, "Default mount options: "); + if (mask & EXT3_DEFM_JMODE) { + fprintf(f, " %s", e2p_mntopt2string(mask & EXT3_DEFM_JMODE)); + printed++; + } + for (i=0,m=1; i < 32; i++, m<<=1) { + if (m & EXT3_DEFM_JMODE) + continue; + if (mask & m) { + fprintf(f, " %s", e2p_mntopt2string(m)); + printed++; + } + } + if (printed == 0) + fprintf(f, " (none)"); + fprintf(f, "\n"); +#endif +} + + +#ifndef EXT2_INODE_SIZE +#define EXT2_INODE_SIZE(s) sizeof(struct ext2_inode) +#endif + +#ifndef EXT2_GOOD_OLD_REV +#define EXT2_GOOD_OLD_REV 0 +#endif + +void list_super2(struct ext2_super_block * sb, FILE *f) +{ + int inode_blocks_per_group; + char buf[80], *str; + time_t tm; + + inode_blocks_per_group = (((sb->s_inodes_per_group * + EXT2_INODE_SIZE(sb)) + + EXT2_BLOCK_SIZE(sb) - 1) / + EXT2_BLOCK_SIZE(sb)); + if (sb->s_volume_name[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_volume_name, sizeof(sb->s_volume_name)); + } else + strcpy(buf, "<none>"); + fprintf(f, "Filesystem volume name: %s\n", buf); + if (sb->s_last_mounted[0]) { + memset(buf, 0, sizeof(buf)); + strncpy(buf, sb->s_last_mounted, sizeof(sb->s_last_mounted)); + } else + strcpy(buf, "<not available>"); + fprintf(f, "Last mounted on: %s\n", buf); + fprintf(f, "Filesystem UUID: %s\n", e2p_uuid2str(sb->s_uuid)); + fprintf(f, "Filesystem magic number: 0x%04X\n", sb->s_magic); + fprintf(f, "Filesystem revision #: %d", sb->s_rev_level); + if (sb->s_rev_level == EXT2_GOOD_OLD_REV) { + fprintf(f, " (original)\n"); +#ifdef EXT2_DYNAMIC_REV + } else if (sb->s_rev_level == EXT2_DYNAMIC_REV) { + fprintf(f, " (dynamic)\n"); +#endif + } else + fprintf(f, " (unknown)\n"); + print_features(sb, f); + print_mntopts(sb, f); + fprintf(f, "Filesystem state: "); + print_fs_state (f, sb->s_state); + fprintf(f, "\n"); + fprintf(f, "Errors behavior: "); + print_fs_errors(f, sb->s_errors); + fprintf(f, "\n"); + str = e2p_os2string(sb->s_creator_os); + fprintf(f, "Filesystem OS type: %s\n", str); + free(str); + fprintf(f, "Inode count: %u\n", sb->s_inodes_count); + fprintf(f, "Block count: %u\n", sb->s_blocks_count); + fprintf(f, "Reserved block count: %u\n", sb->s_r_blocks_count); + fprintf(f, "Free blocks: %u\n", sb->s_free_blocks_count); + fprintf(f, "Free inodes: %u\n", sb->s_free_inodes_count); + fprintf(f, "First block: %u\n", sb->s_first_data_block); + fprintf(f, "Block size: %u\n", EXT2_BLOCK_SIZE(sb)); + fprintf(f, "Fragment size: %u\n", EXT2_FRAG_SIZE(sb)); + if (sb->s_reserved_gdt_blocks) + fprintf(f, "Reserved GDT blocks: %u\n", + sb->s_reserved_gdt_blocks); + fprintf(f, "Blocks per group: %u\n", sb->s_blocks_per_group); + fprintf(f, "Fragments per group: %u\n", sb->s_frags_per_group); + fprintf(f, "Inodes per group: %u\n", sb->s_inodes_per_group); + fprintf(f, "Inode blocks per group: %u\n", inode_blocks_per_group); + if (sb->s_first_meta_bg) + fprintf(f, "First meta block group: %u\n", + sb->s_first_meta_bg); + if (sb->s_mkfs_time) { + tm = sb->s_mkfs_time; + fprintf(f, "Filesystem created: %s", ctime(&tm)); + } + tm = sb->s_mtime; + fprintf(f, "Last mount time: %s", + sb->s_mtime ? ctime(&tm) : "n/a\n"); + tm = sb->s_wtime; + fprintf(f, "Last write time: %s", ctime(&tm)); + fprintf(f, "Mount count: %u\n", sb->s_mnt_count); + fprintf(f, "Maximum mount count: %d\n", sb->s_max_mnt_count); + tm = sb->s_lastcheck; + fprintf(f, "Last checked: %s", ctime(&tm)); + fprintf(f, "Check interval: %u (%s)\n", sb->s_checkinterval, + interval_string(sb->s_checkinterval)); + if (sb->s_checkinterval) + { + time_t next; + + next = sb->s_lastcheck + sb->s_checkinterval; + fprintf(f, "Next check after: %s", ctime(&next)); + } + fprintf(f, "Reserved blocks uid: "); + print_user(sb->s_def_resuid, f); + fprintf(f, "Reserved blocks gid: "); + print_group(sb->s_def_resgid, f); + if (sb->s_rev_level >= EXT2_DYNAMIC_REV) { + fprintf(f, "First inode: %d\n", sb->s_first_ino); + fprintf(f, "Inode size: %d\n", sb->s_inode_size); + } + if (!e2p_is_null_uuid(sb->s_journal_uuid)) + fprintf(f, "Journal UUID: %s\n", + e2p_uuid2str(sb->s_journal_uuid)); + if (sb->s_journal_inum) + fprintf(f, "Journal inode: %u\n", + sb->s_journal_inum); + if (sb->s_journal_dev) + fprintf(f, "Journal device: 0x%04x\n", + sb->s_journal_dev); + if (sb->s_last_orphan) + fprintf(f, "First orphan inode: %u\n", + sb->s_last_orphan); + if ((sb->s_feature_compat & EXT2_FEATURE_COMPAT_DIR_INDEX) || + sb->s_def_hash_version) + fprintf(f, "Default directory hash: %s\n", + e2p_hash2string(sb->s_def_hash_version)); + if (!e2p_is_null_uuid(sb->s_hash_seed)) + fprintf(f, "Directory Hash Seed: %s\n", + e2p_uuid2str(sb->s_hash_seed)); + if (sb->s_jnl_backup_type) { + fprintf(f, "Journal backup: "); + switch (sb->s_jnl_backup_type) { + case 1: + fprintf(f, "inode blocks\n"); + break; + default: + fprintf(f, "type %u\n", sb->s_jnl_backup_type); + } + } +} + +void list_super (struct ext2_super_block * s) +{ + list_super2(s, stdout); +} + diff --git a/e2fsprogs/e2p/mntopts.c b/e2fsprogs/e2p/mntopts.c new file mode 100644 index 000000000..6d0eca0ae --- /dev/null +++ b/e2fsprogs/e2p/mntopts.c @@ -0,0 +1,136 @@ +/* + * mountopts.c --- convert between default mount options and strings + * + * Copyright (C) 2002 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#include "e2p.h" + +struct mntopt { + unsigned int mask; + const char *string; +}; + +static struct mntopt mntopt_list[] = { + { EXT2_DEFM_DEBUG, "debug" }, + { EXT2_DEFM_BSDGROUPS, "bsdgroups" }, + { EXT2_DEFM_XATTR_USER, "user_xattr" }, + { EXT2_DEFM_ACL, "acl" }, + { EXT2_DEFM_UID16, "uid16" }, + { EXT3_DEFM_JMODE_DATA, "journal_data" }, + { EXT3_DEFM_JMODE_ORDERED, "journal_data_ordered" }, + { EXT3_DEFM_JMODE_WBACK, "journal_data_writeback" }, + { 0, 0 }, +}; + +const char *e2p_mntopt2string(unsigned int mask) +{ + struct mntopt *f; + static char buf[20]; + int fnum; + + for (f = mntopt_list; f->string; f++) { + if (mask == f->mask) + return f->string; + } + for (fnum = 0; mask >>= 1; fnum++); + sprintf(buf, "MNTOPT_%d", fnum); + return buf; +} + +int e2p_string2mntopt(char *string, unsigned int *mask) +{ + struct mntopt *f; + char *eptr; + int num; + + for (f = mntopt_list; f->string; f++) { + if (!strcasecmp(string, f->string)) { + *mask = f->mask; + return 0; + } + } + if (strncasecmp(string, "MNTOPT_", 8)) + return 1; + + if (string[8] == 0) + return 1; + num = strtol(string+8, &eptr, 10); + if (num > 32 || num < 0) + return 1; + if (*eptr) + return 1; + *mask = 1 << num; + return 0; +} + +static char *skip_over_blanks(char *cp) +{ + while (*cp && isspace(*cp)) + cp++; + return cp; +} + +static char *skip_over_word(char *cp) +{ + while (*cp && !isspace(*cp) && *cp != ',') + cp++; + return cp; +} + +/* + * Edit a mntopt set array as requested by the user. The ok + * parameter, if non-zero, allows the application to limit what + * mntopts the user is allowed to set or clear using this function. + */ +int e2p_edit_mntopts(const char *str, __u32 *mntopts, __u32 ok) +{ + char *cp, *buf, *next; + int neg; + unsigned int mask; + + buf = malloc(strlen(str)+1); + if (!buf) + return 1; + strcpy(buf, str); + cp = buf; + while (cp && *cp) { + neg = 0; + cp = skip_over_blanks(cp); + next = skip_over_word(cp); + if (*next == 0) + next = 0; + else + *next = 0; + switch (*cp) { + case '-': + case '^': + neg++; + case '+': + cp++; + break; + } + if (e2p_string2mntopt(cp, &mask)) + return 1; + if (ok && !(ok & mask)) + return 1; + if (mask & EXT3_DEFM_JMODE) + *mntopts &= ~EXT3_DEFM_JMODE; + if (neg) + *mntopts &= ~mask; + else + *mntopts |= mask; + cp = next ? next+1 : 0; + } + return 0; +} diff --git a/e2fsprogs/e2p/ostype.c b/e2fsprogs/e2p/ostype.c new file mode 100644 index 000000000..fe6597dd5 --- /dev/null +++ b/e2fsprogs/e2p/ostype.c @@ -0,0 +1,73 @@ +/* + * getostype.c - Get the Filesystem OS type + * + * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include "e2p.h" +#include <string.h> + +const char *os_tab[] = + { "Linux", + "Hurd", + "Masix", + "FreeBSD", + "Lites", + 0 }; + +/* + * Convert an os_type to a string + */ +char *e2p_os2string(int os_type) +{ + const char *os; + char *ret; + + if (os_type <= EXT2_OS_LITES) + os = os_tab[os_type]; + else + os = "(unknown os)"; + + ret = malloc(strlen(os)+1); + strcpy(ret, os); + return ret; +} + +/* + * Convert an os_type to a string + */ +int e2p_string2os(char *str) +{ + const char **cpp; + int i = 0; + + for (cpp = os_tab; *cpp; cpp++, i++) { + if (!strcasecmp(str, *cpp)) + return i; + } + return -1; +} + +#ifdef TEST_PROGRAM +int main(int argc, char **argv) +{ + char *s; + int i, os; + + for (i=0; i <= EXT2_OS_LITES; i++) { + s = e2p_os2string(i); + os = e2p_string2os(s); + printf("%d: %s (%d)\n", i, s, os); + if (i != os) { + fprintf(stderr, "Failure!\n"); + exit(1); + } + } + exit(0); +} +#endif + + diff --git a/e2fsprogs/e2p/parse_num.c b/e2fsprogs/e2p/parse_num.c new file mode 100644 index 000000000..3910e70de --- /dev/null +++ b/e2fsprogs/e2p/parse_num.c @@ -0,0 +1,64 @@ +/* + * parse_num.c - Parse the number of blocks + * + * Copyright (C) 2004,2005 Theodore Ts'o <tytso@mit.edu> + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +#include "e2p.h" + +#include <stdlib.h> + +unsigned long parse_num_blocks(const char *arg, int log_block_size) +{ + char *p; + unsigned long long num; + + num = strtoull(arg, &p, 0); + + if (p[0] && p[1]) + return 0; + + switch (*p) { /* Using fall-through logic */ + case 'T': case 't': + num <<= 10; + case 'G': case 'g': + num <<= 10; + case 'M': case 'm': + num <<= 10; + case 'K': case 'k': + num >>= log_block_size; + break; + case 's': + num >>= 1; + break; + case '\0': + break; + default: + return 0; + } + return num; +} + +#ifdef DEBUG +#include <unistd.h> +#include <stdio.h> + +main(int argc, char **argv) +{ + unsigned long num; + int log_block_size = 0; + + if (argc != 2) { + fprintf(stderr, "Usage: %s arg\n", argv[0]); + exit(1); + } + + num = parse_num_blocks(argv[1], log_block_size); + + printf("Parsed number: %lu\n", num); + exit(0); +} +#endif diff --git a/e2fsprogs/e2p/pe.c b/e2fsprogs/e2p/pe.c new file mode 100644 index 000000000..4cce69117 --- /dev/null +++ b/e2fsprogs/e2p/pe.c @@ -0,0 +1,37 @@ +/* + * pe.c - Print a second extended filesystem errors behavior + * + * Copyright (C) 1992, 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 94/01/09 - Creation + */ + +#include <stdio.h> + +#include "e2p.h" + +void print_fs_errors (FILE * f, unsigned short errors) +{ + switch (errors) + { + case EXT2_ERRORS_CONTINUE: + fprintf (f, "Continue"); + break; + case EXT2_ERRORS_RO: + fprintf (f, "Remount read-only"); + break; + case EXT2_ERRORS_PANIC: + fprintf (f, "Panic"); + break; + default: + fprintf (f, "Unknown (continue)"); + } +} diff --git a/e2fsprogs/e2p/pf.c b/e2fsprogs/e2p/pf.c new file mode 100644 index 000000000..48d75a9ae --- /dev/null +++ b/e2fsprogs/e2p/pf.c @@ -0,0 +1,74 @@ +/* + * pf.c - Print file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#include <stdio.h> + +#include "e2p.h" + +struct flags_name { + unsigned long flag; + const char *short_name; + const char *long_name; +}; + +static struct flags_name flags_array[] = { + { EXT2_SECRM_FL, "s", "Secure_Deletion" }, + { EXT2_UNRM_FL, "u" , "Undelete" }, + { EXT2_SYNC_FL, "S", "Synchronous_Updates" }, + { EXT2_DIRSYNC_FL, "D", "Synchronous_Directory_Updates" }, + { EXT2_IMMUTABLE_FL, "i", "Immutable" }, + { EXT2_APPEND_FL, "a", "Append_Only" }, + { EXT2_NODUMP_FL, "d", "No_Dump" }, + { EXT2_NOATIME_FL, "A", "No_Atime" }, + { EXT2_COMPR_FL, "c", "Compression_Requested" }, +#ifdef ENABLE_COMPRESSION + { EXT2_COMPRBLK_FL, "B", "Compressed_File" }, + { EXT2_DIRTY_FL, "Z", "Compressed_Dirty_File" }, + { EXT2_NOCOMPR_FL, "X", "Compression_Raw_Access" }, + { EXT2_ECOMPR_FL, "E", "Compression_Error" }, +#endif + { EXT3_JOURNAL_DATA_FL, "j", "Journaled_Data" }, + { EXT2_INDEX_FL, "I", "Indexed_direcctory" }, + { EXT2_NOTAIL_FL, "t", "No_Tailmerging" }, + { EXT2_TOPDIR_FL, "T", "Top_of_Directory_Hierarchies" }, + { 0, NULL, NULL } +}; + +void print_flags (FILE * f, unsigned long flags, unsigned options) +{ + int long_opt = (options & PFOPT_LONG); + struct flags_name *fp; + int first = 1; + + for (fp = flags_array; fp->flag != 0; fp++) { + if (flags & fp->flag) { + if (long_opt) { + if (first) + first = 0; + else + fputs(", ", f); + fputs(fp->long_name, f); + } else + fputs(fp->short_name, f); + } else { + if (!long_opt) + fputs("-", f); + } + } + if (long_opt && first) + fputs("---", f); +} + diff --git a/e2fsprogs/e2p/ps.c b/e2fsprogs/e2p/ps.c new file mode 100644 index 000000000..bec8b4195 --- /dev/null +++ b/e2fsprogs/e2p/ps.c @@ -0,0 +1,29 @@ +/* + * ps.c - Print filesystem state + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/12/22 - Creation + */ + +#include <stdio.h> + +#include "e2p.h" + +void print_fs_state (FILE * f, unsigned short state) +{ + if (state & EXT2_VALID_FS) + fprintf (f, " clean"); + else + fprintf (f, " not clean"); + if (state & EXT2_ERROR_FS) + fprintf (f, " with errors"); +} diff --git a/e2fsprogs/e2p/setflags.c b/e2fsprogs/e2p/setflags.c new file mode 100644 index 000000000..47c52a7ad --- /dev/null +++ b/e2fsprogs/e2p/setflags.c @@ -0,0 +1,72 @@ +/* + * setflags.c - Set a file flags on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/types.h> +#include <sys/stat.h> +#if HAVE_EXT2_IOCTLS +#include <sys/ioctl.h> +#endif + +#include "e2p.h" + +/* + * Deal with lame glibc's that define this function without actually + * implementing it. Can you say "attractive nuisance", boys and girls? + * I knew you could! + */ +#ifdef __linux__ +#undef HAVE_CHFLAGS +#endif + +int setflags (int fd, unsigned long flags) +{ + struct stat buf; +#if HAVE_CHFLAGS + unsigned long bsd_flags = 0; + +#ifdef UF_IMMUTABLE + if (flags & EXT2_IMMUTABLE_FL) + bsd_flags |= UF_IMMUTABLE; +#endif +#ifdef UF_APPEND + if (flags & EXT2_APPEND_FL) + bsd_flags |= UF_APPEND; +#endif +#ifdef UF_NODUMP + if (flags & EXT2_NODUMP_FL) + bsd_flags |= UF_NODUMP; +#endif + + return fchflags (fd, bsd_flags); +#else +#if HAVE_EXT2_IOCTLS + int f; + + if (!fstat(fd, &buf) && + !S_ISREG(buf.st_mode) && !S_ISDIR(buf.st_mode)) { + errno = EOPNOTSUPP; + return -1; + } + f = (int) flags; + return ioctl (fd, EXT2_IOC_SETFLAGS, &f); +#endif /* HAVE_EXT2_IOCTLS */ +#endif + errno = EOPNOTSUPP; + return -1; +} diff --git a/e2fsprogs/e2p/setversion.c b/e2fsprogs/e2p/setversion.c new file mode 100644 index 000000000..bd00df668 --- /dev/null +++ b/e2fsprogs/e2p/setversion.c @@ -0,0 +1,36 @@ +/* + * setversion.c - Set a file version on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + */ + +#if HAVE_ERRNO_H +#include <errno.h> +#endif +#include <sys/ioctl.h> + +#include "e2p.h" + +int setversion (int fd, unsigned long version) +{ +#if HAVE_EXT2_IOCTLS + int ver; + + ver = (int) version; + return ioctl (fd, EXT2_IOC_SETVERSION, &ver); +#else /* ! HAVE_EXT2_IOCTLS */ + extern int errno; + errno = EOPNOTSUPP; + return -1; +#endif /* ! HAVE_EXT2_IOCTLS */ +} diff --git a/e2fsprogs/e2p/uuid.c b/e2fsprogs/e2p/uuid.c new file mode 100644 index 000000000..fef3b91e7 --- /dev/null +++ b/e2fsprogs/e2p/uuid.c @@ -0,0 +1,79 @@ +/* + * uuid.c -- utility routines for manipulating UUID's. + */ + +#include <stdio.h> +#include <string.h> +#include <ext2fs/ext2_types.h> + +#include "e2p.h" + +struct uuid { + __u32 time_low; + __u16 time_mid; + __u16 time_hi_and_version; + __u16 clock_seq; + __u8 node[6]; +}; + +/* Returns 1 if the uuid is the NULL uuid */ +int e2p_is_null_uuid(void *uu) +{ + __u8 *cp; + int i; + + for (i=0, cp = uu; i < 16; i++) + if (*cp) + return 0; + return 1; +} + +static void e2p_unpack_uuid(void *in, struct uuid *uu) +{ + __u8 *ptr = in; + __u32 tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_low = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_mid = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->time_hi_and_version = tmp; + + tmp = *ptr++; + tmp = (tmp << 8) | *ptr++; + uu->clock_seq = tmp; + + memcpy(uu->node, ptr, 6); +} + +void e2p_uuid_to_str(void *uu, char *out) +{ + struct uuid uuid; + + e2p_unpack_uuid(uu, &uuid); + sprintf(out, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, + uuid.clock_seq >> 8, uuid.clock_seq & 0xFF, + uuid.node[0], uuid.node[1], uuid.node[2], + uuid.node[3], uuid.node[4], uuid.node[5]); +} + +const char *e2p_uuid2str(void *uu) +{ + static char buf[80]; + + if (e2p_is_null_uuid(uu)) + return "<none>"; + e2p_uuid_to_str(uu, buf); + return buf; +} + diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c new file mode 100644 index 000000000..0f1c6f22c --- /dev/null +++ b/e2fsprogs/lsattr.c @@ -0,0 +1,193 @@ +/* + * lsattr.c - List file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card <card@masi.ibp.fr> + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU General + * Public License + */ + +/* + * History: + * 93/10/30 - Creation + * 93/11/13 - Replace stat() calls by lstat() to avoid loops + * 94/02/27 - Integrated in Ted's distribution + * 98/12/29 - Display version info only when -V specified (G M Sipe) + */ + +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <getopt.h> +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/stat.h> + +#include <ext2fs/ext2_fs.h> +#include "e2fsbb.h" +#include "e2p/e2p.h" + +#ifdef __GNUC__ +#define EXT2FS_ATTR(x) __attribute__(x) +#else +#define EXT2FS_ATTR(x) +#endif + +static int all; +static int dirs_opt; +static unsigned pf_options; +static int recursive; +static int verbose; +static int generation_opt; + +#ifdef _LFS64_LARGEFILE +#define LSTAT lstat64 +#define STRUCT_STAT struct stat64 +#else +#define LSTAT lstat +#define STRUCT_STAT struct stat +#endif + +#if 0 +static void usage(void) +{ + fprintf(stderr, _("Usage: %s [-RVadlv] [files...]\n"), program_name); + exit(1); +} +#endif + +static void list_attributes (const char * name) +{ + unsigned long flags; + unsigned long generation; + + if (fgetflags (name, &flags) == -1) { + com_err (program_name, errno, _("While reading flags on %s"), + name); + return; + } + if (generation_opt) { + if (fgetversion (name, &generation) == -1) { + com_err (program_name, errno, + _("While reading version on %s"), + name); + return; + } + printf ("%5lu ", generation); + } + if (pf_options & PFOPT_LONG) { + printf("%-28s ", name); + print_flags(stdout, flags, pf_options); + fputc('\n', stdout); + } else { + print_flags(stdout, flags, pf_options); + printf(" %s\n", name); + } +} + +static int lsattr_dir_proc (const char *, struct dirent *, void *); + +static void lsattr_args (const char * name) +{ + STRUCT_STAT st; + + if (LSTAT (name, &st) == -1) + com_err (program_name, errno, _("while trying to stat %s"), + name); + else { + if (S_ISDIR(st.st_mode) && !dirs_opt) + iterate_on_dir (name, lsattr_dir_proc, NULL); + else + list_attributes (name); + } +} + +static int lsattr_dir_proc (const char * dir_name, struct dirent * de, + void * private EXT2FS_ATTR((unused))) +{ + STRUCT_STAT st; + char *path; + int dir_len = strlen(dir_name); + + path = malloc(dir_len + strlen (de->d_name) + 2); + + if (dir_len && dir_name[dir_len-1] == '/') + sprintf (path, "%s%s", dir_name, de->d_name); + else + sprintf (path, "%s/%s", dir_name, de->d_name); + if (LSTAT (path, &st) == -1) + perror (path); + else { + if (de->d_name[0] != '.' || all) { + list_attributes (path); + if (S_ISDIR(st.st_mode) && recursive && + strcmp(de->d_name, ".") && + strcmp(de->d_name, "..")) { + printf ("\n%s:\n", path); + iterate_on_dir (path, lsattr_dir_proc, NULL); + printf ("\n"); + } + } + } + free(path); + return 0; +} + +int lsattr_main (int argc, char ** argv) +{ + int c; + int i; + +#ifdef ENABLE_NLS + setlocale(LC_MESSAGES, ""); + setlocale(LC_CTYPE, ""); + bindtextdomain(NLS_CAT_NAME, LOCALEDIR); + textdomain(NLS_CAT_NAME); +#endif +#if 0 + if (argc && *argv) + program_name = *argv; +#endif + while ((c = getopt (argc, argv, "Radlv")) != EOF) + switch (c) + { + case 'R': + recursive = 1; + break; + case 'V': + verbose = 1; + break; + case 'a': + all = 1; + break; + case 'd': + dirs_opt = 1; + break; + case 'l': + pf_options = PFOPT_LONG; + break; + case 'v': + generation_opt = 1; + break; + default: + usage(); + } + +#if 0 + if (verbose) + fprintf (stderr, "lsattr %s (%s)\n", + E2FSPROGS_VERSION, E2FSPROGS_DATE); +#endif + if (optind > argc - 1) + lsattr_args ("."); + else + for (i = optind; i < argc; i++) + lsattr_args (argv[i]); + exit(0); +} |