summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makemodule.am6
-rw-r--r--lib/canonicalize.c187
-rw-r--r--lib/colors.c93
-rw-r--r--lib/crc64.c108
-rw-r--r--lib/exec_shell.c21
-rw-r--r--lib/loopdev.c86
-rw-r--r--lib/mbsalign.c4
-rw-r--r--lib/pager.c10
-rw-r--r--lib/path.c21
-rw-r--r--lib/strutils.c1
-rw-r--r--lib/sysfs.c3
-rw-r--r--lib/timeutils.c338
-rw-r--r--lib/tt.c10
13 files changed, 697 insertions, 191 deletions
diff --git a/lib/Makemodule.am b/lib/Makemodule.am
index afc2156c7..6a4787f1f 100644
--- a/lib/Makemodule.am
+++ b/lib/Makemodule.am
@@ -7,6 +7,7 @@ libcommon_la_SOURCES = \
lib/canonicalize.c \
lib/colors.c \
lib/crc32.c \
+ lib/crc64.c \
lib/env.c \
lib/fileutils.c \
lib/ismounted.c \
@@ -23,6 +24,7 @@ libcommon_la_SOURCES = \
lib/sysfs.c \
lib/tt.c \
lib/wholedisk.c \
+ lib/timeutils.c \
lib/ttyutils.c \
lib/xgetpass.c \
lib/exec_shell.c
@@ -45,6 +47,7 @@ check_PROGRAMS += \
test_at \
test_blkdev \
test_canonicalize \
+ test_colors \
test_fileutils \
test_ismounted \
test_mangle \
@@ -89,6 +92,9 @@ test_at_CFLAGS = -DTEST_PROGRAM_AT
test_strutils_SOURCES = lib/strutils.c
test_strutils_CFLAGS = -DTEST_PROGRAM
+test_colors_SOURCES = lib/colors.c
+test_colors_CFLAGS = -DTEST_PROGRAM
+
test_randutils_SOURCES = lib/randutils.c
test_randutils_CFLAGS = -DTEST_PROGRAM
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 727806e1e..cac60d7a4 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -1,24 +1,10 @@
/*
* canonicalize.c -- canonicalize pathname by removing symlinks
- * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library Public License as published by
- * the Free Software Foundation; either version 2, 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 Library Public License for more details.
+ * This file may be distributed under the terms of the
+ * GNU Lesser General Public License.
*
- */
-
-/*
- * This routine is part of libc. We include it nevertheless,
- * since the libc version has some security flaws.
- *
- * TODO: use canonicalize_file_name() when exist in glibc
+ * Copyright (C) 2009-2013 Karel Zak <kzak@redhat.com>
*/
#include <stdio.h>
#include <string.h>
@@ -26,131 +12,26 @@
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "canonicalize.h"
-#ifndef MAXSYMLINKS
-# define MAXSYMLINKS 256
-#endif
-
-static char *
-myrealpath(const char *path, char *resolved_path, int maxreslth) {
- int readlinks = 0;
- char *npath;
- char link_path[PATH_MAX+1];
- int n;
- char *buf = NULL;
-
- npath = resolved_path;
-
- /* If it's a relative pathname use getcwd for starters. */
- if (*path != '/') {
- if (!getcwd(npath, maxreslth-2))
- return NULL;
- npath += strlen(npath);
- if (npath[-1] != '/')
- *npath++ = '/';
- } else {
- *npath++ = '/';
- path++;
- }
-
- /* Expand each slash-separated pathname component. */
- while (*path != '\0') {
- /* Ignore stray "/" */
- if (*path == '/') {
- path++;
- continue;
- }
- if (*path == '.' && (path[1] == '\0' || path[1] == '/')) {
- /* Ignore "." */
- path++;
- continue;
- }
- if (*path == '.' && path[1] == '.' &&
- (path[2] == '\0' || path[2] == '/')) {
- /* Backup for ".." */
- path += 2;
- while (npath > resolved_path+1 &&
- (--npath)[-1] != '/')
- ;
- continue;
- }
- /* Safely copy the next pathname component. */
- while (*path != '\0' && *path != '/') {
- if (npath-resolved_path > maxreslth-2) {
- errno = ENAMETOOLONG;
- goto err;
- }
- *npath++ = *path++;
- }
-
- /* Protect against infinite loops. */
- if (readlinks++ > MAXSYMLINKS) {
- errno = ELOOP;
- goto err;
- }
-
- /* See if last pathname component is a symlink. */
- *npath = '\0';
- n = readlink(resolved_path, link_path, PATH_MAX);
- if (n < 0) {
- /* EINVAL means the file exists but isn't a symlink. */
- if (errno != EINVAL)
- goto err;
- } else {
- int m;
- char *newbuf;
-
- /* Note: readlink doesn't add the null byte. */
- link_path[n] = '\0';
- if (*link_path == '/')
- /* Start over for an absolute symlink. */
- npath = resolved_path;
- else
- /* Otherwise back up over this component. */
- while (*(--npath) != '/')
- ;
-
- /* Insert symlink contents into path. */
- m = strlen(path);
- newbuf = malloc(m + n + 1);
- if (!newbuf)
- goto err;
- memcpy(newbuf, link_path, n);
- memcpy(newbuf + n, path, m + 1);
- free(buf);
- path = buf = newbuf;
- }
- *npath++ = '/';
- }
- /* Delete trailing slash but don't whomp a lone slash. */
- if (npath != resolved_path+1 && npath[-1] == '/')
- npath--;
- /* Make sure it's null terminated. */
- *npath = '\0';
-
- free(buf);
- return resolved_path;
-
- err:
- free(buf);
- return NULL;
-}
-
/*
* Converts private "dm-N" names to "/dev/mapper/<name>"
*
* Since 2.6.29 (patch 784aae735d9b0bba3f8b9faef4c8b30df3bf0128) kernel sysfs
* provides the real DM device names in /sys/block/<ptname>/dm/name
*/
-char *
-canonicalize_dm_name(const char *ptname)
+char *canonicalize_dm_name(const char *ptname)
{
FILE *f;
size_t sz;
char path[256], name[256], *res = NULL;
+ if (!ptname || !*ptname)
+ return NULL;
+
snprintf(path, sizeof(path), "/sys/block/%s/dm/name", ptname);
if (!(f = fopen(path, "r" UL_CLOEXECSTR)))
return NULL;
@@ -167,39 +48,37 @@ canonicalize_dm_name(const char *ptname)
return res;
}
-char *
-canonicalize_path(const char *path)
+char *canonicalize_path(const char *path)
{
- char canonical[PATH_MAX+2];
- char *p;
+ char *canonical, *p;
- if (path == NULL)
+ if (!path || !*path)
return NULL;
- if (!myrealpath(path, canonical, PATH_MAX+1))
+ canonical = realpath(path, NULL);
+ if (!canonical)
return strdup(path);
-
p = strrchr(canonical, '/');
if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
- p = canonicalize_dm_name(p+1);
- if (p)
- return p;
+ char *dm = canonicalize_dm_name(p + 1);
+ if (dm) {
+ free(canonical);
+ return dm;
+ }
}
- return strdup(canonical);
+ return canonical;
}
-char *
-canonicalize_path_restricted(const char *path)
+char *canonicalize_path_restricted(const char *path)
{
- char canonical[PATH_MAX+2];
- char *p = NULL;
+ char *canonical, *p = NULL;
int errsv;
uid_t euid;
gid_t egid;
- if (path == NULL)
+ if (!path || !*path)
return NULL;
euid = geteuid();
@@ -211,25 +90,27 @@ canonicalize_path_restricted(const char *path)
errsv = errno = 0;
- if (myrealpath(path, canonical, PATH_MAX+1)) {
+ canonical = realpath(path, NULL);
+ if (canonical) {
p = strrchr(canonical, '/');
- if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4)))
- p = canonicalize_dm_name(p+1);
- else
- p = NULL;
- if (!p)
- p = strdup(canonical);
+ if (p && strncmp(p, "/dm-", 4) == 0 && isdigit(*(p + 4))) {
+ char *dm = canonicalize_dm_name(p + 1);
+ if (dm) {
+ free(canonical);
+ canonical = dm;
+ }
+ }
} else
errsv = errno;
/* restore */
if (setegid(egid) < 0 || seteuid(euid) < 0) {
- free(p);
+ free(canonical);
return NULL;
}
errno = errsv;
- return p;
+ return canonical;
}
diff --git a/lib/colors.c b/lib/colors.c
index 6af038b31..51faa010a 100644
--- a/lib/colors.c
+++ b/lib/colors.c
@@ -4,25 +4,106 @@
* This file may be distributed under the terms of the
* GNU Lesser General Public License.
*/
+#include <c.h>
+#include <assert.h>
#include "colors.h"
static int ul_color_term_ok;
-int colors_init(void)
+int colors_init(int mode)
{
- ul_color_term_ok = isatty(STDOUT_FILENO);
+ switch (mode) {
+ case UL_COLORMODE_AUTO:
+ ul_color_term_ok = isatty(STDOUT_FILENO);
+ break;
+ case UL_COLORMODE_ALWAYS:
+ ul_color_term_ok = 1;
+ break;
+ case UL_COLORMODE_NEVER:
+ default:
+ ul_color_term_ok = 0;
+ }
return ul_color_term_ok;
}
-void color_enable(const char *color_scheme)
+int colors_wanted(void)
+{
+ return ul_color_term_ok;
+}
+
+void color_fenable(const char *color_scheme, FILE *f)
{
if (ul_color_term_ok && color_scheme)
- fputs(color_scheme, stdout);
+ fputs(color_scheme, f);
}
-void color_disable(void)
+void color_fdisable(FILE *f)
{
if (ul_color_term_ok)
- fputs(UL_COLOR_RESET, stdout);
+ fputs(UL_COLOR_RESET, f);
+}
+
+int colormode_from_string(const char *str)
+{
+ size_t i;
+ static const char *modes[] = {
+ [UL_COLORMODE_AUTO] = "auto",
+ [UL_COLORMODE_NEVER] = "never",
+ [UL_COLORMODE_ALWAYS] = "always"
+ };
+
+ if (!str || !*str)
+ return -EINVAL;
+
+ assert(ARRAY_SIZE(modes) == __UL_NCOLORMODES);
+
+ for (i = 0; i < ARRAY_SIZE(modes); i++) {
+ if (strcasecmp(str, modes[i]) == 0)
+ return i;
+ }
+
+ return -EINVAL;
}
+
+int colormode_or_err(const char *str, const char *errmsg)
+{
+ const char *p = str && *str == '=' ? str + 1 : str;
+ int colormode;
+
+ colormode = colormode_from_string(p);
+ if (colormode < 0)
+ errx(EXIT_FAILURE, "%s: '%s'", errmsg, p);
+
+ return colormode;
+}
+
+
+#ifdef TEST_PROGRAM
+# include <getopt.h>
+int main(int argc, char *argv[])
+{
+ static const struct option longopts[] = {
+ { "colors", optional_argument, 0, 'c' },
+ { NULL, 0, 0, 0 }
+ };
+ int c, mode = UL_COLORMODE_NEVER; /* default */
+
+ while ((c = getopt_long(argc, argv, "c::", longopts, NULL)) != -1) {
+ switch (c) {
+ case 'c':
+ mode = UL_COLORMODE_AUTO;
+ if (optarg)
+ mode = colormode_or_err(optarg, "unsupported color mode");
+ break;
+ }
+ }
+
+ colors_init(mode);
+ color_enable(UL_COLOR_RED);
+ printf("Hello World!");
+ color_disable();
+ return EXIT_SUCCESS;
+}
+#endif
+
diff --git a/lib/crc64.c b/lib/crc64.c
new file mode 100644
index 000000000..091e95d76
--- /dev/null
+++ b/lib/crc64.c
@@ -0,0 +1,108 @@
+#include "crc64.h"
+
+static const uint64_t crc64_tab[256] = {
+ 0x0000000000000000ULL, 0x42F0E1EBA9EA3693ULL, 0x85E1C3D753D46D26ULL,
+ 0xC711223CFA3E5BB5ULL, 0x493366450E42ECDFULL, 0x0BC387AEA7A8DA4CULL,
+ 0xCCD2A5925D9681F9ULL, 0x8E224479F47CB76AULL, 0x9266CC8A1C85D9BEULL,
+ 0xD0962D61B56FEF2DULL, 0x17870F5D4F51B498ULL, 0x5577EEB6E6BB820BULL,
+ 0xDB55AACF12C73561ULL, 0x99A54B24BB2D03F2ULL, 0x5EB4691841135847ULL,
+ 0x1C4488F3E8F96ED4ULL, 0x663D78FF90E185EFULL, 0x24CD9914390BB37CULL,
+ 0xE3DCBB28C335E8C9ULL, 0xA12C5AC36ADFDE5AULL, 0x2F0E1EBA9EA36930ULL,
+ 0x6DFEFF5137495FA3ULL, 0xAAEFDD6DCD770416ULL, 0xE81F3C86649D3285ULL,
+ 0xF45BB4758C645C51ULL, 0xB6AB559E258E6AC2ULL, 0x71BA77A2DFB03177ULL,
+ 0x334A9649765A07E4ULL, 0xBD68D2308226B08EULL, 0xFF9833DB2BCC861DULL,
+ 0x388911E7D1F2DDA8ULL, 0x7A79F00C7818EB3BULL, 0xCC7AF1FF21C30BDEULL,
+ 0x8E8A101488293D4DULL, 0x499B3228721766F8ULL, 0x0B6BD3C3DBFD506BULL,
+ 0x854997BA2F81E701ULL, 0xC7B97651866BD192ULL, 0x00A8546D7C558A27ULL,
+ 0x4258B586D5BFBCB4ULL, 0x5E1C3D753D46D260ULL, 0x1CECDC9E94ACE4F3ULL,
+ 0xDBFDFEA26E92BF46ULL, 0x990D1F49C77889D5ULL, 0x172F5B3033043EBFULL,
+ 0x55DFBADB9AEE082CULL, 0x92CE98E760D05399ULL, 0xD03E790CC93A650AULL,
+ 0xAA478900B1228E31ULL, 0xE8B768EB18C8B8A2ULL, 0x2FA64AD7E2F6E317ULL,
+ 0x6D56AB3C4B1CD584ULL, 0xE374EF45BF6062EEULL, 0xA1840EAE168A547DULL,
+ 0x66952C92ECB40FC8ULL, 0x2465CD79455E395BULL, 0x3821458AADA7578FULL,
+ 0x7AD1A461044D611CULL, 0xBDC0865DFE733AA9ULL, 0xFF3067B657990C3AULL,
+ 0x711223CFA3E5BB50ULL, 0x33E2C2240A0F8DC3ULL, 0xF4F3E018F031D676ULL,
+ 0xB60301F359DBE0E5ULL, 0xDA050215EA6C212FULL, 0x98F5E3FE438617BCULL,
+ 0x5FE4C1C2B9B84C09ULL, 0x1D14202910527A9AULL, 0x93366450E42ECDF0ULL,
+ 0xD1C685BB4DC4FB63ULL, 0x16D7A787B7FAA0D6ULL, 0x5427466C1E109645ULL,
+ 0x4863CE9FF6E9F891ULL, 0x0A932F745F03CE02ULL, 0xCD820D48A53D95B7ULL,
+ 0x8F72ECA30CD7A324ULL, 0x0150A8DAF8AB144EULL, 0x43A04931514122DDULL,
+ 0x84B16B0DAB7F7968ULL, 0xC6418AE602954FFBULL, 0xBC387AEA7A8DA4C0ULL,
+ 0xFEC89B01D3679253ULL, 0x39D9B93D2959C9E6ULL, 0x7B2958D680B3FF75ULL,
+ 0xF50B1CAF74CF481FULL, 0xB7FBFD44DD257E8CULL, 0x70EADF78271B2539ULL,
+ 0x321A3E938EF113AAULL, 0x2E5EB66066087D7EULL, 0x6CAE578BCFE24BEDULL,
+ 0xABBF75B735DC1058ULL, 0xE94F945C9C3626CBULL, 0x676DD025684A91A1ULL,
+ 0x259D31CEC1A0A732ULL, 0xE28C13F23B9EFC87ULL, 0xA07CF2199274CA14ULL,
+ 0x167FF3EACBAF2AF1ULL, 0x548F120162451C62ULL, 0x939E303D987B47D7ULL,
+ 0xD16ED1D631917144ULL, 0x5F4C95AFC5EDC62EULL, 0x1DBC74446C07F0BDULL,
+ 0xDAAD56789639AB08ULL, 0x985DB7933FD39D9BULL, 0x84193F60D72AF34FULL,
+ 0xC6E9DE8B7EC0C5DCULL, 0x01F8FCB784FE9E69ULL, 0x43081D5C2D14A8FAULL,
+ 0xCD2A5925D9681F90ULL, 0x8FDAB8CE70822903ULL, 0x48CB9AF28ABC72B6ULL,
+ 0x0A3B7B1923564425ULL, 0x70428B155B4EAF1EULL, 0x32B26AFEF2A4998DULL,
+ 0xF5A348C2089AC238ULL, 0xB753A929A170F4ABULL, 0x3971ED50550C43C1ULL,
+ 0x7B810CBBFCE67552ULL, 0xBC902E8706D82EE7ULL, 0xFE60CF6CAF321874ULL,
+ 0xE224479F47CB76A0ULL, 0xA0D4A674EE214033ULL, 0x67C58448141F1B86ULL,
+ 0x253565A3BDF52D15ULL, 0xAB1721DA49899A7FULL, 0xE9E7C031E063ACECULL,
+ 0x2EF6E20D1A5DF759ULL, 0x6C0603E6B3B7C1CAULL, 0xF6FAE5C07D3274CDULL,
+ 0xB40A042BD4D8425EULL, 0x731B26172EE619EBULL, 0x31EBC7FC870C2F78ULL,
+ 0xBFC9838573709812ULL, 0xFD39626EDA9AAE81ULL, 0x3A28405220A4F534ULL,
+ 0x78D8A1B9894EC3A7ULL, 0x649C294A61B7AD73ULL, 0x266CC8A1C85D9BE0ULL,
+ 0xE17DEA9D3263C055ULL, 0xA38D0B769B89F6C6ULL, 0x2DAF4F0F6FF541ACULL,
+ 0x6F5FAEE4C61F773FULL, 0xA84E8CD83C212C8AULL, 0xEABE6D3395CB1A19ULL,
+ 0x90C79D3FEDD3F122ULL, 0xD2377CD44439C7B1ULL, 0x15265EE8BE079C04ULL,
+ 0x57D6BF0317EDAA97ULL, 0xD9F4FB7AE3911DFDULL, 0x9B041A914A7B2B6EULL,
+ 0x5C1538ADB04570DBULL, 0x1EE5D94619AF4648ULL, 0x02A151B5F156289CULL,
+ 0x4051B05E58BC1E0FULL, 0x87409262A28245BAULL, 0xC5B073890B687329ULL,
+ 0x4B9237F0FF14C443ULL, 0x0962D61B56FEF2D0ULL, 0xCE73F427ACC0A965ULL,
+ 0x8C8315CC052A9FF6ULL, 0x3A80143F5CF17F13ULL, 0x7870F5D4F51B4980ULL,
+ 0xBF61D7E80F251235ULL, 0xFD913603A6CF24A6ULL, 0x73B3727A52B393CCULL,
+ 0x31439391FB59A55FULL, 0xF652B1AD0167FEEAULL, 0xB4A25046A88DC879ULL,
+ 0xA8E6D8B54074A6ADULL, 0xEA16395EE99E903EULL, 0x2D071B6213A0CB8BULL,
+ 0x6FF7FA89BA4AFD18ULL, 0xE1D5BEF04E364A72ULL, 0xA3255F1BE7DC7CE1ULL,
+ 0x64347D271DE22754ULL, 0x26C49CCCB40811C7ULL, 0x5CBD6CC0CC10FAFCULL,
+ 0x1E4D8D2B65FACC6FULL, 0xD95CAF179FC497DAULL, 0x9BAC4EFC362EA149ULL,
+ 0x158E0A85C2521623ULL, 0x577EEB6E6BB820B0ULL, 0x906FC95291867B05ULL,
+ 0xD29F28B9386C4D96ULL, 0xCEDBA04AD0952342ULL, 0x8C2B41A1797F15D1ULL,
+ 0x4B3A639D83414E64ULL, 0x09CA82762AAB78F7ULL, 0x87E8C60FDED7CF9DULL,
+ 0xC51827E4773DF90EULL, 0x020905D88D03A2BBULL, 0x40F9E43324E99428ULL,
+ 0x2CFFE7D5975E55E2ULL, 0x6E0F063E3EB46371ULL, 0xA91E2402C48A38C4ULL,
+ 0xEBEEC5E96D600E57ULL, 0x65CC8190991CB93DULL, 0x273C607B30F68FAEULL,
+ 0xE02D4247CAC8D41BULL, 0xA2DDA3AC6322E288ULL, 0xBE992B5F8BDB8C5CULL,
+ 0xFC69CAB42231BACFULL, 0x3B78E888D80FE17AULL, 0x7988096371E5D7E9ULL,
+ 0xF7AA4D1A85996083ULL, 0xB55AACF12C735610ULL, 0x724B8ECDD64D0DA5ULL,
+ 0x30BB6F267FA73B36ULL, 0x4AC29F2A07BFD00DULL, 0x08327EC1AE55E69EULL,
+ 0xCF235CFD546BBD2BULL, 0x8DD3BD16FD818BB8ULL, 0x03F1F96F09FD3CD2ULL,
+ 0x41011884A0170A41ULL, 0x86103AB85A2951F4ULL, 0xC4E0DB53F3C36767ULL,
+ 0xD8A453A01B3A09B3ULL, 0x9A54B24BB2D03F20ULL, 0x5D45907748EE6495ULL,
+ 0x1FB5719CE1045206ULL, 0x919735E51578E56CULL, 0xD367D40EBC92D3FFULL,
+ 0x1476F63246AC884AULL, 0x568617D9EF46BED9ULL, 0xE085162AB69D5E3CULL,
+ 0xA275F7C11F7768AFULL, 0x6564D5FDE549331AULL, 0x279434164CA30589ULL,
+ 0xA9B6706FB8DFB2E3ULL, 0xEB46918411358470ULL, 0x2C57B3B8EB0BDFC5ULL,
+ 0x6EA7525342E1E956ULL, 0x72E3DAA0AA188782ULL, 0x30133B4B03F2B111ULL,
+ 0xF7021977F9CCEAA4ULL, 0xB5F2F89C5026DC37ULL, 0x3BD0BCE5A45A6B5DULL,
+ 0x79205D0E0DB05DCEULL, 0xBE317F32F78E067BULL, 0xFCC19ED95E6430E8ULL,
+ 0x86B86ED5267CDBD3ULL, 0xC4488F3E8F96ED40ULL, 0x0359AD0275A8B6F5ULL,
+ 0x41A94CE9DC428066ULL, 0xCF8B0890283E370CULL, 0x8D7BE97B81D4019FULL,
+ 0x4A6ACB477BEA5A2AULL, 0x089A2AACD2006CB9ULL, 0x14DEA25F3AF9026DULL,
+ 0x562E43B4931334FEULL, 0x913F6188692D6F4BULL, 0xD3CF8063C0C759D8ULL,
+ 0x5DEDC41A34BBEEB2ULL, 0x1F1D25F19D51D821ULL, 0xD80C07CD676F8394ULL,
+ 0x9AFCE626CE85B507ULL
+};
+
+/*
+ * This a generic crc64() function, it takes seed as an argument,
+ * and does __not__ xor at the end. Then individual users can do
+ * whatever they need.
+ */
+uint64_t crc64(uint64_t seed, const unsigned char *data, size_t len)
+{
+ uint64_t crc = seed;
+
+ while (len--) {
+ int i = ((int) (crc >> 56) ^ *data++) & 0xFF;
+ crc = crc64_tab[i] ^ (crc << 8);
+ }
+
+ return crc;
+}
+
diff --git a/lib/exec_shell.c b/lib/exec_shell.c
index 95620cd4d..2b263644d 100644
--- a/lib/exec_shell.c
+++ b/lib/exec_shell.c
@@ -1,3 +1,21 @@
+/*
+ * exec_shell() - launch a shell, else exit!
+ *
+ * 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, 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.
+ */
+
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -11,7 +29,8 @@
#define DEFAULT_SHELL "/bin/sh"
-void __attribute__((__noreturn__)) exec_shell(void) {
+void exec_shell(void)
+{
const char *shell = getenv("SHELL"), *shell_basename;
char *arg0;
if (!shell)
diff --git a/lib/loopdev.c b/lib/loopdev.c
index 3b65b5d29..ebb7ee293 100644
--- a/lib/loopdev.c
+++ b/lib/loopdev.c
@@ -291,9 +291,8 @@ int loopcxt_get_fd(struct loopdev_cxt *lc)
if (lc->fd < 0) {
lc->mode = lc->flags & LOOPDEV_FL_RDWR ? O_RDWR : O_RDONLY;
lc->fd = open(lc->device, lc->mode | O_CLOEXEC);
- DBG(lc, loopdev_debug("open %s [%s]: %s", lc->device,
- lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro",
- lc->fd < 0 ? "failed" : "ok"));
+ DBG(lc, loopdev_debug("open %s [%s]: %m", lc->device,
+ lc->flags & LOOPDEV_FL_RDWR ? "rw" : "ro"));
}
return lc->fd;
}
@@ -1094,13 +1093,16 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
if (!lc->info.lo_offset && !lc->info.lo_sizelimit)
return 0;
- if (fstat(file_fd, &st))
+ if (fstat(file_fd, &st)) {
+ DBG(lc, loopdev_debug("failed to fstat backing file"));
return -errno;
-
+ }
if (S_ISBLK(st.st_mode)) {
if (blkdev_get_size(file_fd,
- (unsigned long long *) &expected_size))
+ (unsigned long long *) &expected_size)) {
+ DBG(lc, loopdev_debug("failed to determine device size"));
return -errno;
+ }
} else
expected_size = st.st_size;
@@ -1116,11 +1118,21 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
expected_size = lc->info.lo_sizelimit;
dev_fd = loopcxt_get_fd(lc);
- if (dev_fd < 0)
+ if (dev_fd < 0) {
+ DBG(lc, loopdev_debug("failed to get loop FD"));
return -errno;
+ }
- if (blkdev_get_size(dev_fd, (unsigned long long *) &size))
+ if (blkdev_get_size(dev_fd, (unsigned long long *) &size)) {
+ DBG(lc, loopdev_debug("failed to determine loopdev size"));
return -errno;
+ }
+
+ /* It's block device, so, align to 512-byte sectors */
+ if (expected_size % 512) {
+ DBG(lc, loopdev_debug("expected size misaligned to 512-byte sectors"));
+ expected_size = (expected_size >> 9) << 9;
+ }
if (expected_size != size) {
DBG(lc, loopdev_debug("warning: loopdev and expected "
@@ -1137,8 +1149,13 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
if (blkdev_get_size(dev_fd, (unsigned long long *) &size))
return -errno;
- if (expected_size != size)
- return -ERANGE;
+ if (expected_size != size) {
+ errno = ERANGE;
+ DBG(lc, loopdev_debug("failed to set loopdev size, "
+ "size: %ju, expected: %ju",
+ size, expected_size));
+ return -errno;
+ }
}
return 0;
@@ -1164,7 +1181,7 @@ static int loopcxt_check_size(struct loopdev_cxt *lc, int file_fd)
*/
int loopcxt_setup_device(struct loopdev_cxt *lc)
{
- int file_fd, dev_fd, mode = O_RDWR, rc = -1;
+ int file_fd, dev_fd, mode = O_RDWR, rc = -1, cnt = 0;
if (!lc || !*lc->device || !lc->filename)
return -EINVAL;
@@ -1204,7 +1221,19 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
lc->flags &= ~LOOPDEV_FL_RDONLY;
}
- dev_fd = loopcxt_get_fd(lc);
+ do {
+ errno = 0;
+ dev_fd = loopcxt_get_fd(lc);
+ if (dev_fd >= 0 || lc->control_ok == 0)
+ break;
+ if (errno != EACCES && errno != ENOENT)
+ break;
+ /* We have permissions to open /dev/loop-control, but open
+ * /dev/loopN failed with EACCES, it's probably because udevd
+ * does not applied chown yet. Let's wait a moment. */
+ usleep(25000);
+ } while (cnt++ < 16);
+
if (dev_fd < 0) {
rc = -errno;
goto err;
@@ -1234,7 +1263,6 @@ int loopcxt_setup_device(struct loopdev_cxt *lc)
goto err;
close(file_fd);
- file_fd = -1;
memset(&lc->info, 0, sizeof(lc->info));
lc->has_info = 0;
@@ -1286,6 +1314,37 @@ int loopcxt_delete_device(struct loopdev_cxt *lc)
return 0;
}
+int loopcxt_add_device(struct loopdev_cxt *lc)
+{
+ int rc = -EINVAL;
+ int ctl, nr = -1;
+ const char *p, *dev = loopcxt_get_device(lc);
+
+ if (!dev)
+ goto done;
+
+ if (!(lc->flags & LOOPDEV_FL_CONTROL)) {
+ rc = -ENOSYS;
+ goto done;
+ }
+
+ p = strrchr(dev, '/');
+ if (!p || (sscanf(p, "/loop%d", &nr) != 1 && sscanf(p, "/%d", &nr) != 1)
+ || nr < 0)
+ goto done;
+
+ ctl = open(_PATH_DEV_LOOPCTL, O_RDWR|O_CLOEXEC);
+ if (ctl >= 0) {
+ DBG(lc, loopdev_debug("add_device %d", nr));
+ rc = ioctl(ctl, LOOP_CTL_ADD, nr);
+ close(ctl);
+ }
+ lc->control_ok = rc >= 0 ? 1 : 0;
+done:
+ DBG(lc, loopdev_debug("add_device done [rc=%d]", rc));
+ return rc;
+}
+
/*
* Note that LOOP_CTL_GET_FREE ioctl is supported since kernel 3.1. In older
* kernels we have to check all loop devices to found unused one.
@@ -1309,6 +1368,7 @@ int loopcxt_find_unused(struct loopdev_cxt *lc)
rc = loopiter_set_device(lc, name);
}
+ lc->control_ok = ctl >= 0 && rc == 0 ? 1 : 0;
if (ctl >= 0)
close(ctl);
DBG(lc, loopdev_debug("find_unused by loop-control [rc=%d]", rc));
diff --git a/lib/mbsalign.c b/lib/mbsalign.c
index e420fea66..89ef03298 100644
--- a/lib/mbsalign.c
+++ b/lib/mbsalign.c
@@ -254,8 +254,8 @@ mbsalign_unibyte:
if (dest_size != 0)
{
char *dest_end = dest + dest_size - 1;
- size_t start_spaces = n_spaces / 2 + n_spaces % 2;
- size_t end_spaces = n_spaces / 2;
+ size_t start_spaces;
+ size_t end_spaces;
switch (align)
{
diff --git a/lib/pager.c b/lib/pager.c
index 5cf8c03b5..c6e74e899 100644
--- a/lib/pager.c
+++ b/lib/pager.c
@@ -40,16 +40,6 @@ static inline void close_pair(int fd[2])
close(fd[1]);
}
-static inline void dup_devnull(int to)
-{
- int fd = open(NULL_DEVICE, O_RDWR);
-
- if (fd < 0)
- err(EXIT_FAILURE, _("cannot open %s"), NULL_DEVICE);
- dup2(fd, to);
- close(fd);
-}
-
static int start_command(struct child_process *cmd)
{
int need_in;
diff --git a/lib/path.c b/lib/path.c
index 7a68d9fe2..42d321cb6 100644
--- a/lib/path.c
+++ b/lib/path.c
@@ -49,6 +49,19 @@ path_vcreate(const char *path, va_list ap)
return pathbuf;
}
+char *
+path_strdup(const char *path, ...)
+{
+ const char *p;
+ va_list ap;
+
+ va_start(ap, path);
+ p = path_vcreate(path, ap);
+ va_end(ap);
+
+ return p ? strdup(p) : NULL;
+}
+
static FILE *
path_vfopen(const char *mode, int exit_on_error, const char *path, va_list ap)
{
@@ -97,7 +110,7 @@ path_read_str(char *result, size_t len, const char *path, ...)
va_end(ap);
if (!fgets(result, len, fd))
- err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+ err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
fclose(fd);
len = strlen(result);
@@ -118,7 +131,7 @@ path_read_s32(const char *path, ...)
if (fscanf(fd, "%d", &result) != 1) {
if (ferror(fd))
- err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+ err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
else
errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
}
@@ -139,7 +152,7 @@ path_read_u64(const char *path, ...)
if (fscanf(fd, "%"SCNu64, &result) != 1) {
if (ferror(fd))
- err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+ err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
else
errx(EXIT_FAILURE, _("parse error: %s"), pathbuf);
}
@@ -187,7 +200,7 @@ path_cpuparse(int maxcpus, int islist, const char *path, va_list ap)
fd = path_vfopen("r" UL_CLOEXECSTR, 1, path, ap);
if (!fgets(buf, len, fd))
- err(EXIT_FAILURE, _("failed to read: %s"), pathbuf);
+ err(EXIT_FAILURE, _("cannot read %s"), pathbuf);
fclose(fd);
len = strlen(buf);
diff --git a/lib/strutils.c b/lib/strutils.c
index c263b86b2..69b7ba23f 100644
--- a/lib/strutils.c
+++ b/lib/strutils.c
@@ -10,6 +10,7 @@
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
+#include <assert.h>
#include "c.h"
#include "nls.h"
diff --git a/lib/sysfs.c b/lib/sysfs.c
index ed0173a1c..ba3a0d030 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -290,7 +290,8 @@ int sysfs_is_partition_dirent(DIR *dir, struct dirent *d, const char *parent_nam
#ifdef _DIRENT_HAVE_D_TYPE
if (d->d_type != DT_DIR &&
- d->d_type != DT_LNK)
+ d->d_type != DT_LNK &&
+ d->d_type != DT_UNKNOWN)
return 0;
#endif
if (parent_name) {
diff --git a/lib/timeutils.c b/lib/timeutils.c
new file mode 100644
index 000000000..7fe62187d
--- /dev/null
+++ b/lib/timeutils.c
@@ -0,0 +1,338 @@
+/***
+ First set of functions in this file are part of systemd, and were
+ copied to util-linux at August 2013.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with util-linux; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+
+#include "c.h"
+#include "strutils.h"
+#include "timeutils.h"
+
+#define WHITESPACE " \t\n\r"
+
+#define streq(a,b) (strcmp((a),(b)) == 0)
+
+static int parse_sec(const char *t, usec_t *usec)
+{
+ static const struct {
+ const char *suffix;
+ usec_t usec;
+ } table[] = {
+ { "seconds", USEC_PER_SEC },
+ { "second", USEC_PER_SEC },
+ { "sec", USEC_PER_SEC },
+ { "s", USEC_PER_SEC },
+ { "minutes", USEC_PER_MINUTE },
+ { "minute", USEC_PER_MINUTE },
+ { "min", USEC_PER_MINUTE },
+ { "months", USEC_PER_MONTH },
+ { "month", USEC_PER_MONTH },
+ { "msec", USEC_PER_MSEC },
+ { "ms", USEC_PER_MSEC },
+ { "m", USEC_PER_MINUTE },
+ { "hours", USEC_PER_HOUR },
+ { "hour", USEC_PER_HOUR },
+ { "hr", USEC_PER_HOUR },
+ { "h", USEC_PER_HOUR },
+ { "days", USEC_PER_DAY },
+ { "day", USEC_PER_DAY },
+ { "d", USEC_PER_DAY },
+ { "weeks", USEC_PER_WEEK },
+ { "week", USEC_PER_WEEK },
+ { "w", USEC_PER_WEEK },
+ { "years", USEC_PER_YEAR },
+ { "year", USEC_PER_YEAR },
+ { "y", USEC_PER_YEAR },
+ { "usec", 1ULL },
+ { "us", 1ULL },
+ { "", USEC_PER_SEC }, /* default is sec */
+ };
+
+ const char *p;
+ usec_t r = 0;
+ int something = FALSE;
+
+ assert(t);
+ assert(usec);
+
+ p = t;
+ for (;;) {
+ long long l, z = 0;
+ char *e;
+ unsigned i, n = 0;
+
+ p += strspn(p, WHITESPACE);
+
+ if (*p == 0) {
+ if (!something)
+ return -EINVAL;
+
+ break;
+ }
+
+ errno = 0;
+ l = strtoll(p, &e, 10);
+
+ if (errno > 0)
+ return -errno;
+
+ if (l < 0)
+ return -ERANGE;
+
+ if (*e == '.') {
+ char *b = e + 1;
+
+ errno = 0;
+ z = strtoll(b, &e, 10);
+ if (errno > 0)
+ return -errno;
+
+ if (z < 0)
+ return -ERANGE;
+
+ if (e == b)
+ return -EINVAL;
+
+ n = e - b;
+
+ } else if (e == p)
+ return -EINVAL;
+
+ e += strspn(e, WHITESPACE);
+
+ for (i = 0; i < ARRAY_SIZE(table); i++)
+ if (startswith(e, table[i].suffix)) {
+ usec_t k = (usec_t) z * table[i].usec;
+
+ for (; n > 0; n--)
+ k /= 10;
+
+ r += (usec_t) l *table[i].usec + k;
+ p = e + strlen(table[i].suffix);
+
+ something = TRUE;
+ break;
+ }
+
+ if (i >= ARRAY_SIZE(table))
+ return -EINVAL;
+
+ }
+
+ *usec = r;
+
+ return 0;
+}
+
+int parse_timestamp(const char *t, usec_t *usec)
+{
+ static const struct {
+ const char *name;
+ const int nr;
+ } day_nr[] = {
+ { "Sunday", 0 },
+ { "Sun", 0 },
+ { "Monday", 1 },
+ { "Mon", 1 },
+ { "Tuesday", 2 },
+ { "Tue", 2 },
+ { "Wednesday", 3 },
+ { "Wed", 3 },
+ { "Thursday", 4 },
+ { "Thu", 4 },
+ { "Friday", 5 },
+ { "Fri", 5 },
+ { "Saturday", 6 },
+ { "Sat", 6 },
+ };
+
+ const char *k;
+ struct tm tm, copy;
+ time_t x;
+ usec_t plus = 0, minus = 0, ret;
+ int r, weekday = -1;
+ unsigned i;
+
+ /*
+ * Allowed syntaxes:
+ *
+ * 2012-09-22 16:34:22
+ * 2012-09-22 16:34 (seconds will be set to 0)
+ * 2012-09-22 (time will be set to 00:00:00)
+ * 16:34:22 (date will be set to today)
+ * 16:34 (date will be set to today, seconds to 0)
+ * now
+ * yesterday (time is set to 00:00:00)
+ * today (time is set to 00:00:00)
+ * tomorrow (time is set to 00:00:00)
+ * +5min
+ * -5days
+ *
+ */
+
+ assert(t);
+ assert(usec);
+
+ x = time(NULL);
+ localtime_r(&x, &tm);
+ tm.tm_isdst = -1;
+
+ if (streq(t, "now"))
+ goto finish;
+
+ else if (streq(t, "today")) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (streq(t, "yesterday")) {
+ tm.tm_mday--;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (streq(t, "tomorrow")) {
+ tm.tm_mday++;
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+
+ } else if (t[0] == '+') {
+
+ r = parse_sec(t + 1, &plus);
+ if (r < 0)
+ return r;
+
+ goto finish;
+ } else if (t[0] == '-') {
+
+ r = parse_sec(t + 1, &minus);
+ if (r < 0)
+ return r;
+
+ goto finish;
+
+ } else if (endswith(t, " ago")) {
+ char *z;
+
+ z = strndup(t, strlen(t) - 4);
+ if (!z)
+ return -ENOMEM;
+
+ r = parse_sec(z, &minus);
+ if (r < 0)
+ return r;
+
+ goto finish;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(day_nr); i++) {
+ size_t skip;
+
+ if (!startswith_no_case(t, day_nr[i].name))
+ continue;
+
+ skip = strlen(day_nr[i].name);
+ if (t[skip] != ' ')
+ continue;
+
+ weekday = day_nr[i].nr;
+ t += skip + 1;
+ break;
+ }
+
+ copy = tm;
+ k = strptime(t, "%y-%m-%d %H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d %H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%y-%m-%d %H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d %H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%y-%m-%d", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y-%m-%d", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%H:%M:%S", &tm);
+ if (k && *k == 0)
+ goto finish;
+
+ tm = copy;
+ k = strptime(t, "%H:%M", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ tm = copy;
+ k = strptime(t, "%Y%m%d%H%M%S", &tm);
+ if (k && *k == 0) {
+ tm.tm_sec = 0;
+ goto finish;
+ }
+
+ return -EINVAL;
+
+ finish:
+ x = mktime(&tm);
+ if (x == (time_t)-1)
+ return -EINVAL;
+
+ if (weekday >= 0 && tm.tm_wday != weekday)
+ return -EINVAL;
+
+ ret = (usec_t) x *USEC_PER_SEC;
+
+ ret += plus;
+ if (ret > minus)
+ ret -= minus;
+ else
+ ret = 0;
+
+ *usec = ret;
+
+ return 0;
+}
diff --git a/lib/tt.c b/lib/tt.c
index cbe4e3b4d..e701becfd 100644
--- a/lib/tt.c
+++ b/lib/tt.c
@@ -221,9 +221,17 @@ void tt_remove_lines(struct tt *tb)
return;
while (!list_empty(&tb->tb_lines)) {
+ struct list_head *p;
struct tt_line *ln = list_entry(tb->tb_lines.next,
struct tt_line, ln_lines);
list_del(&ln->ln_lines);
+
+ list_for_each(p, &tb->tb_columns) {
+ struct tt_column *cl =
+ list_entry(p, struct tt_column, cl_columns);
+ if ((cl->flags & TT_FL_FREEDATA) || (tb->flags & TT_FL_FREEDATA))
+ free(ln->data[cl->seqnum]);
+ }
free(ln->data);
free(ln);
}
@@ -360,7 +368,7 @@ struct tt_column *tt_get_column(struct tt *tb, size_t colnum)
*
* Stores data that will be printed to the table cell.
*/
-int tt_line_set_data(struct tt_line *ln, int colnum, const char *data)
+int tt_line_set_data(struct tt_line *ln, int colnum, char *data)
{
struct tt_column *cl;