Hello community, here is the log from the commit of package sparse for openSUSE:Factory checked in at 2013-05-27 10:02:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sparse (Old) and /work/SRC/openSUSE:Factory/.sparse.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sparse" Changes: -------- --- /work/SRC/openSUSE:Factory/sparse/sparse.changes 2013-03-10 09:13:10.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.sparse.new/sparse.changes 2013-05-27 10:02:34.000000000 +0200 @@ -1,0 +2,6 @@ +Mon May 20 13:12:53 UTC 2013 - [email protected] + +- update to 20130425 + * many fixes + +------------------------------------------------------------------- Old: ---- sparse-20130225.tar.xz New: ---- sparse-20130425.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sparse.spec ++++++ --- /var/tmp/diff_new_pack.pD8nAM/_old 2013-05-27 10:02:35.000000000 +0200 +++ /var/tmp/diff_new_pack.pD8nAM/_new 2013-05-27 10:02:35.000000000 +0200 @@ -20,7 +20,7 @@ Summary: A semantic parser of source files License: SUSE-OSL-1.1 Group: Development/Tools/Building -Version: 20130225 +Version: 20130425 Release: 0 Url: https://sparse.wiki.kernel.org/index.php/Main_Page Source: sparse-%{version}.tar.xz ++++++ sparse-20130225.tar.xz -> sparse-20130425.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/Makefile new/sparse-20130425/Makefile --- old/sparse-20130225/Makefile 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/Makefile 2013-05-20 15:12:32.000000000 +0200 @@ -1,5 +1,13 @@ VERSION=0.4.4 +# Generating file version.h if current version has changed +SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)') +VERSION_H := $(shell cat version.h 2>/dev/null) +ifneq ($(lastword $(VERSION_H)),"$(SPARSE_VERSION)") +$(info $(shell echo ' GEN 'version.h)) +$(shell echo '#define SPARSE_VERSION "$(SPARSE_VERSION)"' > version.h) +endif + OS = linux @@ -191,7 +199,7 @@ rm -f *.[oa] .*.d *.so $(PROGRAMS) $(SLIB_FILE) pre-process.h sparse.pc dist: - @if test "`git describe`" != "v$(VERSION)" ; then \ + @if test "v$(SPARSE_VERSION)" != "v$(VERSION)" ; then \ echo 'Update VERSION in the Makefile before running "make dist".' ; \ exit 1 ; \ fi diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/cgcc new/sparse-20130425/cgcc --- old/sparse-20130225/cgcc 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/cgcc 2013-05-20 15:12:32.000000000 +0200 @@ -240,27 +240,32 @@ return (' -Di386=1 -D__i386=1 -D__i386__=1' . &integer_types (8, 16, 32, $m64 ? 64 : 32, 64) . &float_types (1, 1, 21, [24,8], [53,11], [64,15]) . - &define_size_t ($m64 ? "long unsigned int" : "unsigned int")); + &define_size_t ($m64 ? "long unsigned int" : "unsigned int") . + ' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4')); } elsif ($spec eq 'sparc') { return (' -Dsparc=1 -D__sparc=1 -D__sparc__=1' . &integer_types (8, 16, 32, $m64 ? 64 : 32, 64) . &float_types (1, 1, 33, [24,8], [53,11], [113,15]) . - &define_size_t ($m64 ? "long unsigned int" : "unsigned int")); + &define_size_t ($m64 ? "long unsigned int" : "unsigned int") . + ' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4')); } elsif ($spec eq 'sparc64') { return (' -Dsparc=1 -D__sparc=1 -D__sparc__=1 -D__sparcv9__=1 -D__sparc64__=1 -D__arch64__=1 -D__LP64__=1' . &integer_types (8, 16, 32, 64, 64, 128) . &float_types (1, 1, 33, [24,8], [53,11], [113,15]) . - &define_size_t ("long unsigned int")); + &define_size_t ("long unsigned int") . + ' -D__SIZEOF_POINTER__=8'); } elsif ($spec eq 'x86_64') { return (' -Dx86_64=1 -D__x86_64=1 -D__x86_64__=1' . ($m32 ? '' : ' -D__LP64__=1') . &integer_types (8, 16, 32, $m32 ? 32 : 64, 64, 128) . &float_types (1, 1, 33, [24,8], [53,11], [113,15]) . - &define_size_t ($m32 ? "unsigned int" : "long unsigned int")); + &define_size_t ($m32 ? "unsigned int" : "long unsigned int") . + ' -D__SIZEOF_POINTER__=' . ($m32 ? '4' : '8')); } elsif ($spec eq 'ppc') { return (' -D__powerpc__=1 -D_BIG_ENDIAN -D_STRING_ARCH_unaligned=1' . &integer_types (8, 16, 32, $m64 ? 64 : 32, 64) . &float_types (1, 1, 21, [24,8], [53,11], [113,15]) . - &define_size_t ($m64 ? "long unsigned int" : "unsigned int")); + &define_size_t ($m64 ? "long unsigned int" : "unsigned int") . + ' -D__SIZEOF_POINTER__=' . ($m64 ? '8' : '4')); } elsif ($spec eq 'host_os_specs') { my $os = `uname -s`; chomp $os; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/evaluate.c new/sparse-20130425/evaluate.c --- old/sparse-20130225/evaluate.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/evaluate.c 2013-05-20 15:12:32.000000000 +0200 @@ -2137,7 +2137,7 @@ else degenerate(expr); } - } else { + } else if (!target->forced_arg){ static char where[30]; examine_symbol_type(target); sprintf(where, "argument %d", i); @@ -2592,10 +2592,14 @@ p = alloc_expression(e->pos, EXPR_STRING); *p = *e; type = evaluate_expression(p); - if (ctype->bit_size != -1 && - ctype->bit_size + bits_in_char < type->bit_size) { - warning(e->pos, - "too long initializer-string for array of char"); + if (ctype->bit_size != -1) { + if (ctype->bit_size + bits_in_char < type->bit_size) + warning(e->pos, + "too long initializer-string for array of char"); + else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) { + warning(e->pos, + "too long initializer-string for array of char(no space for nul char)"); + } } *ep = p; return 1; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/expand.c new/sparse-20130425/expand.c --- old/sparse-20130225/expand.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/expand.c 2013-05-20 15:12:32.000000000 +0200 @@ -92,6 +92,14 @@ value = get_longlong(old); Int: + // _Bool requires a zero test rather than truncation. + if (is_bool_type(newtype)) { + expr->value = !!value; + if (!conservative && value != 0 && value != 1) + warning(old->pos, "odd constant _Bool cast (%llx becomes 1)", value); + return; + } + // Truncate it to the new size signmask = 1ULL << (new_size-1); mask = signmask | (signmask-1); @@ -1207,10 +1215,11 @@ } expand_expression(expr); if (expr->type != EXPR_VALUE) { - expression_error(expr, "bad constant expression"); + if (strict != 2) + expression_error(expr, "bad constant expression"); return 0; } - if (strict && bad_integer_constant_expression(expr)) { + if ((strict == 1) && bad_integer_constant_expression(expr)) { expression_error(expr, "bad integer constant expression"); return 0; } @@ -1237,6 +1246,12 @@ return __get_expression_value(expr, 1); } +long long get_expression_value_silent(struct expression *expr) +{ + + return __get_expression_value(expr, 2); +} + int is_zero_constant(struct expression *expr) { const int saved = conservative; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/expression.h new/sparse-20130425/expression.h --- old/sparse-20130225/expression.h 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/expression.h 2013-05-20 15:12:32.000000000 +0200 @@ -163,6 +163,7 @@ int is_zero_constant(struct expression *); long long get_expression_value(struct expression *); long long const_expression_value(struct expression *); +long long get_expression_value_silent(struct expression *expr); /* Expression parsing */ struct token *parse_expression(struct token *token, struct expression **tree); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/ident-list.h new/sparse-20130425/ident-list.h --- old/sparse-20130225/ident-list.h 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/ident-list.h 2013-05-20 15:12:32.000000000 +0200 @@ -97,6 +97,7 @@ * itself by name, preventing these tokens from expanding when compiling * sparse. */ IDENT(defined); +IDENT(once); __IDENT(pragma_ident, "__pragma__", 0); __IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0); __IDENT(__LINE___ident, "__LINE__", 0); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/lib.c new/sparse-20130425/lib.c --- old/sparse-20130225/lib.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/lib.c 2013-05-20 15:12:32.000000000 +0200 @@ -27,6 +27,7 @@ #include "scope.h" #include "linearize.h" #include "target.h" +#include "version.h" int verbose, optimize, optimize_size, preprocessing; int die_if_error = 0; @@ -196,9 +197,11 @@ int Wcast_truncate = 1; int Wcontext = 1; int Wdecl = 1; +int Wdeclarationafterstatement = -1; int Wdefault_bitfield_sign = 0; int Wdesignated_init = 1; int Wdo_while = 0; +int Winit_cstring = 0; int Wenum_mismatch = 1; int Wnon_pointer_null = 1; int Wold_initializer = 1; @@ -211,7 +214,7 @@ int Wtypesign = 0; int Wundef = 0; int Wuninitialized = 1; -int Wdeclarationafterstatement = -1; +int Wvla = 1; int dbg_entry = 0; int dbg_dead = 0; @@ -406,10 +409,12 @@ { "cast-truncate", &Wcast_truncate }, { "context", &Wcontext }, { "decl", &Wdecl }, + { "declaration-after-statement", &Wdeclarationafterstatement }, { "default-bitfield-sign", &Wdefault_bitfield_sign }, { "designated-init", &Wdesignated_init }, { "do-while", &Wdo_while }, { "enum-mismatch", &Wenum_mismatch }, + { "init-cstring", &Winit_cstring }, { "non-pointer-null", &Wnon_pointer_null }, { "old-initializer", &Wold_initializer }, { "one-bit-signed-bitfield", &Wone_bit_signed_bitfield }, @@ -421,7 +426,7 @@ { "typesign", &Wtypesign }, { "undef", &Wundef }, { "uninitialized", &Wuninitialized }, - { "declaration-after-statement", &Wdeclarationafterstatement }, + { "vla", &Wvla }, }; enum { @@ -646,11 +651,34 @@ return next; } +static char **handle_version(char *arg, char **next) +{ + printf("%s\n", SPARSE_VERSION); + exit(0); +} + struct switches { const char *name; char **(*fn)(char *, char **); }; +static char **handle_long_options(char *arg, char **next) +{ + static struct switches cmd[] = { + { "version", handle_version }, + { NULL, NULL } + }; + struct switches *s = cmd; + + while (s->name) { + if (!strcmp(s->name, arg)) + return s->fn(arg, next); + s++; + } + return next; + +} + static char **handle_switch(char *arg, char **next) { static struct switches cmd[] = { @@ -676,6 +704,7 @@ case 'G': return handle_switch_G(arg, next); case 'a': return handle_switch_a(arg, next); case 's': return handle_switch_s(arg, next); + case '-': return handle_long_options(arg + 1, next); default: break; } @@ -863,6 +892,7 @@ add_pre_buffer("#weak_define __LONG_MAX__ " STRINGIFY(__LONG_MAX__) "\n"); add_pre_buffer("#weak_define __LONG_LONG_MAX__ " STRINGIFY(__LONG_LONG_MAX__) "\n"); add_pre_buffer("#weak_define __WCHAR_MAX__ " STRINGIFY(__WCHAR_MAX__) "\n"); + add_pre_buffer("#weak_define __SIZEOF_POINTER__ " STRINGIFY(__SIZEOF_POINTER__) "\n"); } static struct symbol_list *sparse_tokenstream(struct token *token) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/lib.h new/sparse-20130425/lib.h --- old/sparse-20130225/lib.h 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/lib.h 2013-05-20 15:12:32.000000000 +0200 @@ -91,10 +91,12 @@ extern int Wcast_truncate; extern int Wcontext; extern int Wdecl; +extern int Wdeclarationafterstatement; extern int Wdefault_bitfield_sign; extern int Wdesignated_init; extern int Wdo_while; extern int Wenum_mismatch; +extern int Winit_cstring; extern int Wnon_pointer_null; extern int Wold_initializer; extern int Wone_bit_signed_bitfield; @@ -106,7 +108,7 @@ extern int Wtypesign; extern int Wundef; extern int Wuninitialized; -extern int Wdeclarationafterstatement; +extern int Wvla; extern int dbg_entry; extern int dbg_dead; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/parse.c new/sparse-20130425/parse.c --- old/sparse-20130225/parse.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/parse.c 2013-05-20 15:12:32.000000000 +0200 @@ -1841,6 +1841,7 @@ sym->ctype = ctx.ctype; sym->ctype.modifiers |= storage_modifiers(&ctx); sym->endpos = token->pos; + sym->forced_arg = ctx.storage_class == SForced; return token; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/pre-process.c new/sparse-20130425/pre-process.c --- old/sparse-20130225/pre-process.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/pre-process.c 2013-05-20 15:12:32.000000000 +0200 @@ -338,14 +338,16 @@ return res; } -static const char *quote_token_sequence(struct token *token) +static const char *show_token_sequence(struct token *token, int quote) { - static char buffer[1024]; + static char buffer[MAX_STRING]; char *ptr = buffer; int whitespace = 0; + if (!token && !quote) + return "<none>"; while (!eof_token(token)) { - const char *val = quote_token(token); + const char *val = quote ? quote_token(token) : show_token(token); int len = strlen(val); if (ptr + whitespace + len >= buffer + sizeof(buffer)) { @@ -366,7 +368,7 @@ static struct token *stringify(struct token *arg) { - const char *s = quote_token_sequence(arg); + const char *s = show_token_sequence(arg, 1); int size = strlen(s)+1; struct token *token = __alloc_token(0); struct string *string = __alloc_string(size); @@ -743,6 +745,11 @@ struct stream *s = input_streams + stream; next = s->next_stream; + if (s->once) { + if (strcmp(path, s->name)) + continue; + return 1; + } if (s->constant != CONSTANT_FILE_YES) continue; if (strcmp(path, s->name)) @@ -1436,7 +1443,7 @@ return preprocessor_if(stream, token, arg); } -static const char *show_token_sequence(struct token *token); +static const char *show_token_sequence(struct token *token, int quote); /* * Expression handling for #if and #elif; it differs from normal expansion @@ -1495,7 +1502,7 @@ p = constant_expression(*where, &expr); if (!eof_token(p)) - sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p)); + sparse_error(p->pos, "garbage at end: %s", show_token_sequence(p, 0)); value = get_expression_value(expr); return value != 0; } @@ -1584,43 +1591,15 @@ return 1; } -static const char *show_token_sequence(struct token *token) -{ - static char buffer[1024]; - char *ptr = buffer; - int whitespace = 0; - - if (!token) - return "<none>"; - while (!eof_token(token)) { - const char *val = show_token(token); - int len = strlen(val); - - if (ptr + whitespace + len >= buffer + sizeof(buffer)) { - sparse_error(token->pos, "too long token expansion"); - break; - } - - if (whitespace) - *ptr++ = ' '; - memcpy(ptr, val, len); - ptr += len; - token = token->next; - whitespace = token->pos.whitespace; - } - *ptr = 0; - return buffer; -} - static int handle_warning(struct stream *stream, struct token **line, struct token *token) { - warning(token->pos, "%s", show_token_sequence(token->next)); + warning(token->pos, "%s", show_token_sequence(token->next, 0)); return 1; } static int handle_error(struct stream *stream, struct token **line, struct token *token) { - sparse_error(token->pos, "%s", show_token_sequence(token->next)); + sparse_error(token->pos, "%s", show_token_sequence(token->next, 0)); return 1; } @@ -1809,6 +1788,10 @@ { struct token *next = *line; + if (match_ident(token->next, &once_ident) && eof_token(token->next->next)) { + stream->once = 1; + return 1; + } token->ident = &pragma_ident; token->pos.newline = 1; token->pos.whitespace = 1; @@ -1828,7 +1811,7 @@ static int handle_nondirective(struct stream *stream, struct token **line, struct token *token) { - sparse_error(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token)); + sparse_error(token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(token, 0)); return 1; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/sparse.1 new/sparse-20130425/sparse.1 --- old/sparse-20130225/sparse.1 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/sparse.1 2013-05-20 15:12:32.000000000 +0200 @@ -189,6 +189,24 @@ \fB\-Wno\-enum\-mismatch\fR. . .TP +.B \-Winit\-cstring +Warn about initialization of a char array with a too long constant C string. + +If the size of the char array and the length of the string is the same, +there is no space for the last nul char of the string in the array: + +.nf +char s[3] = "abc"; +.fi + +If the array is used as a byte array, not as C string, this +warning is just noise. However, if the array is passed to functions +dealing with C string like printf(%s) and strcmp, it may cause a +trouble. + +Sparse does not issue these warnings by default. +. +.TP .B \-Wnon\-pointer\-null Warn about the use of 0 as a NULL pointer. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/symbol.c new/sparse-20130425/symbol.c --- old/sparse-20130225/symbol.c 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/symbol.c 2013-05-20 15:12:32.000000000 +0200 @@ -211,13 +211,20 @@ static struct symbol * examine_array_type(struct symbol *sym) { struct symbol *base_type = examine_base_type(sym); - unsigned long bit_size, alignment; + unsigned long bit_size = -1, alignment; + struct expression *array_size = sym->array_size; if (!base_type) return sym; - bit_size = base_type->bit_size * get_expression_value(sym->array_size); - if (!sym->array_size || sym->array_size->type != EXPR_VALUE) - bit_size = -1; + + if (array_size) { + bit_size = base_type->bit_size * get_expression_value_silent(array_size); + if (array_size->type != EXPR_VALUE) { + if (Wvla) + warning(array_size->pos, "Variable length array is used."); + bit_size = -1; + } + } alignment = base_type->ctype.alignment; if (!sym->ctype.alignment) sym->ctype.alignment = alignment; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/symbol.h new/sparse-20130425/symbol.h --- old/sparse-20130225/symbol.h 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/symbol.h 2013-05-20 15:12:32.000000000 +0200 @@ -157,7 +157,8 @@ expanding:1, evaluated:1, string:1, - designated_init:1; + designated_init:1, + forced_arg:1; struct expression *array_size; struct ctype ctype; struct symbol_list *arguments; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/token.h new/sparse-20130425/token.h --- old/sparse-20130225/token.h 2013-03-09 10:45:43.000000000 +0100 +++ new/sparse-20130425/token.h 2013-05-20 15:12:32.000000000 +0200 @@ -40,7 +40,7 @@ /* Use these to check for "already parsed" */ enum constantfile constant; - int dirty, next_stream; + int dirty, next_stream, once; struct ident *protect; struct token *ifndef; struct token *top_if; @@ -179,7 +179,7 @@ }; }; -#define MAX_STRING 4095 +#define MAX_STRING 8191 static inline struct token *containing_token(struct token **p) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/validation/fored_arg.c new/sparse-20130425/validation/fored_arg.c --- old/sparse-20130225/validation/fored_arg.c 1970-01-01 01:00:00.000000000 +0100 +++ new/sparse-20130425/validation/fored_arg.c 2013-05-20 15:12:32.000000000 +0200 @@ -0,0 +1,18 @@ +/* + * check-name: Forced function argument type. + */ + +#define __iomem __attribute__((noderef, address_space(2))) +#define __force __attribute__((force)) + +static void foo(__force void * addr) +{ +} + + +static void bar(void) +{ + void __iomem *a; + foo(a); +} + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/validation/init_cstring.c new/sparse-20130425/validation/init_cstring.c --- old/sparse-20130225/validation/init_cstring.c 1970-01-01 01:00:00.000000000 +0100 +++ new/sparse-20130425/validation/init_cstring.c 2013-05-20 15:12:32.000000000 +0200 @@ -0,0 +1,11 @@ +static struct alpha { + char a[2]; +} x = { .a = "ab" }; +/* + * check-name: -Winit-cstring option + * + * check-command: sparse -Winit-cstring $file + * check-error-start +init_cstring.c:3:14: warning: too long initializer-string for array of char(no space for nul char) + * check-error-end + */ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sparse-20130225/validation/pragma-once.c new/sparse-20130425/validation/pragma-once.c --- old/sparse-20130225/validation/pragma-once.c 1970-01-01 01:00:00.000000000 +0100 +++ new/sparse-20130425/validation/pragma-once.c 2013-05-20 15:12:32.000000000 +0200 @@ -0,0 +1,5 @@ +#pragma once +#include "pragma-once.c" +/* + * check-name: #pragma once + */ -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
