aboutsummaryrefslogtreecommitdiff
path: root/isys
diff options
context:
space:
mode:
authorwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
committerwiktor w brodlo <wiktor@brodlo.net>2011-06-15 16:59:54 +0000
commit2590d96369d0217e31dc2812690dde61dac417b5 (patch)
tree82276f787b08a28548e342c7921486f1acefab9f /isys
parentfirst commit (diff)
downloadanaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.gz
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.tar.bz2
anaconda-2590d96369d0217e31dc2812690dde61dac417b5.zip
Initial import from Sabayon (ver 0.9.9.56)
Diffstat (limited to 'isys')
-rw-r--r--isys/.gitignore5
-rw-r--r--isys/Makefile.am50
-rw-r--r--isys/auditd.c135
-rw-r--r--isys/auditd.h30
-rw-r--r--isys/cpio.c46
-rw-r--r--isys/cpio.h102
-rw-r--r--isys/devices.c217
-rw-r--r--isys/devices.h42
-rw-r--r--isys/eddsupport.c339
-rw-r--r--isys/eddsupport.h28
-rw-r--r--isys/ethtool.c119
-rw-r--r--isys/ethtool.h41
-rw-r--r--isys/iface.c543
-rw-r--r--isys/iface.h166
-rw-r--r--isys/imount.c315
-rw-r--r--isys/imount.h48
-rw-r--r--isys/isofs.c55
-rw-r--r--isys/isys.c700
-rw-r--r--isys/isys.h38
-rwxr-xr-xisys/isys.py583
-rw-r--r--isys/lang.c207
-rw-r--r--isys/lang.h44
-rw-r--r--isys/linkdetect.c202
-rw-r--r--isys/log.c224
-rw-r--r--isys/log.h51
-rw-r--r--isys/stubs.h44
-rw-r--r--isys/uncpio.c798
-rw-r--r--isys/vio.c106
28 files changed, 5278 insertions, 0 deletions
diff --git a/isys/.gitignore b/isys/.gitignore
new file mode 100644
index 0000000..9c06205
--- /dev/null
+++ b/isys/.gitignore
@@ -0,0 +1,5 @@
+*.pyc
+.depend
+*.lo
+*.do
+nfs_mountversion.h
diff --git a/isys/Makefile.am b/isys/Makefile.am
new file mode 100644
index 0000000..b05330c
--- /dev/null
+++ b/isys/Makefile.am
@@ -0,0 +1,50 @@
+# isys/Makefile.am for anaconda
+#
+# Copyright (C) 2009 Red Hat, Inc.
+#
+# This program 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.
+#
+# 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 Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author: David Cantrell <dcantrell@redhat.com>
+
+pkgpyexecdir = $(pyexecdir)/py$(PACKAGE_NAME)
+
+ISYS_SRCS = devices.c imount.c cpio.c uncpio.c lang.c \
+ isofs.c linkdetect.c vio.c ethtool.c eddsupport.c iface.c \
+ auditd.c log.c
+
+dist_noinst_HEADERS = *.h
+
+ISYS_CFLAGS = -DVERSION='"$(PACKAGE_VERSION)"' $(NFS_CFLAGS) \
+ $(NETWORKMANAGER_CFLAGS) $(LIBNL_CFLAGS) $(LIBNM_GLIB_CFLAGS) \
+ $(SELINUX_CFLAGS)
+ISYS_LIBS = $(RESOLV_LIBS) $(EXT2FS_LIBS) $(ZLIB_LIBS) \
+ $(DEVMAPPER_LIBS) $(BLKID_LIBS) $(X11_LIBS) $(SELINUX_LIBS) \
+ $(LIBNL_LIBS) $(LIBNM_GLIB_LIBS)
+
+isysdir = $(pkgpyexecdir)
+isys_PYTHON = *.py
+
+pkgpyexec_LTLIBRARIES = _isys.la
+_isys_la_CFLAGS = $(PYTHON_INCLUDES) $(ISYS_CFLAGS)
+_isys_la_LDFLAGS = -module -avoid-version $(PYTHON_LDFLAGS)
+_isys_la_LIBADD = $(PYTHON_LIBS) $(ISYS_LIBS)
+_isys_la_SOURCES = isys.c $(ISYS_SRCS)
+
+noinst_LTLIBRARIES = libisys.la
+libisys_la_CFLAGS = $(ISYS_CFLAGS)
+libisys_la_LDFLAGS = -static
+libisys_la_LIBADD = $(ISYS_LIBS)
+libisys_la_SOURCES = $(ISYS_SRCS)
+
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/isys/auditd.c b/isys/auditd.c
new file mode 100644
index 0000000..8eef4f3
--- /dev/null
+++ b/isys/auditd.c
@@ -0,0 +1,135 @@
+/*
+ * auditd.c: This is a simple audit daemon that throws all messages away.
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+
+#define _GNU_SOURCE 1
+
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <libaudit.h>
+
+#include "auditd.h"
+
+#ifdef USESELINUX
+static int done;
+
+static void sig_done(int sig)
+{
+ done = 1;
+}
+
+static void do_auditd(int fd) {
+ struct audit_reply rep;
+ sigset_t sigs;
+ struct sigaction sa;
+ struct pollfd pds = {
+ .events = POLLIN,
+ .revents = 0,
+ .fd = fd,
+ };
+
+ if (audit_set_pid(fd, getpid(), WAIT_YES) < 0)
+ return;
+
+ if (audit_set_enabled(fd, 1) < 0)
+ return;
+
+ memset(&sa, '\0', sizeof (sa));
+ sa.sa_handler = sig_done;
+ sigaction(SIGTERM, &sa, NULL);
+ sigaction(SIGINT, &sa, NULL);
+ sigaction(SIGHUP, &sa, NULL);
+
+ sigfillset(&sigs);
+ sigdelset(&sigs, SIGTERM);
+ sigdelset(&sigs, SIGINT);
+ sigdelset(&sigs, SIGHUP);
+
+ while (1) {
+ int retval;
+
+ memset(&rep, 0, sizeof(rep));
+
+ do {
+ retval = ppoll(&pds, 1, NULL, &sigs);
+ } while (retval == -1 && errno == EINTR && !done);
+
+ if (done)
+ break;
+
+ if (audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0) > 0) {
+ /* we don't actually want to do anything here. */
+ ;
+ }
+ }
+ return;
+}
+#endif /* USESELINUX */
+
+int audit_daemonize(void) {
+#ifdef USESELINUX
+ int fd;
+#ifndef STANDALONE
+ int i;
+ pid_t child;
+
+ if ((child = fork()) > 0)
+ return 0;
+
+ for (i = 0; i < getdtablesize(); i++)
+ close(i);
+
+ signal(SIGTTOU, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+
+ if ((fd = open("/proc/self/oom_adj", O_RDWR)) >= 0) {
+ i = write(fd, "-17", 3);
+ close(fd);
+ }
+
+#endif /* !defined(STANDALONE) */
+ fd = audit_open();
+ do_auditd(fd);
+ audit_close(fd);
+#ifndef STANDALONE
+ exit(0);
+#endif /* !defined(STANDALONE) */
+#endif /* USESELINUX */
+ return 0;
+}
+
+#ifdef STANDALONE
+int main(void) {
+ return audit_daemonize();
+}
+#endif /* STANDALONE */
+
+/*
+ * vim:ts=8:sw=4:sts=4:et
+ */
diff --git a/isys/auditd.h b/isys/auditd.h
new file mode 100644
index 0000000..55ec5ce
--- /dev/null
+++ b/isys/auditd.h
@@ -0,0 +1,30 @@
+/*
+ * auditd.h: This is a simple audit daemon that throws all messages away.
+ *
+ * Copyright (C) 2006 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Peter Jones <pjones@redhat.com>
+ */
+
+#ifndef ISYS_AUDIT_H
+#define ISYS_AUDIT_H 1
+
+extern int audit_daemonize(void);
+
+#endif /* ISYS_AUDIT_H */
+/*
+ * vim:ts=8:sw=4:sts=4:et
+ */
diff --git a/isys/cpio.c b/isys/cpio.c
new file mode 100644
index 0000000..fd83605
--- /dev/null
+++ b/isys/cpio.c
@@ -0,0 +1,46 @@
+/*
+ * cpio.c
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "cpio.h"
+
+int installCpioFile(gzFile fd, char * cpioName, char * outName, int inWin) {
+ struct cpioFileMapping map;
+ int rc;
+ const char * failedFile;
+
+ if (outName) {
+ map.archivePath = cpioName;
+ map.fsPath = outName;
+ map.mapFlags = CPIO_MAP_PATH;
+ }
+
+ rc = myCpioInstallArchive(fd, outName ? &map : NULL, 1, NULL, NULL,
+ &failedFile);
+
+ if (rc || access(outName, R_OK)) {
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/isys/cpio.h b/isys/cpio.h
new file mode 100644
index 0000000..4cbb7c0
--- /dev/null
+++ b/isys/cpio.h
@@ -0,0 +1,102 @@
+/*
+ * cpio.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_CPIO
+#define H_CPIO
+
+#include <sys/types.h>
+
+#include "stubs.h"
+
+/* Note the CPIO_CHECK_ERRNO bit is set only if errno is valid. These have to
+ be positive numbers or this setting the high bit stuff is a bad idea. */
+#define CPIOERR_CHECK_ERRNO 0x80000000
+
+#define CPIOERR_BAD_MAGIC (2 )
+#define CPIOERR_BAD_HEADER (3 )
+#define CPIOERR_OPEN_FAILED (4 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_CHMOD_FAILED (5 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_CHOWN_FAILED (6 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_WRITE_FAILED (7 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_UTIME_FAILED (8 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_UNLINK_FAILED (9 | CPIOERR_CHECK_ERRNO)
+
+#define CPIOERR_SYMLINK_FAILED (11 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_STAT_FAILED (12 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_MKDIR_FAILED (13 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_MKNOD_FAILED (14 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_MKFIFO_FAILED (15 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_LINK_FAILED (16 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_READLINK_FAILED (17 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_READ_FAILED (18 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_COPY_FAILED (19 | CPIOERR_CHECK_ERRNO)
+#define CPIOERR_INTERNAL (20 )
+#define CPIOERR_HDR_SIZE (21 )
+#define CPIOERR_UNKNOWN_FILETYPE (22 )
+
+
+/* Don't think this behaves just like standard cpio. It's pretty close, but
+ it has some behaviors which are more to RPM's liking. I tried to document
+ them inline in cpio.c, but I may have missed some. */
+
+#define CPIO_MAP_PATH (1 << 0)
+#define CPIO_MAP_MODE (1 << 1)
+#define CPIO_MAP_UID (1 << 2)
+#define CPIO_MAP_GID (1 << 3)
+#define CPIO_FOLLOW_SYMLINKS (1 << 4) /* only for building */
+
+struct cpioFileMapping {
+ char * archivePath;
+ char * fsPath;
+ mode_t finalMode;
+ uid_t finalUid;
+ gid_t finalGid;
+ int mapFlags;
+};
+
+/* on cpio building, only "file" is filled in */
+struct cpioCallbackInfo {
+ char * file;
+ long fileSize; /* total file size */
+ long fileComplete; /* amount of file unpacked */
+ long bytesProcessed; /* bytes in archive read */
+};
+
+typedef void (*cpioCallback)(struct cpioCallbackInfo * filespec, void * data);
+
+/* If no mappings are passed, this installs everything! If one is passed
+ it should be sorted according to cpioFileMapCmp() and only files included
+ in the map are installed. Files are installed relative to the current
+ directory unless a mapping is given which specifies an absolute
+ directory. The mode mapping is only used for the permission bits, not
+ for the file type. The owner/group mappings are ignored for the nonroot
+ user. If *failedFile is non-NULL on return, it should be free()d. */
+int myCpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
+ int numMappings, cpioCallback cb, void * cbData,
+ const char ** failedFile);
+int myCpioFilterArchive(gzFile inStream, gzFile outStream, char ** pattern);
+
+/* This is designed to be qsort/bsearch compatible */
+int myCpioFileMapCmp(const void * a, const void * b);
+
+const char *myCpioStrerror(int rc);
+
+int installCpioFile(gzFile fd, char * cpioName, char * outName, int inWin);
+
+#endif
diff --git a/isys/devices.c b/isys/devices.c
new file mode 100644
index 0000000..98c8769
--- /dev/null
+++ b/isys/devices.c
@@ -0,0 +1,217 @@
+/*
+ * devices.c - various hardware probing functionality
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Bill Nottingham <notting@redhat.com>
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "devices.h"
+
+/* for 'disks', to filter out weird stuff */
+#define MINIMUM_INTERESTING_SIZE 32*1024 /* 32MB */
+
+/* from genhd.h, kernel side */
+#define GENHD_FL_REMOVABLE 1
+#define GENHD_FL_DRIVERFS 2
+#define GENHD_FL_MEDIA_CHANGE_NOTIFY 4
+#define GENHD_FL_CD 8
+#define GENHD_FL_UP 16
+#define GENHD_FL_SUPPRESS_PARTITION_INFO 32
+#define GENHD_FL_FAIL 64
+
+
+struct device **getDevices(enum deviceType type) {
+ struct device **ret = NULL;
+ struct device *new;
+ int numdevices = 0;
+
+ if (type & (DEVICE_DISK | DEVICE_CDROM)) {
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir("/sys/block");
+
+ if (!dir) goto storagedone;
+
+ while ((ent = readdir(dir))) {
+ char path[64];
+ char buf[64];
+ int fd, caps, devtype;
+
+ snprintf(path, 64, "/sys/block/%s/capability", ent->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ continue;
+ if (read(fd, buf, 63) <= 0) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ errno = 0;
+ caps = strtol(buf, NULL, 16);
+
+ if ((errno == ERANGE && (caps == LONG_MIN || caps == LONG_MAX)) ||
+ (errno != 0 && caps == 0)) {
+ return NULL;
+ }
+
+ if (caps & GENHD_FL_CD)
+ devtype = DEVICE_CDROM;
+ else
+ devtype = DEVICE_DISK;
+ if (!(devtype & type))
+ continue;
+
+ if (devtype == DEVICE_DISK && !(caps & GENHD_FL_REMOVABLE)) {
+ int size;
+
+ snprintf(path, 64, "/sys/block/%s/size", ent->d_name);
+ fd = open(path, O_RDONLY);
+
+ if (fd == -1)
+ continue;
+ if (read(fd, buf, 63) <= 0) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ errno = 0;
+ size = strtol(buf, NULL, 10);
+
+ if ((errno == ERANGE && (size == LONG_MIN ||
+ size == LONG_MAX)) ||
+ (errno != 0 && size == 0)) {
+ return NULL;
+ }
+
+ if (size < MINIMUM_INTERESTING_SIZE)
+ continue;
+ }
+
+ new = calloc(1, sizeof(struct device));
+ new->device = strdup(ent->d_name);
+ /* FIXME */
+ if (asprintf(&new->description, "Storage device %s",
+ new->device) == -1) {
+ fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__,
+ strerror(errno));
+ fflush(stderr);
+ abort();
+ }
+ new->type = devtype;
+ if (caps & GENHD_FL_REMOVABLE) {
+ new->priv.removable = 1;
+ }
+ ret = realloc(ret, (numdevices+2) * sizeof(struct device));
+ ret[numdevices] = new;
+ ret[numdevices+1] = NULL;
+ numdevices++;
+ }
+ }
+storagedone:
+
+ if (type & DEVICE_NETWORK) {
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir("/sys/class/net");
+
+ if (!dir) goto netdone;
+
+ while ((ent = readdir(dir))) {
+ char path[64];
+ int fd, type;
+ char buf[64];
+
+ snprintf(path, 64, "/sys/class/net/%s/type", ent->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ continue;
+ if (read(fd, buf, 63) <= 0) {
+ close(fd);
+ continue;
+ }
+
+ close(fd);
+ errno = 0;
+ type = strtol(buf, NULL, 10);
+
+ if ((errno == ERANGE && (type == LONG_MIN || type == LONG_MAX)) ||
+ (errno != 0 && type == 0)) {
+ return NULL;
+ }
+
+ if (type != 1)
+ continue;
+
+ new = calloc(1, sizeof(struct device));
+ new->device = strdup(ent->d_name);
+ /* FIXME */
+ snprintf(path, 64, "/sys/class/net/%s/address", ent->d_name);
+ fd = open(path, O_RDONLY);
+ if (fd != -1) {
+ memset(buf, '\0', 64);
+ if (read(fd, buf, 63) > 0) {
+ int i;
+ for (i = (strlen(buf)-1); isspace(buf[i]); i--)
+ buf[i] = '\0';
+ new->priv.hwaddr = strdup(buf);
+ }
+ }
+
+ if (new->priv.hwaddr) {
+ if (asprintf(&new->description, "Ethernet device %s - %s",
+ new->device, new->priv.hwaddr) == -1) {
+ fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__,
+ strerror(errno));
+ fflush(stderr);
+ abort();
+ }
+ } else {
+ if (asprintf(&new->description, "Ethernet device %s",
+ new->device) == -1) {
+ fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__,
+ strerror(errno));
+ fflush(stderr);
+ abort();
+ }
+ }
+
+ ret = realloc(ret, (numdevices+2) * sizeof(struct device));
+ ret[numdevices] = new;
+ ret[numdevices+1] = NULL;
+ numdevices++;
+ }
+ }
+netdone:
+ return ret;
+}
+
diff --git a/isys/devices.h b/isys/devices.h
new file mode 100644
index 0000000..9428a77
--- /dev/null
+++ b/isys/devices.h
@@ -0,0 +1,42 @@
+/*
+ * devices.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DEVICES_H
+#define DEVICES_H
+
+enum deviceType {
+ DEVICE_ANY = ~0,
+ DEVICE_NETWORK = (1 << 0),
+ DEVICE_DISK = (1 << 1),
+ DEVICE_CDROM = (1 << 2)
+};
+
+struct device {
+ char *device;
+ char *description;
+ enum deviceType type;
+ union {
+ char *hwaddr;
+ int removable;
+ } priv;
+};
+
+struct device **getDevices(enum deviceType type);
+
+#endif
diff --git a/isys/eddsupport.c b/isys/eddsupport.c
new file mode 100644
index 0000000..c50278e
--- /dev/null
+++ b/isys/eddsupport.c
@@ -0,0 +1,339 @@
+/*
+ * eddsupport.c - handling of mapping disk drives in Linux to disk drives
+ * according to the BIOS using the edd kernel module
+ *
+ * Copyright (C) 2004 Dell, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Rezwanul_Kabir@Dell.com
+ * Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/reboot.h>
+#include <sys/types.h>
+#include <linux/types.h>
+
+
+#include "eddsupport.h"
+#include "devices.h"
+#include "isys.h"
+
+#define EDD_DIR "/sys/firmware/edd"
+#define SIG_FILE "mbr_signature"
+#define MBRSIG_OFFSET 0x1b8
+
+#define HASH_TABLE_SIZE 17
+
+
+struct diskMapEntry{
+ uint32_t key;
+ char *diskname;
+ struct diskMapEntry *next;
+};
+
+struct diskMapTable {
+ struct diskMapEntry **table;
+ int tableSize;
+};
+
+static struct diskMapTable *mbrSigToName = NULL;
+static int diskHashInit = 0;
+
+
+
+static struct diskMapTable* initializeHashTable(int);
+static int insertHashItem(struct diskMapTable *, struct diskMapEntry *);
+static struct diskMapEntry* lookupHashItem(struct diskMapTable *, uint32_t);
+static int addToHashTable(struct diskMapTable *, uint32_t , char *);
+static struct device ** createDiskList();
+static int mapBiosDisks(struct device ** , const char *);
+static int readDiskSig(char *, uint32_t *);
+static int readMbrSig(char *, uint32_t *);
+
+/* This is the top level function that creates a disk list present in the
+ * system, checks to see if unique signatures exist on the disks at offset
+ * 0x1b8. If a unique signature exists then it will map BIOS disks to their
+ * corresponding hd/sd device names. Otherwise, we'll avoid mapping drives.
+ */
+
+int probeBiosDisks() {
+ struct device ** devices = NULL;
+
+ devices = createDiskList();
+ if(!devices){
+#ifdef STANDALONE
+ fprintf(stderr, "No disks!\n");
+#endif
+ return -1;
+ }
+
+ if(!mapBiosDisks(devices, EDD_DIR)){
+#ifdef STANDALONE
+ fprintf(stderr, "WARNING: couldn't map BIOS disks\n");
+#endif
+ return -1;
+ }
+ return 0;
+}
+
+
+static struct device ** createDiskList(){
+ return getDevices (DEVICE_DISK);
+}
+
+static int readDiskSig(char *device, uint32_t *disksig) {
+ int fd, rc;
+ char devnodeName[64];
+
+ snprintf(devnodeName, sizeof(devnodeName), "/dev/%s", device);
+ fd = open(devnodeName, O_RDONLY);
+ if (fd < 0) {
+#ifdef STANDALONE
+ fprintf(stderr, "Error opening device %s: %s\n ", device,
+ strerror(errno));
+#endif
+ return -errno;
+ }
+
+ rc = lseek(fd, MBRSIG_OFFSET, SEEK_SET);
+ if (rc < 0){
+ close(fd);
+
+#ifdef STANDALONE
+ fprintf(stderr, "Error seeking to MBRSIG_OFFSET in %s: %s\n",
+ device, strerror(errno));
+#endif
+ return -1;
+ }
+
+ rc = read(fd, disksig, sizeof(uint32_t));
+ if (rc < sizeof(uint32_t)) {
+ close(fd);
+
+#ifdef STANDALONE
+ fprintf(stderr, "Failed to read signature from %s\n", device);
+#endif
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int mapBiosDisks(struct device** devices,const char *path) {
+ DIR *dirHandle;
+ struct dirent *entry;
+ char * sigFileName;
+ uint32_t mbrSig, biosNum, currentSig;
+ struct device **currentDev, **foundDisk;
+ int i, rc, ret, dm_nr, highest_dm;
+
+ dirHandle = opendir(path);
+ if(!dirHandle){
+#ifdef STANDALONE
+ fprintf(stderr, "Failed to open directory %s: %s\n", path,
+ strerror(errno));
+#endif
+ return 0;
+ }
+
+ mbrSigToName = initializeHashTable(HASH_TABLE_SIZE);
+ if(!mbrSigToName){
+#ifdef STANDALONE
+ fprintf(stderr, "Error initializing mbrSigToName table\n");
+#endif
+ closedir(dirHandle);
+ return 0;
+ }
+
+ while ((entry = readdir(dirHandle)) != NULL) {
+ if(!strncmp(entry->d_name,".",1) || !strncmp(entry->d_name,"..",2)) {
+ continue;
+ }
+ ret = sscanf((entry->d_name+9), "%x", &biosNum);
+
+ sigFileName = malloc(strlen(path) + strlen(entry->d_name) + 20);
+ sprintf(sigFileName, "%s/%s/%s", path, entry->d_name, SIG_FILE);
+ if (readMbrSig(sigFileName, &mbrSig) == 0) {
+ for (currentDev = devices, i = 0, foundDisk=NULL, highest_dm=-1;
+ (*currentDev) != NULL;
+ currentDev++) {
+ if (!(*currentDev)->device)
+ continue;
+
+ if ((rc=readDiskSig((*currentDev)->device, &currentSig)) < 0) {
+ if (rc == -ENOMEDIUM || rc == -ENXIO)
+ continue;
+ closedir(dirHandle);
+ return 0;
+ }
+
+ if (mbrSig == currentSig) {
+ /* When we have a fakeraid setup we will find multiple hits
+ a number for the raw disks (1 when striping, 2 when
+ mirroring, more with raid on raid like raid 01 or 10)
+ and a number for the dm devices (normally only one dm
+ device will match, but more with raid on raid).
+ Since with raid on raid the last dm device created
+ will be the top layer raid, we want the highest matching
+ dm device. */
+ if (!strncmp((*currentDev)->device, "dm-", 3) &&
+ sscanf((*currentDev)->device+3, "%d", &dm_nr) == 1) {
+ if (dm_nr > highest_dm) {
+ highest_dm = dm_nr;
+ foundDisk=currentDev;
+ i = 1;
+ }
+ } else if (!foundDisk ||
+ strncmp((*foundDisk)->device, "dm-", 3)) {
+ foundDisk=currentDev;
+ i++;
+ }
+ }
+ }
+
+ if (i==1) {
+ if(!addToHashTable(mbrSigToName, (uint32_t)biosNum,
+ (*foundDisk)->device)) {
+ closedir(dirHandle);
+ return 0;
+ }
+ }
+ }
+ }
+ closedir(dirHandle);
+ return 1;
+}
+
+
+static int readMbrSig(char *filename, uint32_t *int_sig){
+ FILE* fh;
+
+ fh = fopen(filename,"r");
+ if(fh == NULL) {
+#ifdef STANDALONE
+ fprintf(stderr, "Error opening mbr_signature file %s: %s\n", filename,
+ strerror(errno));
+#endif
+ return -1;
+ }
+ fseek(fh, 0, SEEK_SET);
+ if (fscanf(fh, "%x", int_sig) != 1) {
+#ifdef STANDALONE
+ fprintf(stderr, "Error reading %s\n", filename);
+#endif
+ fclose(fh);
+ return -1;
+ }
+
+ fclose(fh);
+ return 0;
+}
+
+
+static struct diskMapTable* initializeHashTable(int size) {
+ struct diskMapTable *hashTable;
+
+ hashTable = malloc(sizeof(struct diskMapTable));
+ hashTable->tableSize = size;
+ hashTable->table = malloc(sizeof(struct diskMapEntry *) * size);
+ memset(hashTable->table,0,(sizeof(struct diskMapEntry *) * size));
+ return hashTable;
+}
+
+
+static int insertHashItem(struct diskMapTable *hashTable,
+ struct diskMapEntry *hashItem) {
+ int index;
+
+ index = (hashItem->key) % (hashTable->tableSize);
+
+ if(hashTable->table[index] == NULL){
+ hashTable->table[index] = hashItem;
+ return index;
+ } else {
+ hashItem->next = hashTable->table[index];
+ hashTable->table[index] = hashItem;
+ return index;
+ }
+}
+
+
+static struct diskMapEntry * lookupHashItem(struct diskMapTable *hashTable,
+ uint32_t itemKey) {
+ int index;
+ struct diskMapEntry *hashItem;
+
+ index = itemKey % (hashTable->tableSize);
+ for (hashItem = hashTable->table[index];
+ (hashItem != NULL) && (hashItem->key != itemKey);
+ hashItem = hashItem->next) {
+ ;
+ }
+ return hashItem;
+}
+
+
+static int addToHashTable(struct diskMapTable *hashTable,
+ uint32_t itemKey, char *diskName) {
+ int index;
+ struct diskMapEntry *diskSigToNameEntry;
+
+ diskSigToNameEntry = malloc(sizeof(struct diskMapEntry));
+ diskSigToNameEntry->next = NULL;
+ diskSigToNameEntry->key = itemKey;
+ diskSigToNameEntry->diskname = diskName;
+
+ if ((index = insertHashItem(hashTable, diskSigToNameEntry)) < 0){
+#ifdef STANDALONE
+ fprintf(stderr, "Unable to insert item\n");
+#endif
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+
+char * getBiosDisk(char *biosStr) {
+ uint32_t biosNum;
+ struct diskMapEntry * disk;
+ int ret;
+
+ if (diskHashInit == 0) {
+ probeBiosDisks();
+ diskHashInit = 1;
+ }
+
+ if (mbrSigToName == NULL)
+ return NULL;
+
+ ret = sscanf(biosStr,"%x",&biosNum);
+ disk = lookupHashItem(mbrSigToName, biosNum);
+ if (disk) return disk->diskname;
+
+ return NULL;
+}
diff --git a/isys/eddsupport.h b/isys/eddsupport.h
new file mode 100644
index 0000000..77fc4c4
--- /dev/null
+++ b/isys/eddsupport.h
@@ -0,0 +1,28 @@
+/*
+ * eddsupport.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EDDSUPPORT_H
+#define EDDSUPPORT_H
+
+int probeBiosDisks();
+char* getBiosDisk(char *);
+
+#endif
+
+
diff --git a/isys/ethtool.c b/isys/ethtool.c
new file mode 100644
index 0000000..871f1d4
--- /dev/null
+++ b/isys/ethtool.c
@@ -0,0 +1,119 @@
+/*
+ * ethtool.c - setting of basic ethtool options
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <net/if.h>
+
+#include <linux/sockios.h>
+#include "ethtool.h"
+
+static int set_intf_up(struct ifreq ifr, int sock) {
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+ return (-1);
+ }
+ ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+ fprintf(stderr, "failed to bring up interface %s: %s", ifr.ifr_name,
+ strerror(errno));
+ return -1;
+ }
+ return (0);
+}
+
+int setEthtoolSettings(char * dev, ethtool_speed speed,
+ ethtool_duplex duplex) {
+ int sock, err;
+ struct ethtool_cmd ecmd;
+ struct ifreq ifr;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Unable to create socket");
+ return -1;
+ }
+
+ /* Setup our control structures. */
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, dev);
+
+ if (set_intf_up(ifr, sock) == -1) {
+ fprintf(stderr, "unable to bring up interface %s: %s", dev,
+ strerror(errno));
+ return -1;
+ }
+
+ ecmd.cmd = ETHTOOL_GSET;
+ ifr.ifr_data = (caddr_t)&ecmd;
+ err = ioctl(sock, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ perror("Unable to get settings via ethtool. Not setting");
+ return -1;
+ }
+
+ if (speed != ETHTOOL_SPEED_UNSPEC)
+ ecmd.speed = speed;
+ if (duplex != ETHTOOL_DUPLEX_UNSPEC)
+ ecmd.duplex = duplex;
+ if ((duplex != ETHTOOL_DUPLEX_UNSPEC) || (speed != ETHTOOL_SPEED_UNSPEC))
+ ecmd.autoneg = AUTONEG_DISABLE;
+
+ ecmd.cmd = ETHTOOL_SSET;
+ ifr.ifr_data = (caddr_t)&ecmd;
+ err = ioctl(sock, SIOCETHTOOL, &ifr);
+ if (err < 0) {
+ // perror("Unable to set settings via ethtool. Not setting");
+ return -1;
+ }
+
+ return 0;
+}
+
+int identifyNIC(char *iface, int seconds) {
+ int sock;
+ struct ethtool_value edata;
+ struct ifreq ifr;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("Unable to create socket");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ memset(&edata, 0, sizeof(edata));
+
+ strcpy(ifr.ifr_name, iface);
+ edata.cmd = ETHTOOL_PHYS_ID;
+ edata.data = seconds;
+ ifr.ifr_data = (caddr_t) &edata;
+
+ if (ioctl(sock, SIOCETHTOOL, &ifr) < 0) {
+ perror("Unable to identify NIC");
+ }
+
+ return 0;
+}
diff --git a/isys/ethtool.h b/isys/ethtool.h
new file mode 100644
index 0000000..57b4ffc
--- /dev/null
+++ b/isys/ethtool.h
@@ -0,0 +1,41 @@
+/*
+ * net.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISYSNET_H
+#define ISYSNET_H
+
+#include <linux/types.h>
+#include <linux/ethtool.h>
+
+/* returns 1 for link, 0 for no link, -1 for unknown */
+int get_link_status(char *ifname);
+
+typedef enum ethtool_speed_t { ETHTOOL_SPEED_UNSPEC = -1,
+ ETHTOOL_SPEED_10 = SPEED_10,
+ ETHTOOL_SPEED_100 = SPEED_100,
+ ETHTOOL_SPEED_1000 = SPEED_1000 } ethtool_speed;
+typedef enum ethtool_duplex_t { ETHTOOL_DUPLEX_UNSPEC = -1,
+ ETHTOOL_DUPLEX_HALF = DUPLEX_HALF,
+ ETHTOOL_DUPLEX_FULL = DUPLEX_FULL } ethtool_duplex;
+
+/* set ethtool settings */
+int setEthtoolSettings(char * dev, ethtool_speed speed, ethtool_duplex duplex);
+int identifyNIC(char *iface, int seconds);
+
+#endif
diff --git a/isys/iface.c b/isys/iface.c
new file mode 100644
index 0000000..5897286
--- /dev/null
+++ b/isys/iface.c
@@ -0,0 +1,543 @@
+/*
+ * iface.c - Network interface configuration API
+ *
+ * Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): David Cantrell <dcantrell@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <signal.h>
+#include <netinet/in.h>
+
+#include <netlink/netlink.h>
+#include <netlink/socket.h>
+#include <netlink/route/rtnl.h>
+#include <netlink/route/route.h>
+#include <netlink/route/addr.h>
+#include <netlink/route/link.h>
+
+#include <glib.h>
+#include <NetworkManager.h>
+#include <nm-client.h>
+#include <nm-device.h>
+#include <nm-ip4-config.h>
+#include <nm-setting-ip4-config.h>
+
+#include "isys.h"
+#include "iface.h"
+
+/* Internal-only function prototypes. */
+static struct nl_handle *_iface_get_handle(void);
+static struct nl_cache *_iface_get_link_cache(struct nl_handle **);
+static int _iface_have_valid_addr(void *addr, int family, int length);
+static int _iface_redirect_io(char *device, int fd, int mode);
+
+/*
+ * Return a libnl handle for NETLINK_ROUTE.
+ */
+static struct nl_handle *_iface_get_handle(void) {
+ struct nl_handle *handle = NULL;
+
+ if ((handle = nl_handle_alloc()) == NULL) {
+ return NULL;
+ }
+
+ if (nl_connect(handle, NETLINK_ROUTE)) {
+ nl_handle_destroy(handle);
+ return NULL;
+ }
+
+ return handle;
+}
+
+/*
+ * Return an NETLINK_ROUTE cache.
+ */
+static struct nl_cache *_iface_get_link_cache(struct nl_handle **handle) {
+ struct nl_cache *cache = NULL;
+
+ if ((*handle = _iface_get_handle()) == NULL) {
+ return NULL;
+ }
+
+ if ((cache = rtnl_link_alloc_cache(*handle)) == NULL) {
+ nl_close(*handle);
+ nl_handle_destroy(*handle);
+ return NULL;
+ }
+
+ return cache;
+}
+
+/*
+ * Determine if a struct in_addr or struct in6_addr contains a valid address.
+ */
+static int _iface_have_valid_addr(void *addr, int family, int length) {
+ char buf[length+1];
+
+ if ((addr == NULL) || (family != AF_INET && family != AF_INET6)) {
+ return 0;
+ }
+
+ memset(buf, '\0', sizeof(buf));
+
+ if (inet_ntop(family, addr, buf, length) == NULL) {
+ return 0;
+ } else {
+ /* check for unknown addresses */
+ if (family == AF_INET) {
+ if (!strncmp(buf, "0.0.0.0", 7)) {
+ return 0;
+ }
+ } else if (family == AF_INET6) {
+ if (!strncmp(buf, "::", 2)) {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Redirect I/O to another device (e.g., stdout to /dev/tty5)
+ */
+int _iface_redirect_io(char *device, int fd, int mode) {
+ int io = -1;
+
+ if ((io = open(device, mode)) == -1) {
+ return 1;
+ }
+
+ if (close(fd) == -1) {
+ return 2;
+ }
+
+ if (dup2(io, fd) == -1) {
+ return 3;
+ }
+
+ if (close(io) == -1) {
+ return 4;
+ }
+
+ return 0;
+}
+
+/*
+ * Given an interface name (e.g., eth0) and address family (e.g., AF_INET),
+ * return the IP address in human readable format (i.e., the output from
+ * inet_ntop()). Return NULL for no match or error.
+ */
+char *iface_ip2str(char *ifname, int family) {
+ int i;
+ NMClient *client = NULL;
+ NMIP4Config *ip4config = NULL;
+ NMIP4Address *ipaddr = NULL;
+ NMDevice *candidate = NULL;
+ struct in_addr tmp_addr;
+ const GPtrArray *devices;
+ const char *iface;
+ char ipstr[INET_ADDRSTRLEN+1];
+
+ if (ifname == NULL) {
+ return NULL;
+ }
+
+ /* DCFIXME: add IPv6 once NM gains support */
+ if (family != AF_INET) {
+ return NULL;
+ }
+
+ g_type_init();
+
+ client = nm_client_new();
+ if (!client) {
+ return NULL;
+ }
+
+ if (nm_client_get_state(client) != NM_STATE_CONNECTED) {
+ g_object_unref(client);
+ return NULL;
+ }
+
+ devices = nm_client_get_devices(client);
+ for (i=0; i < devices->len; i++) {
+ candidate = g_ptr_array_index(devices, i);
+ iface = nm_device_get_iface(candidate);
+
+ if (nm_device_get_state(candidate) != NM_DEVICE_STATE_ACTIVATED)
+ continue;
+
+ if (!iface || strcmp(iface, ifname))
+ continue;
+
+ if (!(ip4config = nm_device_get_ip4_config(candidate)))
+ continue;
+
+ if (!(ipaddr = nm_ip4_config_get_addresses(ip4config)->data))
+ continue;
+
+ memset(&ipstr, '\0', sizeof(ipstr));
+ tmp_addr.s_addr = nm_ip4_address_get_address(ipaddr);
+
+ if (inet_ntop(AF_INET, &tmp_addr, ipstr, INET_ADDRSTRLEN) == NULL) {
+ g_object_unref(client);
+ return NULL;
+ }
+
+ g_object_unref(client);
+ return g_strdup(ipstr);
+ }
+
+ g_object_unref(client);
+ return NULL;
+}
+
+/* Given an interface's MAC address, return the name (e.g., eth0) in human
+ * readable format. Return NULL for no match
+ */
+char *iface_mac2device(char *mac) {
+ struct nl_handle *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *link = NULL;
+ struct nl_addr *mac_as_nl_addr = NULL;
+ char *retval = NULL;
+ int i, n;
+
+ if (mac == NULL) {
+ return NULL;
+ }
+
+ if ((mac_as_nl_addr = nl_addr_parse(mac, AF_LLC)) == NULL) {
+ return NULL;
+ }
+
+ if ((cache = _iface_get_link_cache(&handle)) == NULL) {
+ return NULL;
+ }
+
+ n = nl_cache_nitems(cache);
+ for (i = 0; i <= n; i++) {
+ struct nl_addr *addr;
+
+ if ((link = rtnl_link_get(cache, i)) == NULL) {
+ continue;
+ }
+
+ addr = rtnl_link_get_addr(link);
+
+ if (!nl_addr_cmp(mac_as_nl_addr, addr)) {
+ retval = strdup(rtnl_link_get_name(link));
+ rtnl_link_put(link);
+ break;
+ }
+
+ rtnl_link_put(link);
+ }
+
+ nl_close(handle);
+ nl_handle_destroy(handle);
+
+ return retval;
+}
+
+/*
+ * Given an interface name (e.g., eth0), return the MAC address in human
+ * readable format (e.g., 00:11:52:12:D9:A0). Return NULL for no match.
+ */
+char *iface_mac2str(char *ifname) {
+ int buflen = 20;
+ char *buf = NULL;
+ struct nl_handle *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *link = NULL;
+ struct nl_addr *addr = NULL;
+
+ if (ifname == NULL) {
+ return NULL;
+ }
+
+ if ((cache = _iface_get_link_cache(&handle)) == NULL) {
+ return NULL;
+ }
+
+ if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) {
+ goto mac2str_error2;
+ }
+
+ if ((addr = rtnl_link_get_addr(link)) == NULL) {
+ goto mac2str_error3;
+ }
+
+ if ((buf = calloc(sizeof(char *), buflen)) == NULL) {
+ goto mac2str_error4;
+ }
+
+ if ((buf = nl_addr2str(addr, buf, buflen)) != NULL) {
+ char *oldbuf = buf;
+ buf = g_ascii_strup(buf, -1);
+ free(oldbuf);
+ }
+
+mac2str_error4:
+ nl_addr_destroy(addr);
+mac2str_error3:
+ rtnl_link_put(link);
+mac2str_error2:
+ nl_close(handle);
+ nl_handle_destroy(handle);
+
+ return buf;
+}
+
+/*
+ * Convert an IPv4 CIDR prefix to a dotted-quad netmask. Return NULL on
+ * failure.
+ */
+struct in_addr *iface_prefix2netmask(int prefix) {
+ int mask = 0;
+ char *buf = NULL;
+ struct in_addr *ret;
+
+ if ((buf = calloc(sizeof(char *), INET_ADDRSTRLEN + 1)) == NULL) {
+ return NULL;
+ }
+
+ mask = htonl(~((1 << (32 - prefix)) - 1));
+
+ if (inet_ntop(AF_INET, (struct in_addr *) &mask, buf,
+ INET_ADDRSTRLEN) == NULL) {
+ return NULL;
+ }
+
+ if ((ret = calloc(sizeof(struct in_addr), 1)) == NULL) {
+ return NULL;
+ }
+
+ memcpy(ret, (struct in_addr *) &mask, sizeof(struct in_addr));
+ return ret;
+}
+
+/*
+ * Initialize a new iface_t structure to default values.
+ */
+void iface_init_iface_t(iface_t *iface) {
+ int i;
+
+ memset(&iface->device, '\0', sizeof(iface->device));
+ memset(&iface->ipaddr, 0, sizeof(iface->ipaddr));
+ memset(&iface->netmask, 0, sizeof(iface->netmask));
+ memset(&iface->broadcast, 0, sizeof(iface->broadcast));
+ memset(&iface->ip6addr, 0, sizeof(iface->ip6addr));
+ memset(&iface->gateway, 0, sizeof(iface->gateway));
+ memset(&iface->gateway6, 0, sizeof(iface->gateway6));
+
+ for (i = 0; i < MAXNS; i++) {
+ iface->dns[i] = NULL;
+ }
+
+ iface->macaddr = NULL;
+ iface->ip6prefix = 0;
+ iface->nextserver = NULL;
+ iface->bootfile = NULL;
+ iface->numdns = 0;
+ iface->hostname = NULL;
+ iface->domain = NULL;
+ iface->search = NULL;
+ iface->dhcptimeout = 0;
+ iface->vendorclass = NULL;
+ iface->ssid = NULL;
+ iface->wepkey = NULL;
+ iface->mtu = 0;
+ iface->subchannels = NULL;
+ iface->portname = NULL;
+ iface->peerid = NULL;
+ iface->nettype = NULL;
+ iface->ctcprot = NULL;
+ iface->layer2 = NULL;
+ iface->portno = NULL;
+ iface->flags = 0;
+ iface->ipv4method = IPV4_UNUSED_METHOD;
+ iface->ipv6method = IPV6_UNUSED_METHOD;
+
+ return;
+}
+
+/*
+ * Given a pointer to a struct in_addr, return 1 if it contains a valid
+ * address, 0 otherwise.
+ */
+int iface_have_in_addr(struct in_addr *addr) {
+ return _iface_have_valid_addr(addr, AF_INET, INET_ADDRSTRLEN);
+}
+
+/*
+ * Given a pointer to a struct in6_addr, return 1 if it contains a valid
+ * address, 0 otherwise.
+ */
+int iface_have_in6_addr(struct in6_addr *addr6) {
+ return _iface_have_valid_addr(addr6, AF_INET6, INET6_ADDRSTRLEN);
+}
+
+/* Check if NM has an active connection */
+gboolean is_nm_connected(void) {
+ NMState state;
+ NMClient *client = NULL;
+
+ g_type_init();
+
+ client = nm_client_new();
+ if (!client)
+ return FALSE;
+
+ state = nm_client_get_state(client);
+ g_object_unref(client);
+
+ if (state == NM_STATE_CONNECTED)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+/* Check if NM is already running */
+gboolean is_nm_running(void) {
+ gboolean running;
+ NMClient *client = NULL;
+
+ g_type_init();
+
+ client = nm_client_new();
+ if (!client)
+ return FALSE;
+
+ running = nm_client_get_manager_running(client);
+ g_object_unref(client);
+ return running;
+}
+
+/*
+ * Wait for NetworkManager to appear on the system bus
+ */
+int wait_for_nm(void) {
+ int count = 0;
+
+ /* send message and block until a reply or error comes back */
+ while (count < 45) {
+ if (is_nm_running())
+ return 0;
+
+ sleep(1);
+ count++;
+ }
+
+ return 1;
+}
+
+/*
+ * Start NetworkManager -- requires that you have already written out the
+ * control files in /etc/sysconfig for the interface.
+ */
+int iface_start_NetworkManager(void) {
+ pid_t pid;
+
+ if (is_nm_running())
+ return 0; /* already running */
+
+ /* Start NetworkManager */
+ pid = fork();
+ if (pid == 0) {
+ if (setpgrp() == -1) {
+ exit(1);
+ }
+
+ if (_iface_redirect_io("/dev/null", STDIN_FILENO, O_RDONLY) ||
+ _iface_redirect_io(OUTPUT_TERMINAL, STDOUT_FILENO, O_WRONLY) ||
+ _iface_redirect_io(OUTPUT_TERMINAL, STDERR_FILENO, O_WRONLY)) {
+ exit(2);
+ }
+
+ if (execl(NETWORKMANAGER, NETWORKMANAGER,
+ "--pid-file=/var/run/NetworkManager/NetworkManager.pid",
+ NULL) == -1) {
+ exit(3);
+ }
+ } else if (pid == -1) {
+ return 1;
+ } else {
+ return wait_for_nm();
+ }
+
+ return 0;
+}
+
+/*
+ * Set the MTU on the specified device.
+ */
+int iface_set_interface_mtu(char *ifname, int mtu) {
+ int ret = 0;
+ struct nl_handle *handle = NULL;
+ struct nl_cache *cache = NULL;
+ struct rtnl_link *link = NULL;
+ struct rtnl_link *request = NULL;
+
+ if (ifname == NULL) {
+ return -1;
+ }
+
+ if (mtu <= 0) {
+ return -2;
+ }
+
+ if ((cache = _iface_get_link_cache(&handle)) == NULL) {
+ return -3;
+ }
+
+ if ((link = rtnl_link_get_by_name(cache, ifname)) == NULL) {
+ ret = -4;
+ goto ifacemtu_error1;
+ }
+
+ request = rtnl_link_alloc();
+ rtnl_link_set_mtu(request, mtu);
+
+ if (rtnl_link_change(handle, link, request, 0)) {
+ ret = -5;
+ goto ifacemtu_error2;
+ }
+
+ifacemtu_error2:
+ rtnl_link_put(link);
+ifacemtu_error1:
+ nl_close(handle);
+ nl_handle_destroy(handle);
+
+ return ret;
+}
diff --git a/isys/iface.h b/isys/iface.h
new file mode 100644
index 0000000..820d10b
--- /dev/null
+++ b/isys/iface.h
@@ -0,0 +1,166 @@
+/*
+ * iface.h - Network interface configuration API
+ *
+ * Copyright (C) 2006, 2007, 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): David Cantrell <dcantrell@redhat.com>
+ */
+
+#ifndef ISYSIFACE_H
+#define ISYSIFACE_H
+
+#include <resolv.h>
+#include <net/if.h>
+#include <netlink/cache.h>
+#include <netlink/socket.h>
+#include <glib.h>
+
+/* Enumerated types used in iface.c as well as loader's network code */
+enum { IPUNUSED = -1, IPV4, IPV6 };
+
+enum { IPV4_UNUSED_METHOD, IPV4_DHCP_METHOD, IPV4_MANUAL_METHOD, IPV4_IBFT_METHOD, IPV4_IBFT_DHCP_METHOD };
+enum { IPV6_UNUSED_METHOD, IPV6_AUTO_METHOD, IPV6_DHCP_METHOD,
+ IPV6_MANUAL_METHOD };
+
+#define IPV4_FIRST_METHOD IPV4_DHCP_METHOD
+#define IPV4_LAST_METHOD IPV4_MANUAL_METHOD
+
+#define IPV6_FIRST_METHOD IPV6_AUTO_METHOD
+#define IPV6_LAST_METHOD IPV6_MANUAL_METHOD
+
+/* Flags for the iface_t (do we need these?) */
+#define IFACE_FLAGS_NO_WRITE_RESOLV_CONF (((uint64_t) 1) << 0)
+#define IFACE_NO_WRITE_RESOLV_CONF(a) ((a) & IFACE_FLAGS_NO_WRITE_RESOLV_CONF)
+
+/* Macros for starting NetworkManager */
+#define NETWORKMANAGER "/usr/sbin/NetworkManager"
+
+/* Per-interface configuration information */
+typedef struct _iface_t {
+ /* device name (e.g., eth0) */
+ char device[IF_NAMESIZE];
+
+ /* MAC address as xx:xx:xx:xx:xx:xx */
+ char *macaddr;
+
+ /* IPv4 (store addresses in in_addr format, use inet_pton() to display) */
+ struct in_addr ipaddr;
+ struct in_addr netmask;
+ struct in_addr broadcast;
+
+ /* IPv6 (store addresses in in6_addr format, prefix is just an int) */
+ struct in6_addr ip6addr;
+ int ip6prefix;
+
+ /* Gateway settings */
+ struct in_addr gateway;
+ struct in6_addr gateway6;
+
+ /* BOOTP (these can be IPv4 or IPv6, store human-readable version as str) */
+ char *nextserver;
+ char *bootfile;
+
+ /* DNS (these can be IPv4 or IPv6, store human-readable version as str) */
+ char *dns[MAXNS];
+ int numdns;
+ char *hostname;
+ char *domain;
+ char *search;
+
+ /* Misc DHCP settings */
+ int dhcptimeout;
+ char *vendorclass;
+
+ /* Wireless settings */
+ char *ssid;
+ char *wepkey;
+
+ /* s390 specifics */
+ int mtu;
+ char *subchannels;
+ char *portname;
+ char *peerid;
+ char *nettype;
+ char *ctcprot;
+ char *layer2;
+ char *portno;
+
+ /* flags */
+ uint64_t flags;
+ int ipv4method;
+ int ipv6method;
+ int isiBFT;
+} iface_t;
+
+/* Function prototypes */
+
+/*
+ * Given an interface name (e.g., eth0) and address family (e.g., AF_INET),
+ * return the IP address in human readable format (i.e., the output from
+ * inet_ntop()). Return NULL for no match or error.
+ */
+char *iface_ip2str(char *, int);
+
+/*
+ * Given an interface name (e.g., eth0), return the MAC address in human
+ * readable format (e.g., 00:11:52:12:D9:A0). Return NULL for no match.
+ */
+char *iface_mac2str(char *);
+
+/* Given an interface's MAC address, return the name (e.g., eth0) in human
+ * readable format. Return NULL for no match
+ */
+char *iface_mac2device(char *);
+
+/*
+ * Convert an IPv4 CIDR prefix to a dotted-quad netmask. Return NULL on
+ * failure.
+ */
+struct in_addr *iface_prefix2netmask(int);
+
+/*
+ * Initialize a new iface_t structure to default values.
+ */
+void iface_init_iface_t(iface_t *);
+
+/*
+ * Given a pointer to a struct in_addr, return 1 if it contains a valid
+ * address, 0 otherwise.
+ */
+int iface_have_in_addr(struct in_addr *addr);
+
+/*
+ * Given a pointer to a struct in6_addr, return 1 if it contains a valid
+ * address, 0 otherwise.
+ */
+int iface_have_in6_addr(struct in6_addr *addr6);
+
+/*
+ * Checks if NetworkManager has an active connection.
+ */
+gboolean is_nm_connected(void);
+
+/*
+ * Start NetworkManager
+ */
+int iface_start_NetworkManager(void);
+
+/*
+ * Set Maximum Transfer Unit (MTU) on specified interface
+ */
+int iface_set_interface_mtu(char *ifname, int mtu);
+
+#endif /* ISYSIFACE_H */
diff --git a/isys/imount.c b/isys/imount.c
new file mode 100644
index 0000000..be5b760
--- /dev/null
+++ b/isys/imount.c
@@ -0,0 +1,315 @@
+/*
+ * imount.c
+ *
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include "imount.h"
+#include "log.h"
+
+#define _(foo) foo
+
+static int mkdirIfNone(char * directory);
+
+static int readFD(int fd, char **buf) {
+ char *p;
+ size_t size = 4096;
+ int s, filesize = 0;
+
+ *buf = calloc(4096, sizeof (char));
+ if (*buf == NULL)
+ abort();
+
+ do {
+ p = &(*buf)[filesize];
+ s = read(fd, p, 4096);
+ if (s < 0)
+ break;
+
+ filesize += s;
+ if (s == 0)
+ break;
+
+ size += s;
+ *buf = realloc(*buf, size);
+ if (*buf == NULL)
+ abort();
+ } while (1);
+
+ if (filesize == 0 && s < 0) {
+ free(*buf);
+ *buf = NULL;
+ return -1;
+ }
+
+ return filesize;
+}
+
+static size_t rstrip(char *str) {
+ size_t len = strlen(str);
+ if (len > 0 && str[len-1] == '\n') {
+ str[len-1] = '\0';
+ --len;
+ }
+ return len;
+}
+
+int mountCommandWrapper(int mode, char *dev, char *where, char *fs,
+ char *options, char **err) {
+ int rc, child, status;
+ int stdout_pipe[2], stderr_pipe[2];
+ char *opts = NULL, *device = NULL, *cmd = NULL;
+
+ if (mode == IMOUNT_MODE_MOUNT) {
+ cmd = "/bin/mount";
+ } else if (mode == IMOUNT_MODE_UMOUNT) {
+ cmd = "/bin/umount";
+ } else {
+ return IMOUNT_ERR_MODE;
+ }
+
+ if (mode == IMOUNT_MODE_MOUNT) {
+ if (mkdirChain(where))
+ return IMOUNT_ERR_ERRNO;
+
+ if (strstr(fs, "nfs")) {
+ if (options) {
+ if (asprintf(&opts, "%s,nolock", options) == -1) {
+ fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__,
+ strerror(errno));
+ fflush(stderr);
+ abort();
+ }
+ } else {
+ opts = strdup("nolock");
+ }
+
+ device = strdup(dev);
+ } else {
+ if ((options && strstr(options, "bind") == NULL) &&
+ strncmp(dev, "LABEL=", 6) && strncmp(dev, "UUID=", 5) &&
+ *dev != '/') {
+ if (asprintf(&device, "/dev/%s", dev) == -1) {
+ fprintf(stderr, "%s: %d: %s\n", __func__, __LINE__,
+ strerror(errno));
+ fflush(stderr);
+ abort();
+ }
+ } else {
+ device = strdup(dev);
+ }
+
+ if (options)
+ opts = strdup(options);
+ }
+ }
+
+ if (pipe(stdout_pipe))
+ return IMOUNT_ERR_ERRNO;
+ if (pipe(stderr_pipe))
+ return IMOUNT_ERR_ERRNO;
+
+ if (!(child = fork())) {
+ int tty_fd;
+
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
+
+ /* Pull stdin from /dev/tty5 and redirect stdout and stderr to the pipes
+ * so we can log the output and put error messages into exceptions.
+ * We'll only use these messages should mount also return an error
+ * code.
+ */
+ tty_fd = open("/dev/tty5", O_RDONLY);
+ close(STDIN_FILENO);
+ dup2(tty_fd, STDIN_FILENO);
+ close(tty_fd);
+
+ close(STDOUT_FILENO);
+ dup2(stdout_pipe[1], STDOUT_FILENO);
+ close(STDERR_FILENO);
+ dup2(stderr_pipe[1], STDERR_FILENO);
+
+ if (mode == IMOUNT_MODE_MOUNT) {
+ if (opts) {
+ logProgramMessage(INFO, "Running... %s -n -t %s -o %s %s %s",
+ cmd, fs, opts, device, where);
+ rc = execl(cmd, cmd,
+ "-n", "-t", fs, "-o", opts, device, where, NULL);
+ exit(1);
+ } else {
+ logProgramMessage(INFO, "Running... %s -n -t %s %s %s",
+ cmd, fs, device, where);
+ rc = execl(cmd, cmd, "-n", "-t", fs, device, where, NULL);
+ exit(1);
+ }
+ } else if (mode == IMOUNT_MODE_UMOUNT) {
+ logProgramMessage(INFO, "Running... %s %s", cmd, where);
+ rc = execl(cmd, cmd, where, NULL);
+ exit(1);
+ } else {
+ logProgramMessage(ERROR, "Running... Unknown imount mode: %d\n", mode);
+ exit(1);
+ }
+ }
+
+ close(stdout_pipe[1]);
+ close(stderr_pipe[1]);
+
+ char *buffer = NULL;
+ /* In case when when the stderr pipe gets enough data to fill the kernel
+ * buffer we might see a deadlock as this will block the mount program on
+ * its next write(). The buffer size is 65kB though so we should be safe.
+ */
+ rc = readFD(stdout_pipe[0], &buffer);
+ if (rc > 0) {
+ rstrip(buffer);
+ logProgramMessage(INFO, "%s", buffer);
+ free(buffer);
+ buffer = NULL;
+ }
+ rc = readFD(stderr_pipe[0], &buffer);
+ if (rc > 0) {
+ rstrip(buffer);
+ logProgramMessage(ERROR, "%s", buffer);
+ if (err != NULL)
+ *err = buffer;
+ else
+ free(buffer);
+ }
+ close(stdout_pipe[0]);
+ close(stderr_pipe[0]);
+
+ waitpid(child, &status, 0);
+
+ if (opts) {
+ free(opts);
+ }
+
+ if (device) {
+ free(device);
+ }
+
+ if (!WIFEXITED(status))
+ return IMOUNT_ERR_OTHER;
+ else if ( (rc = WEXITSTATUS(status)) ) {
+ /* Refer to 'man mount' for the meaning of the error codes. */
+ switch (rc) {
+ case 1:
+ return IMOUNT_ERR_PERMISSIONS;
+ case 2:
+ return IMOUNT_ERR_SYSTEM;
+ case 4:
+ return IMOUNT_ERR_MOUNTINTERNAL;
+ case 8:
+ return IMOUNT_ERR_USERINTERRUPT;
+ case 16:
+ return IMOUNT_ERR_MTAB;
+ case 32:
+ return IMOUNT_ERR_MOUNTFAILURE;
+ case 64:
+ return IMOUNT_ERR_PARTIALSUCC;
+ default:
+ return IMOUNT_ERR_OTHER;
+ }
+ }
+
+ return 0;
+}
+
+int doPwMount(char *dev, char *where, char *fs, char *options, char **err) {
+ return mountCommandWrapper(IMOUNT_MODE_MOUNT,
+ dev, where, fs, options, err);
+}
+
+int doPwUmount(char *where, char **err) {
+ return mountCommandWrapper(IMOUNT_MODE_UMOUNT,
+ NULL, where, NULL, NULL, err);
+}
+
+int mkdirChain(char * origChain) {
+ char * chain;
+ char * chptr;
+
+ chain = alloca(strlen(origChain) + 1);
+ strcpy(chain, origChain);
+ chptr = chain;
+
+ while ((chptr = strchr(chptr, '/'))) {
+ *chptr = '\0';
+ if (mkdirIfNone(chain)) {
+ *chptr = '/';
+ return IMOUNT_ERR_ERRNO;
+ }
+
+ *chptr = '/';
+ chptr++;
+ }
+
+ if (mkdirIfNone(chain))
+ return IMOUNT_ERR_ERRNO;
+
+ return 0;
+}
+
+/* Returns true iff it is possible that the mount command that have returned
+ * 'errno' might succeed at a later time (think e.g. not yet initialized USB
+ * device, etc.) */
+int mountMightSucceedLater(int mountRc)
+{
+ int rc;
+ switch (mountRc) {
+ case IMOUNT_ERR_MOUNTFAILURE:
+ rc = 1;
+ break;
+ default:
+ rc = 0;
+ }
+ return rc;
+}
+
+static int mkdirIfNone(char * directory) {
+ int rc, mkerr;
+ char * chptr;
+
+ /* If the file exists it *better* be a directory -- I'm not going to
+ actually check or anything */
+ if (!access(directory, X_OK)) return 0;
+
+ /* if the path is '/' we get ENOFILE not found" from mkdir, rather
+ then EEXIST which is weird */
+ for (chptr = directory; *chptr; chptr++)
+ if (*chptr != '/') break;
+ if (!*chptr) return 0;
+
+ rc = mkdir(directory, 0755);
+ mkerr = errno;
+
+ if (!rc || mkerr == EEXIST) return 0;
+
+ return IMOUNT_ERR_ERRNO;
+}
diff --git a/isys/imount.h b/isys/imount.h
new file mode 100644
index 0000000..9fa6769
--- /dev/null
+++ b/isys/imount.h
@@ -0,0 +1,48 @@
+/*
+ * imount.h
+ *
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_IMOUNT
+#define H_IMOUNT
+
+#define IMOUNT_ERR_ERRNO 1
+#define IMOUNT_ERR_OTHER 2
+#define IMOUNT_ERR_MODE 3
+#define IMOUNT_ERR_PERMISSIONS 4
+#define IMOUNT_ERR_SYSTEM 5
+#define IMOUNT_ERR_MOUNTINTERNAL 6
+#define IMOUNT_ERR_USERINTERRUPT 7
+#define IMOUNT_ERR_MTAB 8
+#define IMOUNT_ERR_MOUNTFAILURE 9
+#define IMOUNT_ERR_PARTIALSUCC 10
+
+#include <sys/mount.h> /* for umount() */
+
+#define IMOUNT_RDONLY 1
+#define IMOUNT_BIND 2
+#define IMOUNT_REMOUNT 4
+
+#define IMOUNT_MODE_MOUNT 1
+#define IMOUNT_MODE_UMOUNT 2
+
+int doPwMount(char *dev, char *where, char *fs, char *options, char **err);
+int doPwUmount(char *where, char **err);
+int mkdirChain(char * origChain);
+int mountMightSucceedLater(int mountRc);
+
+#endif
diff --git a/isys/isofs.c b/isys/isofs.c
new file mode 100644
index 0000000..bb5a44a
--- /dev/null
+++ b/isys/isofs.c
@@ -0,0 +1,55 @@
+/*
+ * isofs.c
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#define BLOCK_SIZE 2048
+
+/* returns 1 if file is an ISO, 0 otherwise */
+int fileIsIso(const char * file) {
+ int blkNum;
+ char magic[5];
+ int fd;
+
+ fd = open(file, O_RDONLY);
+ if (fd < 0)
+ return 0;
+
+ for (blkNum = 16; blkNum < 100; blkNum++) {
+ if (lseek(fd, blkNum * BLOCK_SIZE + 1, SEEK_SET) < 0) {
+ close(fd);
+ return 0;
+ }
+
+ if (read(fd, magic, sizeof(magic)) != sizeof(magic)) {
+ close(fd);
+ return 0;
+ }
+
+ if (!strncmp(magic, "CD001", 5)) {
+ close(fd);
+ return 1;
+ }
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/isys/isys.c b/isys/isys.c
new file mode 100644
index 0000000..6b49ba6
--- /dev/null
+++ b/isys/isys.c
@@ -0,0 +1,700 @@
+/*
+ * isys.c
+ *
+ * Copyright (C) 2007, 2008, 2009 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <Python.h>
+
+#include <stdio.h>
+#include <dirent.h>
+#include <errno.h>
+#define u32 __u32
+#include <ext2fs/ext2fs.h>
+#include <fcntl.h>
+/* Need to tell loop.h what the actual dev_t type is. */
+#undef dev_t
+#if defined(__alpha) || (defined(__sparc__) && defined(__arch64__))
+#define dev_t unsigned int
+#else
+#if defined(__x86_64__)
+#define dev_t unsigned long
+#else
+#define dev_t unsigned short
+#endif
+#endif
+#include <linux/loop.h>
+#undef dev_t
+#define dev_t dev_t
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/time.h>
+#include <sys/utsname.h>
+#include <sys/vfs.h>
+#include <unistd.h>
+#include <resolv.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+#include <sys/vt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <linux/fb.h>
+#include <libintl.h>
+#include <libgen.h>
+#include <linux/cdrom.h>
+#include <linux/major.h>
+#include <linux/raid/md_u.h>
+#include <linux/raid/md_p.h>
+#include <signal.h>
+#include <execinfo.h>
+
+#include <blkid/blkid.h>
+
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+#include <X11/keysym.h>
+
+#include "iface.h"
+#include "isys.h"
+#include "imount.h"
+#include "ethtool.h"
+#include "lang.h"
+#include "eddsupport.h"
+#include "auditd.h"
+#include "imount.h"
+#include "log.h"
+
+#ifndef CDROMEJECT
+#define CDROMEJECT 0x5309
+#endif
+
+static PyObject * doMount(PyObject * s, PyObject * args);
+static PyObject * doUMount(PyObject * s, PyObject * args);
+static PyObject * doSwapon(PyObject * s, PyObject * args);
+static PyObject * doSwapoff(PyObject * s, PyObject * args);
+static PyObject * doLoSetup(PyObject * s, PyObject * args);
+static PyObject * doUnLoSetup(PyObject * s, PyObject * args);
+static PyObject * doLoChangeFd(PyObject * s, PyObject * args);
+static PyObject * doWipeRaidSuperblock(PyObject * s, PyObject * args);
+static PyObject * doGetRaidChunkSize(PyObject * s, PyObject * args);
+static PyObject * doDevSpaceFree(PyObject * s, PyObject * args);
+static PyObject * doResetResolv(PyObject * s, PyObject * args);
+static PyObject * doLoadKeymap(PyObject * s, PyObject * args);
+static PyObject * doExt2Dirty(PyObject * s, PyObject * args);
+static PyObject * doExt2HasJournal(PyObject * s, PyObject * args);
+static PyObject * doEjectCdrom(PyObject * s, PyObject * args);
+static PyObject * doVtActivate(PyObject * s, PyObject * args);
+static PyObject * doisPseudoTTY(PyObject * s, PyObject * args);
+static PyObject * doisVioConsole(PyObject * s);
+static PyObject * doSync(PyObject * s, PyObject * args);
+static PyObject * doisIsoImage(PyObject * s, PyObject * args);
+static PyObject * printObject(PyObject * s, PyObject * args);
+static PyObject * py_bind_textdomain_codeset(PyObject * o, PyObject * args);
+static PyObject * doSegvHandler(PyObject *s, PyObject *args);
+static PyObject * doAuditDaemon(PyObject *s);
+static PyObject * doPrefixToNetmask(PyObject *s, PyObject *args);
+static PyObject * doGetBlkidData(PyObject * s, PyObject * args);
+static PyObject * doIsCapsLockEnabled(PyObject * s, PyObject * args);
+static PyObject * doGetLinkStatus(PyObject * s, PyObject * args);
+static PyObject * doGetAnacondaVersion(PyObject * s, PyObject * args);
+static PyObject * doInitLog(PyObject * s);
+
+static PyMethodDef isysModuleMethods[] = {
+ { "ejectcdrom", (PyCFunction) doEjectCdrom, METH_VARARGS, NULL },
+ { "e2dirty", (PyCFunction) doExt2Dirty, METH_VARARGS, NULL },
+ { "e2hasjournal", (PyCFunction) doExt2HasJournal, METH_VARARGS, NULL },
+ { "devSpaceFree", (PyCFunction) doDevSpaceFree, METH_VARARGS, NULL },
+ { "wiperaidsb", (PyCFunction) doWipeRaidSuperblock, METH_VARARGS, NULL },
+ { "getraidchunk", (PyCFunction) doGetRaidChunkSize, METH_VARARGS, NULL },
+ { "lochangefd", (PyCFunction) doLoChangeFd, METH_VARARGS, NULL },
+ { "losetup", (PyCFunction) doLoSetup, METH_VARARGS, NULL },
+ { "unlosetup", (PyCFunction) doUnLoSetup, METH_VARARGS, NULL },
+ { "mount", (PyCFunction) doMount, METH_VARARGS, NULL },
+ { "umount", (PyCFunction) doUMount, METH_VARARGS, NULL },
+ { "resetresolv", (PyCFunction) doResetResolv, METH_VARARGS, NULL },
+ { "swapon", (PyCFunction) doSwapon, METH_VARARGS, NULL },
+ { "swapoff", (PyCFunction) doSwapoff, METH_VARARGS, NULL },
+ { "loadKeymap", (PyCFunction) doLoadKeymap, METH_VARARGS, NULL },
+ { "vtActivate", (PyCFunction) doVtActivate, METH_VARARGS, NULL},
+ { "isPseudoTTY", (PyCFunction) doisPseudoTTY, METH_VARARGS, NULL},
+ { "isVioConsole", (PyCFunction) doisVioConsole, METH_NOARGS, NULL},
+ { "sync", (PyCFunction) doSync, METH_VARARGS, NULL},
+ { "isisoimage", (PyCFunction) doisIsoImage, METH_VARARGS, NULL},
+ { "printObject", (PyCFunction) printObject, METH_VARARGS, NULL},
+ { "bind_textdomain_codeset", (PyCFunction) py_bind_textdomain_codeset, METH_VARARGS, NULL},
+ { "handleSegv", (PyCFunction) doSegvHandler, METH_VARARGS, NULL },
+ { "auditdaemon", (PyCFunction) doAuditDaemon, METH_NOARGS, NULL },
+ { "prefix2netmask", (PyCFunction) doPrefixToNetmask, METH_VARARGS, NULL },
+ { "getblkid", (PyCFunction) doGetBlkidData, METH_VARARGS, NULL },
+ { "isCapsLockEnabled", (PyCFunction) doIsCapsLockEnabled, METH_VARARGS, NULL },
+ { "getLinkStatus", (PyCFunction) doGetLinkStatus, METH_VARARGS, NULL },
+ { "getAnacondaVersion", (PyCFunction) doGetAnacondaVersion, METH_VARARGS, NULL },
+ { "initLog", (PyCFunction) doInitLog, METH_VARARGS, NULL },
+ { NULL, NULL, 0, NULL }
+} ;
+
+static PyObject * doUnLoSetup(PyObject * s, PyObject * args) {
+ int loopfd;
+
+ if (!PyArg_ParseTuple(args, "i", &loopfd)) return NULL;
+ if (ioctl(loopfd, LOOP_CLR_FD, 0)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* XXX - msw */
+#ifndef LOOP_CHANGE_FD
+#define LOOP_CHANGE_FD 0x4C06
+#endif
+
+static PyObject * doLoChangeFd(PyObject * s, PyObject * args) {
+ int loopfd;
+ int targfd;
+
+ if (!PyArg_ParseTuple(args, "ii", &loopfd, &targfd))
+ return NULL;
+ if (ioctl(loopfd, LOOP_CHANGE_FD, targfd)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doLoSetup(PyObject * s, PyObject * args) {
+ int loopfd;
+ int targfd;
+ struct loop_info loopInfo;
+ char * loopName;
+
+ if (!PyArg_ParseTuple(args, "iis", &loopfd, &targfd, &loopName))
+ return NULL;
+ if (ioctl(loopfd, LOOP_SET_FD, targfd)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ memset(&loopInfo, 0, sizeof(loopInfo));
+ strncpy(loopInfo.lo_name, basename(loopName), 63);
+
+ if (ioctl(loopfd, LOOP_SET_STATUS, &loopInfo)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doUMount(PyObject * s, PyObject * args) {
+ char *err = NULL, *mntpoint = NULL;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &mntpoint)) {
+ return NULL;
+ }
+
+ rc = doPwUmount(mntpoint, &err);
+ if (rc == IMOUNT_ERR_ERRNO) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ } else if (rc) {
+ PyObject *tuple = PyTuple_New(2);
+
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(rc));
+
+ if (err == NULL) {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(tuple, 1, Py_None);
+ } else {
+ PyTuple_SetItem(tuple, 1, PyString_FromString(err));
+ }
+
+ PyErr_SetObject(PyExc_SystemError, tuple);
+ }
+
+ if (rc) {
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doMount(PyObject * s, PyObject * args) {
+ char *err = NULL, *fs, *device, *mntpoint, *flags = NULL;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "sss|z", &fs, &device, &mntpoint,
+ &flags)) return NULL;
+
+ rc = doPwMount(device, mntpoint, fs, flags, &err);
+ if (rc == IMOUNT_ERR_ERRNO)
+ PyErr_SetFromErrno(PyExc_SystemError);
+ else if (rc) {
+ PyObject *tuple = PyTuple_New(2);
+
+ PyTuple_SetItem(tuple, 0, PyInt_FromLong(rc));
+
+ if (err == NULL) {
+ Py_INCREF(Py_None);
+ PyTuple_SetItem(tuple, 1, Py_None);
+ } else {
+ PyTuple_SetItem(tuple, 1, PyString_FromString(err));
+ }
+
+ PyErr_SetObject(PyExc_SystemError, tuple);
+ }
+
+ if (rc) return NULL;
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+#define BOOT_SIGNATURE 0xaa55 /* boot signature */
+#define BOOT_SIG_OFFSET 510 /* boot signature offset */
+
+int swapoff(const char * path);
+int swapon(const char * path, int priorty);
+
+static PyObject * doSwapoff (PyObject * s, PyObject * args) {
+ char * path;
+
+ if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
+
+ if (swapoff (path)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doSwapon (PyObject * s, PyObject * args) {
+ char * path;
+
+ if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
+
+ if (swapon (path, 0)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+void init_isys(void) {
+ PyObject * m, * d;
+
+ m = Py_InitModule("_isys", isysModuleMethods);
+ d = PyModule_GetDict(m);
+
+ PyDict_SetItemString(d, "MIN_RAM", PyInt_FromLong(MIN_RAM));
+ PyDict_SetItemString(d, "MIN_GUI_RAM", PyInt_FromLong(MIN_GUI_RAM));
+ PyDict_SetItemString(d, "EARLY_SWAP_RAM", PyInt_FromLong(EARLY_SWAP_RAM));
+}
+
+static PyObject * doPrefixToNetmask (PyObject * s, PyObject * args) {
+ int prefix = 0;
+ struct in_addr *mask = NULL;
+ char dst[INET_ADDRSTRLEN+1];
+
+ if (!PyArg_ParseTuple(args, "i", &prefix))
+ return NULL;
+
+ if ((mask = iface_prefix2netmask(prefix)) == NULL)
+ return NULL;
+
+ if (inet_ntop(AF_INET, mask, dst, INET_ADDRSTRLEN) == NULL)
+ return NULL;
+
+ return Py_BuildValue("s", dst);
+}
+
+static PyObject * doResetResolv(PyObject * s, PyObject * args) {
+ if (!PyArg_ParseTuple(args, "")) {
+ return NULL;
+ }
+
+ /* reinit the resolver so DNS changes take affect */
+ res_init();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doWipeRaidSuperblock(PyObject * s, PyObject * args) {
+ int fd;
+ unsigned long size;
+ struct mdp_super_t * sb;
+
+ if (!PyArg_ParseTuple(args, "i", &fd)) return NULL;
+
+ if (ioctl(fd, BLKGETSIZE, &size)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ /* put the size in 1k blocks */
+ size >>= 1;
+
+ if (lseek64(fd, ((off64_t) 512) * (off64_t) MD_NEW_SIZE_SECTORS(size), SEEK_SET) < 0) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ sb = malloc(sizeof(mdp_super_t));
+ sb = memset(sb, '\0', sizeof(mdp_super_t));
+
+ if (write(fd, sb, sizeof(sb)) != sizeof(sb)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ return Py_None;
+}
+
+static PyObject * doGetRaidChunkSize(PyObject * s, PyObject * args) {
+ int fd;
+ unsigned long size;
+ mdp_super_t sb;
+
+ if (!PyArg_ParseTuple(args, "i", &fd)) return NULL;
+
+ if (ioctl(fd, BLKGETSIZE, &size)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ /* put the size in 1k blocks */
+ size >>= 1;
+
+ if (lseek64(fd, ((off64_t) 512) * (off64_t) MD_NEW_SIZE_SECTORS(size), SEEK_SET) < 0) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ if (sb.md_magic != MD_SB_MAGIC) {
+ PyErr_SetString(PyExc_ValueError, "bad md magic on device");
+ return NULL;
+ }
+
+ return Py_BuildValue("i", sb.chunk_size / 1024);
+}
+
+static int get_bits(unsigned long long v) {
+ int b = 0;
+
+ if ( v & 0xffffffff00000000LLU ) { b += 32; v >>= 32; }
+ if ( v & 0xffff0000LLU ) { b += 16; v >>= 16; }
+ if ( v & 0xff00LLU ) { b += 8; v >>= 8; }
+ if ( v & 0xf0LLU ) { b += 4; v >>= 4; }
+ if ( v & 0xcLLU ) { b += 2; v >>= 2; }
+ if ( v & 0x2LLU ) b++;
+
+ return v ? b + 1 : b;
+}
+
+static PyObject * doDevSpaceFree(PyObject * s, PyObject * args) {
+ char * path;
+ struct statfs sb;
+ unsigned long long size;
+
+ if (!PyArg_ParseTuple(args, "s", &path)) return NULL;
+
+ if (statfs(path, &sb)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ /* Calculate a saturated addition to prevent oveflow. */
+ if ( get_bits(sb.f_bfree) + get_bits(sb.f_bsize) <= 64 )
+ size = (unsigned long long)sb.f_bfree * sb.f_bsize;
+ else
+ size = ~0LLU;
+
+ return PyLong_FromUnsignedLongLong(size>>20);
+}
+
+static PyObject * doLoadKeymap (PyObject * s, PyObject * args) {
+ char * keymap;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "s", &keymap)) return NULL;
+
+ ret = isysLoadKeymap (keymap);
+ if (ret) {
+ errno = -ret;
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doExt2Dirty(PyObject * s, PyObject * args) {
+ char * device;
+ ext2_filsys fsys;
+ int rc;
+ int clean;
+
+ if (!PyArg_ParseTuple(args, "s", &device)) return NULL;
+
+ rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager,
+ &fsys);
+ if (rc) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ clean = fsys->super->s_state & EXT2_VALID_FS;
+
+ ext2fs_close(fsys);
+
+ return Py_BuildValue("i", !clean);
+}
+static PyObject * doExt2HasJournal(PyObject * s, PyObject * args) {
+ char * device;
+ ext2_filsys fsys;
+ int rc;
+ int hasjournal;
+
+ if (!PyArg_ParseTuple(args, "s", &device)) return NULL;
+ rc = ext2fs_open(device, EXT2_FLAG_FORCE, 0, 0, unix_io_manager,
+ &fsys);
+ if (rc) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+
+ hasjournal = fsys->super->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+
+ ext2fs_close(fsys);
+
+ return Py_BuildValue("i", hasjournal);
+}
+
+static PyObject * doEjectCdrom(PyObject * s, PyObject * args) {
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "i", &fd)) return NULL;
+
+ /* Ask it to unlock the door and then eject the disc. There's really
+ * nothing to do if unlocking doesn't work, so just eject without
+ * worrying about it. -- pjones
+ */
+ ioctl(fd, CDROM_LOCKDOOR, 0);
+ if (ioctl(fd, CDROMEJECT, 1)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doVtActivate(PyObject * s, PyObject * args) {
+ int vtnum;
+
+ if (!PyArg_ParseTuple(args, "i", &vtnum)) return NULL;
+
+ if (ioctl(0, VT_ACTIVATE, vtnum)) {
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doisPseudoTTY(PyObject * s, PyObject * args) {
+ int fd;
+ struct stat sb;
+
+ if (!PyArg_ParseTuple(args, "i", &fd)) return NULL;
+ fstat(fd, &sb);
+
+ /* XXX close enough for now */
+ return Py_BuildValue("i", ((major(sb.st_rdev) >= 136) && (major(sb.st_rdev) <= 143)));
+}
+
+static PyObject * doisVioConsole(PyObject * s) {
+ return Py_BuildValue("i", isVioConsole());
+}
+
+static PyObject * doSync(PyObject * s, PyObject * args) {
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "", &fd)) return NULL;
+ sync();
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+int fileIsIso(const char * file);
+
+static PyObject * doisIsoImage(PyObject * s, PyObject * args) {
+ char * fn;
+ int rc;
+
+ if (!PyArg_ParseTuple(args, "s", &fn)) return NULL;
+
+ rc = fileIsIso(fn);
+
+ return Py_BuildValue("i", rc);
+}
+
+static PyObject * printObject (PyObject * o, PyObject * args) {
+ PyObject * obj;
+ char buf[256];
+
+ if (!PyArg_ParseTuple(args, "O", &obj))
+ return NULL;
+
+ snprintf(buf, 256, "<%s object at %lx>", obj->ob_type->tp_name,
+ (long) obj);
+
+ return PyString_FromString(buf);
+}
+
+static PyObject *
+py_bind_textdomain_codeset(PyObject * o, PyObject * args) {
+ char *domain, *codeset, *ret;
+
+ if (!PyArg_ParseTuple(args, "ss", &domain, &codeset))
+ return NULL;
+
+ ret = bind_textdomain_codeset(domain, codeset);
+
+ if (ret)
+ return PyString_FromString(ret);
+
+ PyErr_SetFromErrno(PyExc_SystemError);
+ return NULL;
+}
+
+static PyObject * doSegvHandler(PyObject *s, PyObject *args) {
+ void *array[20];
+ size_t size;
+ char **strings;
+ size_t i;
+
+ signal(SIGSEGV, SIG_DFL); /* back to default */
+
+ size = backtrace (array, 20);
+ strings = backtrace_symbols (array, size);
+
+ printf ("Anaconda received SIGSEGV!. Backtrace:\n");
+ for (i = 0; i < size; i++)
+ printf ("%s\n", strings[i]);
+
+ free (strings);
+ exit(1);
+}
+
+static PyObject * doAuditDaemon(PyObject *s) {
+ audit_daemonize();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doGetBlkidData(PyObject * s, PyObject * args) {
+ char * dev, * key;
+ blkid_cache cache;
+ blkid_dev bdev = NULL;
+ blkid_tag_iterate titer;
+ const char * type, * data;
+
+ if (!PyArg_ParseTuple(args, "ss", &dev, &key)) return NULL;
+
+ blkid_get_cache(&cache, NULL);
+
+ bdev = blkid_get_dev(cache, dev, BLKID_DEV_NORMAL);
+ if (bdev == NULL)
+ goto out;
+ titer = blkid_tag_iterate_begin(bdev);
+ while (blkid_tag_next(titer, &type, &data) >= 0) {
+ if (!strcmp(type, key)) {
+ blkid_tag_iterate_end(titer);
+ return Py_BuildValue("s", data);
+ }
+ }
+ blkid_tag_iterate_end(titer);
+
+ out:
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyObject * doIsCapsLockEnabled(PyObject * s, PyObject * args) {
+ Display *d = NULL;
+ XkbStateRec state;
+
+ if ((d = XOpenDisplay(NULL)) == NULL) {
+ return NULL;
+ }
+
+ memset(&state, 0, sizeof(state));
+ XkbGetState(d, XkbUseCoreKbd, &state);
+
+ if (XCloseDisplay(d)) {
+ return NULL;
+ }
+
+ return PyBool_FromLong(state.locked_mods & LockMask);
+}
+
+static PyObject * doGetLinkStatus(PyObject * s, PyObject * args) {
+ char *dev = NULL;
+
+ if (!PyArg_ParseTuple(args, "s", &dev)) {
+ return NULL;
+ }
+
+ if (get_link_status(dev) == 1) {
+ return PyBool_FromLong(1);
+ }
+
+ return PyBool_FromLong(0);
+}
+
+static PyObject * doGetAnacondaVersion(PyObject * s, PyObject * args) {
+ return Py_BuildValue("s", VERSION);
+}
+
+static PyObject * doInitLog(PyObject * s) {
+ openLog();
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/isys/isys.h b/isys/isys.h
new file mode 100644
index 0000000..265dc77
--- /dev/null
+++ b/isys/isys.h
@@ -0,0 +1,38 @@
+/*
+ * isys.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef H_ISYS
+#define H_ISYS
+
+#define MIN_RAM 131072
+#define MIN_GUI_RAM 393216
+#define EARLY_SWAP_RAM 524288
+
+#define OUTPUT_TERMINAL "/dev/tty5"
+
+int insmod(char * modName, char * path, char ** args);
+int rmmod(char * modName);
+
+/* returns 0 for true, !0 for false */
+int fileIsIso(const char * file);
+
+/* returns 1 if on an iSeries vio console, 0 otherwise */
+int isVioConsole(void);
+
+#endif
diff --git a/isys/isys.py b/isys/isys.py
new file mode 100755
index 0000000..32632ee
--- /dev/null
+++ b/isys/isys.py
@@ -0,0 +1,583 @@
+#
+# isys.py - installer utility functions and glue for C module
+#
+# Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author(s): Matt Wilson <msw@redhat.com>
+# Erik Troan <ewt@redhat.com>
+# Jeremy Katz <katzj@redhat.com>
+#
+
+import _isys
+import string
+import os
+import os.path
+import socket
+import stat
+import posix
+import sys
+import iutil
+import warnings
+import resource
+import re
+import struct
+import block
+import dbus
+import selinux
+
+import logging
+log = logging.getLogger("anaconda")
+
+NM_SERVICE = "org.freedesktop.NetworkManager"
+NM_MANAGER_PATH = "/org/freedesktop/NetworkManager"
+NM_MANAGER_IFACE = "org.freedesktop.NetworkManager"
+NM_ACTIVE_CONNECTION_IFACE = "org.freedesktop.NetworkManager.Connection.Active"
+NM_CONNECTION_IFACE = "org.freedesktop.NetworkManagerSettings.Connection"
+NM_DEVICE_IFACE = "org.freedesktop.NetworkManager.Device"
+NM_IP4CONFIG_IFACE = "org.freedesktop.NetworkManager.IP4Config"
+NM_DEVICE_WIRED_IFACE = "org.freedesktop.NetworkManager.Device.Wired"
+NM_DEVICE_WIRELESS_IFACE = "org.freedesktop.NetworkManager.Device.Wireless"
+NM_DEVICE_BLUETOOTH_IFACE = "org.freedesktop.NetworkManager.Device.Bluetooth"
+NM_DEVICE_OLPCMESH_IFACE = "org.freedesktop.NetworkManager.Device.OlpcMesh"
+
+NM_STATE_UNKNOWN = 0
+NM_STATE_ASLEEP = 1
+NM_STATE_CONNECTING = 2
+NM_STATE_CONNECTED = 3
+NM_STATE_DISCONNECTED = 4
+
+DBUS_PROPS_IFACE = "org.freedesktop.DBus.Properties"
+
+mountCount = {}
+
+MIN_RAM = _isys.MIN_RAM
+MIN_GUI_RAM = _isys.MIN_GUI_RAM
+EARLY_SWAP_RAM = _isys.EARLY_SWAP_RAM
+
+## Get the amount of free space available under a directory path.
+# @param path The directory path to check.
+# @return The amount of free space available, in
+def pathSpaceAvailable(path):
+ return _isys.devSpaceFree(path)
+
+## Set up an already existing device node to be used as a loopback device.
+# @param device The full path to a device node to set up as a loopback device.
+# @param file The file to mount as loopback on device.
+# @param readOnly Should this loopback device be used read-only?
+def losetup(device, file, readOnly = 0):
+ # FIXME: implement this as a storage.devices.Device subclass
+ if readOnly:
+ mode = os.O_RDONLY
+ else:
+ mode = os.O_RDWR
+ targ = os.open(file, mode)
+ loop = os.open(device, mode)
+ try:
+ _isys.losetup(loop, targ, file)
+ finally:
+ os.close(loop)
+ os.close(targ)
+
+def lochangefd(device, file):
+ # FIXME: implement this as a storage.devices.Device subclass
+ loop = os.open(device, os.O_RDONLY)
+ targ = os.open(file, os.O_RDONLY)
+ try:
+ _isys.lochangefd(loop, targ)
+ finally:
+ os.close(loop)
+ os.close(targ)
+
+## Disable a previously setup loopback device.
+# @param device The full path to an existing loopback device node.
+def unlosetup(device):
+ # FIXME: implement this as a storage.devices.Device subclass
+ loop = os.open(device, os.O_RDONLY)
+ try:
+ _isys.unlosetup(loop)
+ finally:
+ os.close(loop)
+
+## Mount a filesystem, similar to the mount system call.
+# @param device The device to mount. If bindMount is True, this should be an
+# already mounted directory. Otherwise, it should be a device
+# name.
+# @param location The path to mount device on.
+# @param fstype The filesystem type on device. This can be disk filesystems
+# such as vfat or ext3, or pseudo filesystems such as proc or
+# selinuxfs.
+# @param readOnly Should this filesystem be mounted readonly?
+# @param bindMount Is this a bind mount? (see the mount(8) man page)
+# @param remount Are we mounting an already mounted filesystem?
+# @return The return value from the mount system call.
+def mount(device, location, fstype = "ext2", readOnly = False,
+ bindMount = False, remount = False, options = None):
+ flags = None
+ location = os.path.normpath(location)
+ if not options:
+ opts = ["defaults"]
+ else:
+ opts = options.split(",")
+
+ # We don't need to create device nodes for devices that start with '/'
+ # (like '/usbdevfs') and also some special fake devices like 'proc'.
+ # First try to make a device node and if that fails, assume we can
+ # mount without making a device node. If that still fails, the caller
+ # will have to deal with the exception.
+ # We note whether or not we created a node so we can clean up later.
+
+ if mountCount.has_key(location) and mountCount[location] > 0:
+ mountCount[location] = mountCount[location] + 1
+ return
+
+ if readOnly or bindMount or remount:
+ if readOnly:
+ opts.append("ro")
+ if bindMount:
+ opts.append("bind")
+ if remount:
+ opts.append("remount")
+
+ flags = ",".join(opts)
+
+ log.debug("isys.py:mount()- going to mount %s on %s as %s with options %s" %(device, location, fstype, flags))
+ rc = _isys.mount(fstype, device, location, flags)
+
+ if not rc:
+ mountCount[location] = 1
+
+ return rc
+
+## Unmount a filesystem, similar to the umount system call.
+# @param what The directory to be unmounted. This does not need to be the
+# absolute path.
+# @param removeDir Should the mount point be removed after being unmounted?
+# @return The return value from the umount system call.
+def umount(what, removeDir = True):
+ what = os.path.normpath(what)
+
+ if not os.path.isdir(what):
+ raise ValueError, "isys.umount() can only umount by mount point"
+
+ if mountCount.has_key(what) and mountCount[what] > 1:
+ mountCount[what] = mountCount[what] - 1
+ return
+
+ log.debug("isys.py:umount()- going to unmount %s, removeDir = %s" % (what, removeDir))
+ rc = _isys.umount(what)
+
+ if removeDir and os.path.isdir(what):
+ try:
+ os.rmdir(what)
+ except:
+ pass
+
+ if not rc and mountCount.has_key(what):
+ del mountCount[what]
+
+ return rc
+
+## Disable swap.
+# @param path The full path of the swap device to disable.
+def swapoff (path):
+ return _isys.swapoff (path)
+
+## Enable swap.
+# @param path The full path of the swap device to enable.
+def swapon (path):
+ return _isys.swapon (path)
+
+## Load a keyboard layout for text mode installs.
+# @param keymap The keyboard layout to load. This must be one of the values
+# from rhpl.KeyboardModels.
+def loadKeymap(keymap):
+ return _isys.loadKeymap (keymap)
+
+def resetResolv():
+ return _isys.resetresolv()
+
+def readFSUuid(device):
+ if not os.path.exists(device):
+ device = "/dev/%s" % device
+
+ label = _isys.getblkid(device, "UUID")
+ return label
+
+def readFSLabel(device):
+ if not os.path.exists(device):
+ device = "/dev/%s" % device
+
+ label = _isys.getblkid(device, "LABEL")
+ return label
+
+def readFSType(device):
+ if not os.path.exists(device):
+ device = "/dev/%s" % device
+
+ fstype = _isys.getblkid(device, "TYPE")
+ if fstype is None:
+ # FIXME: libblkid doesn't show physical volumes as having a filesystem
+ # so let's sniff for that.(#409321)
+ try:
+ fd = os.open(device, os.O_RDONLY)
+ buf = os.read(fd, 2048)
+ except:
+ return fstype
+ finally:
+ try:
+ os.close(fd)
+ except:
+ pass
+
+ if buf.startswith("HM"):
+ return "physical volume (LVM)"
+ for sec in range(0, 4):
+ off = (sec * 512) + 24
+ if len(buf) < off:
+ continue
+ if buf[off:].startswith("LVM2"):
+ return "physical volume (LVM)"
+ elif fstype == "lvm2pv":
+ return "physical volume (LVM)"
+ return fstype
+
+def ext2IsDirty(device):
+ label = _isys.e2dirty(device)
+ return label
+
+def ext2HasJournal(device):
+ hasjournal = _isys.e2hasjournal(device)
+ return hasjournal
+
+def modulesWithPaths():
+ mods = []
+ for modline in open("/proc/modules", "r"):
+ modName = modline.split(" ", 1)[0]
+ modInfo = iutil.execWithCapture("modinfo",
+ ["-F", "filename", modName]).splitlines()
+ modPaths = [ line.strip() for line in modInfo if line!="" ]
+ mods.extend(modPaths)
+ return mods
+
+def driveUsesModule(device, modules):
+ """Returns true if a drive is using a prticular module. Only works
+ for SCSI devices right now."""
+
+ if not isinstance(modules, ().__class__) and not \
+ isinstance(modules, [].__class__):
+ modules = [modules]
+
+ if device[:2] == "hd":
+ return False
+ rc = False
+ if os.access("/tmp/scsidisks", os.R_OK):
+ sdlist=open("/tmp/scsidisks", "r")
+ sdlines = sdlist.readlines()
+ sdlist.close()
+ for l in sdlines:
+ try:
+ # each line has format of: <device> <module>
+ (sddev, sdmod) = string.split(l)
+
+ if sddev == device:
+ if sdmod in modules:
+ rc = True
+ break
+ except:
+ pass
+ return rc
+
+def vtActivate (num):
+ if iutil.isS390():
+ return
+ _isys.vtActivate (num)
+
+def isPseudoTTY (fd):
+ return _isys.isPseudoTTY (fd)
+
+## Flush filesystem buffers.
+def sync ():
+ return _isys.sync ()
+
+## Determine if a file is an ISO image or not.
+# @param file The full path to a file to check.
+# @return True if ISO image, False otherwise.
+def isIsoImage(file):
+ return _isys.isisoimage(file)
+
+# Return number of network devices
+def getNetworkDeviceCount():
+ bus = dbus.SystemBus()
+ nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH)
+ devlist = nm.get_dbus_method("GetDevices")()
+ return len(devlist)
+
+# Get a D-Bus interface for the specified device's (e.g., eth0) properties.
+# If dev=None, return a hash of the form 'hash[dev] = props_iface' that
+# contains all device properties for all interfaces that NetworkManager knows
+# about.
+def getDeviceProperties(dev=None):
+ bus = dbus.SystemBus()
+ nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH)
+ devlist = nm.get_dbus_method("GetDevices")()
+ all = {}
+
+ for path in devlist:
+ device = bus.get_object(NM_SERVICE, path)
+ device_props_iface = dbus.Interface(device, DBUS_PROPS_IFACE)
+
+ device_interface = str(device_props_iface.Get(NM_DEVICE_IFACE, "Interface"))
+
+ if dev is None:
+ all[device_interface] = device_props_iface
+ elif device_interface == dev:
+ return device_props_iface
+
+ if dev is None:
+ return all
+ else:
+ return None
+
+# Return true if method is currently 'dhcp' for the specified device.
+def isDeviceDHCP(dev=None):
+ if dev is None:
+ return False
+
+ bus = dbus.SystemBus()
+ nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH)
+ nm_props_iface = dbus.Interface(nm, DBUS_PROPS_IFACE)
+ active_connections = nm_props_iface.Get(NM_MANAGER_IFACE, "ActiveConnections")
+
+ for path in active_connections:
+ active = bus.get_object(NM_SERVICE, path)
+ active_props_iface = dbus.Interface(active, DBUS_PROPS_IFACE)
+
+ active_service_name = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "ServiceName")
+ active_path = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "Connection")
+ active_devices = active_props_iface.Get(NM_ACTIVE_CONNECTION_IFACE, "Devices")
+
+ device = bus.get_object(NM_SERVICE, active_devices[0])
+ device_props_iface = dbus.Interface(device, DBUS_PROPS_IFACE)
+ iface = device_props_iface.Get(NM_DEVICE_IFACE, "Interface")
+
+ if iface != dev:
+ continue
+
+ connection = bus.get_object(active_service_name, active_path)
+ connection_iface = dbus.Interface(connection, NM_CONNECTION_IFACE)
+ settings = connection_iface.GetSettings()
+
+ ip4_setting = settings.get('ipv4')
+ if not ip4_setting or not ip4_setting['method'] or ip4_setting['method'] == 'auto':
+ return True
+
+ return False
+
+# Get the MAC address for a network device.
+def getMacAddress(dev):
+ if dev == '' or dev is None:
+ return False
+
+ device_props_iface = getDeviceProperties(dev=dev)
+ if device_props_iface is None:
+ return None
+
+ device_macaddr = None
+ dev_type = int(device_props_iface.Get(NM_DEVICE_IFACE, "DeviceType"))
+ device_type_map = {
+ 0: None, # unknown
+ 1: [NM_DEVICE_WIRED_IFACE],
+ 2: [NM_DEVICE_WIRELESS_IFACE],
+ #3: [NM_DEVICE_BLUETOOTH_IFACE], # NM_DEVICE_TYPE_GSM, try everything
+ #4: [NM_DEVICE_BLUETOOTH_IFACE], # NM_DEVICE_TYPE_CDMA, try everything
+ }
+ device_types = device_type_map.get(dev_type)
+ if device_types is None:
+ device_types = [NM_DEVICE_WIRED_IFACE, NM_DEVICE_WIRELESS_IFACE,
+ NM_DEVICE_OLPCMESH_IFACE, NM_DEVICE_BLUETOOTH_IFACE]
+ for device_type in device_types:
+ # try bluetooth
+ try:
+ device_macaddr = device_props_iface.Get(device_type, "HwAddress").upper()
+ break
+ except dbus.exceptions.DBusException:
+ pass
+
+ if (device_macaddr is None) and (dev_type in (1, 2)):
+ # this is wtf
+ raise dbus.exceptions.DBusException("cannot determine hwaddr")
+
+ return device_macaddr
+
+# Get a description string for a network device (e.g., eth0)
+def getNetDevDesc(dev):
+ from baseudev import udev_get_device
+ desc = "Network Interface"
+
+ if dev == '' or dev is None:
+ return desc
+
+ bus = dbus.SystemBus()
+ nm = bus.get_object(NM_SERVICE, NM_MANAGER_PATH)
+ devlist = nm.get_dbus_method("GetDevices")()
+
+ for path in devlist:
+ device = bus.get_object(NM_SERVICE, path)
+ device_iface = dbus.Interface(device, DBUS_PROPS_IFACE)
+ device_props = device_iface.get_dbus_method("GetAll")(NM_DEVICE_IFACE)
+
+ if dev == device_props['Interface']:
+ # This is the sysfs path (for now).
+ udev_path = device_props['Udi']
+ dev = udev_get_device(udev_path[4:])
+
+ if dev is None:
+ log.debug("weird, we have a None dev with path %s" % path)
+ elif dev.has_key("ID_VENDOR_ENC") and dev.has_key("ID_MODEL_ENC"):
+ desc = "%s %s" % (dev["ID_VENDOR_ENC"], dev["ID_MODEL_ENC"])
+ elif dev.has_key("ID_VENDOR_FROM_DATABASE") and dev.has_key("ID_MODEL_FROM_DATABASE"):
+ desc = "%s %s" % (dev["ID_VENDOR_FROM_DATABASE"], dev["ID_MODEL_FROM_DATABASE"])
+
+ return desc
+
+ return desc
+
+# Determine if a network device is a wireless device.
+def isWireless(dev):
+ if dev == '' or dev is None:
+ return False
+
+ device_props_iface = getDeviceProperties(dev=dev)
+ if device_props_iface is None:
+ return None
+
+ device_type = int(device_props_iface.Get(NM_DEVICE_IFACE, "DeviceType"))
+
+ # from include/NetworkManager.h in the NM source code
+ # 0 == NM_DEVICE_TYPE_UNKNOWN
+ # 1 == NM_DEVICE_TYPE_ETHERNET
+ # 2 == NM_DEVICE_TYPE_WIFI
+ # 3 == NM_DEVICE_TYPE_GSM
+ # 4 == NM_DEVICE_TYPE_CDMA
+ if device_type == 2:
+ return True
+ else:
+ return False
+
+# Get the IP address for a network device.
+def getIPAddress(dev):
+ if dev == '' or dev is None:
+ return None
+
+ device_props_iface = getDeviceProperties(dev=dev)
+ if device_props_iface is None:
+ return None
+
+ # XXX: add support for IPv6 addresses when NM can do that
+ device_ip4addr = device_props_iface.Get(NM_DEVICE_IFACE, "Ip4Address")
+
+ try:
+ tmp = struct.pack('I', device_ip4addr)
+ address = socket.inet_ntop(socket.AF_INET, tmp)
+ except ValueError, e:
+ return None
+
+ return address
+
+## Get the correct context for a file from loaded policy.
+# @param fn The filename to query.
+def matchPathContext(fn):
+ con = None
+ try:
+ con = selinux.matchpathcon(os.path.normpath(fn), 0)[1]
+ except OSError as e:
+ log.info("failed to get default SELinux context for %s: %s" % (fn, e))
+ return con
+
+## Set the SELinux file context of a file
+# @param fn The filename to fix.
+# @param con The context to use.
+# @param instroot An optional root filesystem to look under for fn.
+def setFileContext(fn, con, instroot = '/'):
+ full_path = os.path.normpath("%s/%s" % (instroot, fn))
+ rc = False
+ if con is not None and os.access(full_path, os.F_OK):
+ try:
+ rc = (selinux.lsetfilecon(full_path, con) == 0)
+ except OSError as e:
+ log.info("failed to set SELinux context for %s: %s" % (full_path, e))
+ return rc
+
+## Restore the SELinux file context of a file to its default.
+# @param fn The filename to fix.
+# @param instroot An optional root filesystem to look under for fn.
+def resetFileContext(fn, instroot = '/'):
+ con = matchPathContext(fn)
+ if con:
+ if setFileContext(fn, con, instroot):
+ return con
+ return None
+
+def prefix2netmask(prefix):
+ return _isys.prefix2netmask(prefix)
+
+def netmask2prefix (netmask):
+ prefix = 0
+
+ while prefix < 33:
+ if (prefix2netmask(prefix) == netmask):
+ return prefix
+
+ prefix += 1
+
+ return prefix
+
+isPAE = None
+def isPaeAvailable():
+ global isPAE
+ if isPAE is not None:
+ return isPAE
+
+ isPAE = False
+ if not iutil.isX86():
+ return isPAE
+
+ f = open("/proc/cpuinfo", "r")
+ lines = f.readlines()
+ f.close()
+
+ for line in lines:
+ if line.startswith("flags") and line.find("pae") != -1:
+ isPAE = True
+ break
+
+ return isPAE
+
+def getLinkStatus(dev):
+ return _isys.getLinkStatus(dev)
+
+def getAnacondaVersion():
+ return _isys.getAnacondaVersion()
+
+auditDaemon = _isys.auditdaemon
+
+handleSegv = _isys.handleSegv
+
+printObject = _isys.printObject
+bind_textdomain_codeset = _isys.bind_textdomain_codeset
+isVioConsole = _isys.isVioConsole
+initLog = _isys.initLog
diff --git a/isys/lang.c b/isys/lang.c
new file mode 100644
index 0000000..b6e2a36
--- /dev/null
+++ b/isys/lang.c
@@ -0,0 +1,207 @@
+/*
+ * lang.c
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <linux/keyboard.h>
+#ifdef NR_KEYS
+#undef NR_KEYS
+#define NR_KEYS 128
+#endif
+
+#include "linux/kd.h"
+
+#include "cpio.h"
+#include "isys.h"
+#include "lang.h"
+#include "stubs.h"
+
+int isysLoadFont(void) {
+ unsigned char font[65536];
+ struct console_font_op cfo;
+ unsigned short map[E_TABSZ];
+ struct unimapdesc d;
+ struct unimapinit u;
+ struct unipair desc[2048];
+ gzFile stream;
+ int rc;
+
+#if defined (__s390__) || defined (__s390x__)
+ return 0;
+#endif
+ stream = gunzip_open("/etc/screenfont.gz");
+ if (!stream)
+ return -EACCES;
+
+ gunzip_read(stream, &cfo, sizeof(cfo));
+ gunzip_read(stream, font, sizeof(font));
+ gunzip_read(stream, map, sizeof(map));
+ gunzip_read(stream, &d.entry_ct, sizeof(d.entry_ct));
+ d.entries = desc;
+ gunzip_read(stream, desc, d.entry_ct * sizeof(desc[0]));
+ gunzip_close(stream);
+
+ cfo.data = font;
+ cfo.op = KD_FONT_OP_SET;
+
+ rc = ioctl(1, KDFONTOP, &cfo);
+ if (rc) return rc;
+ rc = ioctl(1, PIO_UNIMAPCLR, &u);
+ if (rc) return rc;
+ rc = ioctl(1, PIO_UNIMAP, &d);
+ if (rc) return rc;
+ rc = ioctl(1, PIO_UNISCRNMAP, map);
+ if (rc) return rc;
+ /* activate the font map */
+ fprintf(stderr, "\033(K");
+ return 0;
+}
+
+int isysSetUnicodeKeymap(void) {
+ int console;
+
+#if defined (__s390__) || defined (__s390x__)
+ return 0;
+#endif
+ console = open("/dev/console", O_RDWR);
+ if (console < 0)
+ return -EACCES;
+
+ /* place keyboard in unicode mode */
+ ioctl(console, KDSKBMODE, K_UNICODE);
+ close(console);
+ return 0;
+}
+
+/* the file pointer must be at the beginning of the section already! */
+int loadKeymap(gzFile stream) {
+ int console;
+ int kmap, key;
+ struct kbentry entry;
+ int keymaps[MAX_NR_KEYMAPS];
+ int count = 0;
+ unsigned int magic;
+ short keymap[NR_KEYS];
+ struct stat sb;
+
+#if defined (__s390__) || defined (__s390x__)
+ return 0;
+#endif
+ if (isVioConsole())
+ return 0;
+
+ /* assume that if we're already on a pty loading a keymap is silly */
+ fstat(0, &sb);
+ if (major(sb.st_rdev) == 3 || major(sb.st_rdev) == 136)
+ return 0;
+
+ if (gunzip_read(stream, &magic, sizeof(magic)) != sizeof(magic))
+ return -EIO;
+
+ if (magic != KMAP_MAGIC) return -EINVAL;
+
+ if (gunzip_read(stream, keymaps, sizeof(keymaps)) != sizeof(keymaps))
+ return -EINVAL;
+
+ console = open("/dev/tty0", O_RDWR);
+ if (console < 0)
+ return -EACCES;
+
+ for (kmap = 0; kmap < MAX_NR_KEYMAPS; kmap++) {
+ if (!keymaps[kmap]) continue;
+
+ if (gunzip_read(stream, keymap, sizeof(keymap)) != sizeof(keymap)) {
+ close(console);
+ return -EIO;
+ }
+
+ count++;
+ for (key = 0; key < NR_KEYS; key++) {
+ entry.kb_index = key;
+ entry.kb_table = kmap;
+ entry.kb_value = keymap[key];
+ if (KTYP(entry.kb_value) != KT_SPEC) {
+ if (ioctl(console, KDSKBENT, &entry)) {
+ int ret = errno;
+ close(console);
+ return ret;
+ }
+ }
+ }
+ }
+ close(console);
+ return 0;
+}
+
+int isysLoadKeymap(char * keymap) {
+ int num = -1;
+ int rc;
+ gzFile f;
+ struct kmapHeader hdr;
+ struct kmapInfo * infoTable;
+ char buf[16384]; /* I hope this is big enough */
+ int i;
+
+ f = gunzip_open("/etc/keymaps.gz");
+ if (!f) return -EACCES;
+
+ if (gunzip_read(f, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ gunzip_close(f);
+ return -EINVAL;
+ }
+
+ i = hdr.numEntries * sizeof(*infoTable);
+ infoTable = alloca(i);
+ if (gunzip_read(f, infoTable, i) != i) {
+ gunzip_close(f);
+ return -EIO;
+ }
+
+ for (i = 0; i < hdr.numEntries; i++)
+ if (!strcmp(infoTable[i].name, keymap)) {
+ num = i;
+ break;
+ }
+
+ if (num == -1) {
+ gunzip_close(f);
+ return -ENOENT;
+ }
+
+ for (i = 0; i < num; i++) {
+ if (gunzip_read(f, buf, infoTable[i].size) != infoTable[i].size) {
+ gunzip_close(f);
+ return -EIO;
+ }
+ }
+
+ rc = loadKeymap(f);
+
+ gunzip_close(f);
+
+ return rc;
+}
diff --git a/isys/lang.h b/isys/lang.h
new file mode 100644
index 0000000..a08adbd
--- /dev/null
+++ b/isys/lang.h
@@ -0,0 +1,44 @@
+/*
+ * lang.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef ISYS_LANG_H
+#define ISYS_LANG_H
+
+#include "stubs.h"
+
+/* define ask johnsonm@redhat.com where this came from */
+#define KMAP_MAGIC 0x8B39C07F
+#define KMAP_NAMELEN 40 /* including '\0' */
+
+struct kmapHeader {
+ int magic;
+ int numEntries;
+};
+
+struct kmapInfo {
+ int size;
+ char name[KMAP_NAMELEN];
+};
+
+int loadKeymap(gzFile stream);
+int isysLoadFont(void);
+int isysLoadKeymap(char * keymap);
+int isysSetUnicodeKeymap(void);
+
+#endif
diff --git a/isys/linkdetect.c b/isys/linkdetect.c
new file mode 100644
index 0000000..f97a291
--- /dev/null
+++ b/isys/linkdetect.c
@@ -0,0 +1,202 @@
+/*
+ * linkdetect.c - simple link detection
+ *
+ * pulls code from mii-tool.c in net-toools and ethtool so
+ * that we can do everything that jgarzik says we should check
+ *
+ * Copyright (C) 2002, 2003 Red Hat, Inc. All rights reserved.
+ * Portions Copyright (C) 2000 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <net/if.h>
+
+#include <linux/sockios.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include "ethtool.h"
+
+static struct ifreq ifr;
+
+static int mdio_read(int skfd, uint16_t location)
+{
+ struct mii_ioctl_data mii;
+
+ memset(&mii, 0, sizeof(mii));
+ memcpy(&mii, &ifr.ifr_data, sizeof(mii));
+ mii.reg_num = location;
+ memcpy(&ifr.ifr_data, &mii, sizeof(mii));
+
+ if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
+#ifdef STANDALONE
+ fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+#endif
+ return -1;
+ } else {
+ memcpy(&mii, &ifr.ifr_data, sizeof(mii));
+ }
+
+ return mii.val_out;
+}
+
+/* we don't need writing right now */
+#if 0
+static void mdio_write(int skfd, int location, int value)
+{
+ struct mii_ioctl_data *mii = (struct mii_ioctl_data *)&ifr.ifr_data;
+ mii->reg_num = location;
+ mii->val_in = value;
+ if (ioctl(skfd, SIOCSMIIREG, &ifr) < 0) {
+#ifdef STANDALONE
+ fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+#endif
+ }
+}
+#endif
+
+
+
+static int get_mii_link_status(int sock) {
+ int i, mii_val[32];
+
+ if (ioctl(sock, SIOCGMIIPHY, &ifr) < 0) {
+ if (errno != ENODEV)
+#ifdef STANDALONE
+ fprintf(stderr, "SIOCGMIIPHY on '%s' failed: %s\n",
+ ifr.ifr_name, strerror(errno));
+#endif
+ return -1;
+ }
+
+ /* Some bits in the BMSR are latched, but we can't rely on being
+ the only reader, so only the current values are meaningful */
+ mdio_read(sock, MII_BMSR);
+ for (i = 0; i < 8; i++)
+ mii_val[i] = mdio_read(sock, i);
+
+ if (mii_val[MII_BMCR] == 0xffff) {
+#ifdef STANDALONE
+ fprintf(stderr, " No MII transceiver present!.\n");
+#endif
+ return -1;
+ }
+
+ if (mii_val[MII_BMSR] & BMSR_LSTATUS)
+ return 1;
+ else
+ return 0;
+}
+
+static int get_ethtool_link_status(int sock) {
+ struct ethtool_value edata;
+ int rc;
+
+ edata.cmd = ETHTOOL_GLINK;
+ ifr.ifr_data = (caddr_t)&edata;
+ rc = ioctl(sock, SIOCETHTOOL, &ifr);
+ if (rc == 0) {
+ return edata.data;
+ } else if (errno != EOPNOTSUPP) {
+#ifdef STANDALONE
+ fprintf(stderr, "Cannot get link status (%d): %s\n", errno, strerror(errno));
+#endif
+ }
+
+ return -1;
+}
+
+
+
+int get_link_status(char * devname) {
+ int sock, rc;
+
+ if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+#ifdef STANDALONE
+ fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+#endif
+ return -1;
+ }
+
+ /* make sure interface is up and activated */
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+
+ if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
+ return -1;
+ }
+
+ ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
+
+ if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
+ return -1;
+ }
+
+ /* Setup our control structures. */
+ memset(&ifr, 0, sizeof(ifr));
+ strcpy(ifr.ifr_name, devname);
+
+ /* check for link with both ethtool and mii registers. ethtool is
+ * supposed to be the One True Way (tm), but it seems to not work
+ * with much yet :/ */
+
+ rc = get_ethtool_link_status(sock);
+#ifdef STANDALONE
+ printf("ethtool link status of %s is: %d\n", devname, rc);
+#endif
+ if (rc == 1) {
+ close(sock);
+ return 1;
+ }
+
+ rc = get_mii_link_status(sock);
+#ifdef STANDALONE
+ printf("MII link status of %s is: %d\n", devname, rc);
+#endif
+ if (rc == 1) {
+ close(sock);
+ return 1;
+ }
+
+ return 0;
+}
+
+#ifdef STANDALONE
+/* hooray for stupid test programs! */
+int main(int argc, char **argv) {
+ char * dev;
+
+ if (argc >= 2)
+ dev = argv[1];
+ else
+ dev = strdup("eth0");
+
+ printf("link status of %s is %d\n", dev, get_link_status(dev));
+ return 0;
+}
+#endif
diff --git a/isys/log.c b/isys/log.c
new file mode 100644
index 0000000..da39c7b
--- /dev/null
+++ b/isys/log.c
@@ -0,0 +1,224 @@
+/*
+ * log.c - logging functionality
+ *
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Erik Troan <ewt@redhat.com>
+ * Matt Wilson <msw@redhat.com>
+ * Michael Fulbright <msf@redhat.com>
+ * Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <syslog.h>
+
+#include "log.h"
+
+static FILE * main_log_tty = NULL;
+static FILE * main_log_file = NULL;
+static FILE * program_log_file = NULL;
+static int minLevel = INFO;
+static const char * main_tag = "loader";
+static const char * program_tag = "program";
+static const int syslog_facility = LOG_LOCAL0;
+
+/* maps our loglevel to syslog loglevel */
+static int mapLogLevel(int level)
+{
+ switch (level) {
+ case DEBUGLVL:
+ return LOG_DEBUG;
+ case INFO:
+ return LOG_INFO;
+ case WARNING:
+ return LOG_WARNING;
+ case CRITICAL:
+ return LOG_CRIT;
+ case ERROR:
+ default:
+ /* if someone called us with an invalid level value, log it as an error
+ too. */
+ return LOG_ERR;
+ }
+}
+
+static void printLogHeader(int level, const char *tag, FILE *outfile) {
+ struct timeval current_time;
+ struct tm *t;
+ int msecs;
+
+ gettimeofday(&current_time, NULL);
+ t = gmtime(&current_time.tv_sec);
+ msecs = current_time.tv_usec / 1000;
+ switch (level) {
+ case DEBUGLVL:
+ fprintf (outfile, "%02d:%02d:%02d,%03d DEBUG %s: ", t->tm_hour,
+ t->tm_min, t->tm_sec, msecs, tag);
+ break;
+
+ case INFO:
+ fprintf (outfile, "%02d:%02d:%02d,%03d INFO %s: ", t->tm_hour,
+ t->tm_min, t->tm_sec, msecs, tag);
+ break;
+
+ case WARNING:
+ fprintf (outfile, "%02d:%02d:%02d,%03d WARNING %s: ", t->tm_hour,
+ t->tm_min, t->tm_sec, msecs, tag);
+ break;
+
+ case ERROR:
+ fprintf (outfile, "%02d:%02d:%02d,%03d ERROR %s: ", t->tm_hour,
+ t->tm_min, t->tm_sec, msecs, tag);
+ break;
+
+ case CRITICAL:
+ fprintf (outfile, "%02d:%02d:%02d,%03d CRITICAL %s: ", t->tm_hour,
+ t->tm_min, t->tm_sec, msecs, tag);
+ break;
+ }
+}
+
+static void printLogMessage(int level, const char *tag, FILE *outfile, const char *s, va_list ap)
+{
+ printLogHeader(level, tag, outfile);
+
+ va_list apc;
+ va_copy(apc, ap);
+ vfprintf(outfile, s, apc);
+ va_end(apc);
+
+ fprintf(outfile, "\n");
+ fflush(outfile);
+}
+
+static void retagSyslog(const char* new_tag)
+{
+ closelog();
+ openlog(new_tag, 0, syslog_facility);
+}
+
+void logMessageV(enum logger_t logger, int level, const char * s, va_list ap) {
+ FILE *log_tty = main_log_tty;
+ FILE *log_file = main_log_file;
+ const char *tag = main_tag;
+ if (logger == PROGRAM_LOG) {
+ /* tty output is done directly for programs */
+ log_tty = NULL;
+ log_file = program_log_file;
+ tag = program_tag;
+ /* close and reopen syslog so we get the tagging right */
+ retagSyslog(tag);
+ }
+
+ va_list apc;
+ /* Log everything into syslog */
+ va_copy(apc, ap);
+ vsyslog(mapLogLevel(level), s, apc);
+ va_end(apc);
+
+ /* Only log to the screen things that are above the minimum level. */
+ if (main_log_tty && level >= minLevel && log_tty) {
+ printLogMessage(level, tag, log_tty, s, ap);
+ }
+
+ /* But log everything to the file. */
+ if (main_log_file) {
+ printLogMessage(level, tag, log_file, s, ap);
+ }
+
+ /* change the syslog tag back to the default again */
+ if (logger == PROGRAM_LOG)
+ retagSyslog(main_tag);
+}
+
+void logMessage(int level, const char * s, ...) {
+ va_list args;
+
+ va_start(args, s);
+ logMessageV(MAIN_LOG, level, s, args);
+ va_end(args);
+}
+
+void logProgramMessage(int level, const char * s, ...) {
+ va_list args;
+
+ va_start(args, s);
+ logMessageV(PROGRAM_LOG, level, s, args);
+ va_end(args);
+}
+
+int tty_logfd = -1;
+int file_logfd = -1;
+
+void openLog() {
+ /* init syslog logging (so loader messages can also be forwarded to a remote
+ syslog daemon */
+ openlog(main_tag, 0, syslog_facility);
+
+ int flags;
+ main_log_tty = fopen("/dev/tty3", "a");
+ main_log_file = fopen("/tmp/anaconda.log", "a");
+ program_log_file = fopen("/tmp/program.log", "a");
+
+ if (main_log_tty) {
+ tty_logfd = fileno(main_log_tty);
+ flags = fcntl(tty_logfd, F_GETFD, 0) | FD_CLOEXEC;
+ fcntl(tty_logfd, F_SETFD, flags);
+ }
+
+ if (main_log_file) {
+ file_logfd = fileno(main_log_file);
+ flags = fcntl(file_logfd, F_GETFD, 0) | FD_CLOEXEC;
+ fcntl(file_logfd, F_SETFD, flags);
+ }
+
+ if (program_log_file) {
+ int fd;
+ fd = fileno(program_log_file);
+ flags = fcntl(fd, F_GETFD, 0) | FD_CLOEXEC;
+ fcntl(file_logfd, F_SETFD, flags);
+ }
+}
+
+void closeLog(void) {
+ if (main_log_tty)
+ fclose(main_log_tty);
+ if (main_log_file)
+ fclose(main_log_file);
+ if (program_log_file)
+ fclose(program_log_file);
+
+ /* close syslog logger */
+ closelog();
+}
+
+/* set the level. higher means you see more verbosity */
+void setLogLevel(int level) {
+ minLevel = level;
+}
+
+int getLogLevel(void) {
+ return minLevel;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4: */
diff --git a/isys/log.h b/isys/log.h
new file mode 100644
index 0000000..51de2de
--- /dev/null
+++ b/isys/log.h
@@ -0,0 +1,51 @@
+/*
+ * log.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _LOG_H_
+#define _LOG_H_
+
+#include <stdio.h>
+#include <stdarg.h>
+
+#define DEBUGLVL 10
+#define INFO 20
+#define WARNING 30
+#define ERROR 40
+#define CRITICAL 50
+
+enum logger_t {
+ MAIN_LOG = 1,
+ PROGRAM_LOG = 2
+};
+
+void logMessageV(enum logger_t logger, int level, const char * s, va_list ap)
+ __attribute__ ((format (printf, 3, 0)));
+void logMessage(int level, const char * s, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void logProgramMessage(int level, const char * s, ...)
+ __attribute__ ((format (printf, 2, 3)));
+void openLog();
+void closeLog(void);
+void setLogLevel(int minLevel);
+int getLogLevel(void);
+
+extern int tty_logfd;
+extern int file_logfd;
+
+#endif /* _LOG_H_ */
diff --git a/isys/stubs.h b/isys/stubs.h
new file mode 100644
index 0000000..40ecb22
--- /dev/null
+++ b/isys/stubs.h
@@ -0,0 +1,44 @@
+/*
+ * stubs.h
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* we use gzlib when linked against dietlibc, but otherwise, we should use
+ zlib. it would make more sense to do the defines in the other direction,
+ but that causes symbol wackiness because both gunzip_open and gzip_open in
+ gzlib are gzopen from zlib
+*/
+
+#ifndef ISYS_STUB
+#define ISYS_STUB
+
+#ifndef GZLIB
+#include <zlib.h>
+
+#define gunzip_open(x) gzopen(x, "r")
+#define gunzip_dopen gzdopen(x, "r")
+#define gunzip_close gzclose
+#define gunzip_read gzread
+#define gzip_write gzwrite
+#define gzip_open(x, y, z) gzopen(x, "w")
+
+#else
+#include "gzlib/gzlib.h"
+
+#endif
+
+#endif
diff --git a/isys/uncpio.c b/isys/uncpio.c
new file mode 100644
index 0000000..171eb6b
--- /dev/null
+++ b/isys/uncpio.c
@@ -0,0 +1,798 @@
+/*
+ * uncpio.c
+ *
+ * Copyright (C) 2007 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define HAVE_ALLOCA_H 1
+#define MAJOR_IN_SYSMACROS 1
+
+#if HAVE_ALLOCA_H
+# include <alloca.h>
+#endif
+
+#define _(foo) (foo)
+
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <utime.h>
+
+#include "cpio.h"
+#include "stubs.h"
+
+#if MAJOR_IN_SYSMACROS
+#include <sys/sysmacros.h>
+#elif MAJOR_IN_MKDEV
+#include <sys/mkdev.h>
+#endif
+
+#define CPIO_NEWC_MAGIC "070701"
+#define CPIO_CRC_MAGIC "070702"
+#define TRAILER "TRAILER!!!"
+
+/* FIXME: We don't translate between cpio and system mode bits! These
+ should both be the same, but really odd things are going to happen if
+ that's not true! */
+
+/* We need to maintain our oun file pointer to allow padding */
+struct ourfd {
+ gzFile fd;
+ size_t pos;
+};
+
+struct hardLink {
+ struct hardLink * next;
+ char ** files; /* there are nlink of these, used by install */
+ int * fileMaps; /* used by build */
+ dev_t dev;
+ ino_t inode;
+ int nlink;
+ int linksLeft;
+ int createdPath;
+ struct stat sb;
+};
+
+struct cpioCrcPhysicalHeader {
+ char magic[6];
+ char inode[8];
+ char mode[8];
+ char uid[8];
+ char gid[8];
+ char nlink[8];
+ char mtime[8];
+ char filesize[8];
+ char devMajor[8];
+ char devMinor[8];
+ char rdevMajor[8];
+ char rdevMinor[8];
+ char namesize[8];
+ char checksum[8]; /* ignored !! */
+};
+
+#define PHYS_HDR_SIZE 110 /* don't depend on sizeof(struct) */
+
+struct cpioHeader {
+ ino_t inode;
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ int nlink;
+ time_t mtime;
+ unsigned long size;
+ dev_t dev, rdev;
+ char * path;
+};
+
+static inline off_t ourread(struct ourfd * thefd, void * buf, size_t size) {
+ off_t i;
+
+ i = gunzip_read(thefd->fd, buf, size);
+ thefd->pos += i;
+
+ return i;
+}
+
+static inline void padinfd(struct ourfd * fd, int modulo) {
+ int buf[10];
+ int amount;
+
+ amount = (modulo - fd->pos % modulo) % modulo;
+ ourread(fd, buf, amount);
+}
+
+static inline int padoutfd(struct ourfd * fd, size_t * where, int modulo) {
+ /*static int buf[10] = { '\0', '\0', '\0', '\0', '\0',
+ '\0', '\0', '\0', '\0', '\0' };*/
+ int amount;
+ static int buf[512];
+
+ amount = (modulo - *where % modulo) % modulo;
+ *where += amount;
+
+ if (gzip_write(fd->fd, buf, amount) != amount)
+ return CPIOERR_WRITE_FAILED;
+
+ return 0;
+}
+
+static int strntoul(const char * str, char ** endptr, int base, int num) {
+ char * buf, * end;
+ unsigned long ret;
+
+ buf = alloca(num + 1);
+ strncpy(buf, str, num);
+ buf[num] = '\0';
+
+ ret = strtoul(buf, &end, base);
+ if (*end)
+ *endptr = (char *)(str + (end - buf)); /* XXX discards const */
+ else
+ *endptr = "";
+
+ return strtoul(buf, endptr, base);
+}
+
+#define GET_NUM_FIELD(phys, log) \
+ log = strntoul(phys, &end, 16, sizeof(phys)); \
+ if (*end) return CPIOERR_BAD_HEADER;
+#define SET_NUM_FIELD(phys, val, space) \
+ sprintf(space, "%8.8lx", (unsigned long) (val)); \
+ memcpy(phys, space, 8);
+
+static int getNextHeader(struct ourfd * fd, struct cpioHeader * chPtr,
+ struct cpioCrcPhysicalHeader * physHeaderPtr) {
+ struct cpioCrcPhysicalHeader physHeader;
+ int nameSize;
+ char * end;
+ int major, minor;
+
+ if (ourread(fd, &physHeader, PHYS_HDR_SIZE) != PHYS_HDR_SIZE)
+ return CPIOERR_READ_FAILED;
+
+ if (physHeaderPtr)
+ memcpy(physHeaderPtr, &physHeader, PHYS_HDR_SIZE);
+
+ if (strncmp(CPIO_CRC_MAGIC, physHeader.magic, strlen(CPIO_CRC_MAGIC)) &&
+ strncmp(CPIO_NEWC_MAGIC, physHeader.magic, strlen(CPIO_NEWC_MAGIC)))
+ return CPIOERR_BAD_MAGIC;
+
+ GET_NUM_FIELD(physHeader.inode, chPtr->inode);
+ GET_NUM_FIELD(physHeader.mode, chPtr->mode);
+ GET_NUM_FIELD(physHeader.uid, chPtr->uid);
+ GET_NUM_FIELD(physHeader.gid, chPtr->gid);
+ GET_NUM_FIELD(physHeader.nlink, chPtr->nlink);
+ GET_NUM_FIELD(physHeader.mtime, chPtr->mtime);
+ GET_NUM_FIELD(physHeader.filesize, chPtr->size);
+
+ GET_NUM_FIELD(physHeader.devMajor, major);
+ GET_NUM_FIELD(physHeader.devMinor, minor);
+ chPtr->dev = makedev(major, minor);
+
+ GET_NUM_FIELD(physHeader.rdevMajor, major);
+ GET_NUM_FIELD(physHeader.rdevMinor, minor);
+ chPtr->rdev = makedev(major, minor);
+
+ GET_NUM_FIELD(physHeader.namesize, nameSize);
+
+ chPtr->path = malloc(nameSize + 1);
+ if (ourread(fd, chPtr->path, nameSize) != nameSize) {
+ free(chPtr->path);
+ return CPIOERR_BAD_HEADER;
+ }
+
+ /* this is unecessary chPtr->path[nameSize] = '\0'; */
+
+ padinfd(fd, 4);
+
+ return 0;
+}
+
+int myCpioFileMapCmp(const void * a, const void * b) {
+ const struct cpioFileMapping * first = a;
+ const struct cpioFileMapping * second = b;
+
+ return (strcmp(first->archivePath, second->archivePath));
+}
+
+/* This could trash files in the path! I'm not sure that's a good thing */
+static int createDirectory(char * path, mode_t perms) {
+ struct stat sb;
+ int dounlink;
+
+ if (!lstat(path, &sb)) {
+ if (S_ISDIR(sb.st_mode)) {
+ return 0;
+ } else if (S_ISLNK(sb.st_mode)) {
+ if (stat(path, &sb)) {
+ if (errno != ENOENT)
+ return CPIOERR_STAT_FAILED;
+ dounlink = 1;
+ } else {
+ if (S_ISDIR(sb.st_mode))
+ return 0;
+ dounlink = 1;
+ }
+ } else {
+ dounlink = 1;
+ }
+
+ if (dounlink && unlink(path)) {
+ return CPIOERR_UNLINK_FAILED;
+ }
+ }
+
+ if (mkdir(path, 000))
+ return CPIOERR_MKDIR_FAILED;
+
+ if (chmod(path, perms))
+ return CPIOERR_CHMOD_FAILED;
+
+ return 0;
+}
+
+static int setInfo(struct cpioHeader * hdr) {
+ int rc = 0;
+ struct utimbuf stamp;
+
+ stamp.actime = hdr->mtime;
+ stamp.modtime = hdr->mtime;
+
+ if (!S_ISLNK(hdr->mode)) {
+ if (!getuid() && chown(hdr->path, hdr->uid, hdr->gid))
+ rc = CPIOERR_CHOWN_FAILED;
+ if (!rc && chmod(hdr->path, hdr->mode & 07777))
+ rc = CPIOERR_CHMOD_FAILED;
+ if (!rc && utime(hdr->path, &stamp))
+ rc = CPIOERR_UTIME_FAILED;
+ } else {
+# if ! CHOWN_FOLLOWS_SYMLINK
+ if (!getuid() && !rc && lchown(hdr->path, hdr->uid, hdr->gid))
+ rc = CPIOERR_CHOWN_FAILED;
+# endif
+ }
+
+ return rc;
+}
+
+static int checkDirectory(char * filename) {
+ static char * lastDir = NULL;
+ static int lastDirLength = 0;
+ static int lastDirAlloced = 0;
+ int length = strlen(filename);
+ char * buf;
+ char * chptr;
+ int rc = 0;
+
+ buf = alloca(length + 1);
+ strcpy(buf, filename);
+
+ for (chptr = buf + length - 1; chptr > buf; chptr--) {
+ if (*chptr == '/') break;
+ }
+
+ if (chptr == buf) return 0; /* /filename - no directories */
+
+ *chptr = '\0'; /* buffer is now just directories */
+
+ length = strlen(buf);
+ if (lastDirLength == length && !strcmp(buf, lastDir)) return 0;
+
+ if (lastDirAlloced < (length + 1)) {
+ lastDirAlloced = length + 100;
+ lastDir = realloc(lastDir, lastDirAlloced);
+ }
+
+ strcpy(lastDir, buf);
+ lastDirLength = length;
+
+ for (chptr = buf + 1; *chptr; chptr++) {
+ if (*chptr == '/') {
+ *chptr = '\0';
+ rc = createDirectory(buf, 0755);
+ *chptr = '/';
+ if (rc) return rc;
+ }
+ }
+ rc = createDirectory(buf, 0755);
+
+ return rc;
+}
+
+static int expandRegular(struct ourfd * fd, struct cpioHeader * hdr,
+ cpioCallback cb, void * cbData) {
+ int out;
+ char buf[8192];
+ int bytesRead;
+ unsigned long left = hdr->size;
+ int rc = 0;
+ struct cpioCallbackInfo cbInfo;
+ struct stat sb;
+
+ if (!lstat(hdr->path, &sb))
+ if (unlink(hdr->path))
+ return CPIOERR_UNLINK_FAILED;
+
+ out = open(hdr->path, O_CREAT | O_WRONLY, 0);
+ if (out < 0)
+ return CPIOERR_OPEN_FAILED;
+
+ cbInfo.file = hdr->path;
+ cbInfo.fileSize = hdr->size;
+
+ while (left) {
+ bytesRead = ourread(fd, buf, left < sizeof(buf) ? left : sizeof(buf));
+ if (bytesRead <= 0) {
+ rc = CPIOERR_READ_FAILED;
+ break;
+ }
+
+ if (write(out, buf, bytesRead) != bytesRead) {
+ rc = CPIOERR_COPY_FAILED;
+ break;
+ }
+
+ left -= bytesRead;
+
+ /* don't call this with fileSize == fileComplete */
+ if (!rc && cb && left) {
+ cbInfo.fileComplete = hdr->size - left;
+ cbInfo.bytesProcessed = fd->pos;
+ cb(&cbInfo, cbData);
+ }
+ }
+
+ close(out);
+
+ return rc;
+}
+
+static int expandSymlink(struct ourfd * fd, struct cpioHeader * hdr) {
+ char buf[2048], buf2[2048];
+ struct stat sb;
+ int len;
+
+ if ((hdr->size + 1)> sizeof(buf))
+ return CPIOERR_INTERNAL;
+
+ if (ourread(fd, buf, hdr->size) != hdr->size)
+ return CPIOERR_READ_FAILED;
+
+ buf[hdr->size] = '\0';
+
+ if (!lstat(hdr->path, &sb)) {
+ if (S_ISLNK(sb.st_mode)) {
+ len = readlink(hdr->path, buf2, sizeof(buf2) - 1);
+ if (len > 0) {
+ buf2[len] = '\0';
+ if (!strcmp(buf, buf2)) return 0;
+ }
+ }
+
+ if (unlink(hdr->path))
+ return CPIOERR_UNLINK_FAILED;
+ }
+
+ if (symlink(buf, hdr->path) < 0)
+ return CPIOERR_SYMLINK_FAILED;
+
+ return 0;
+}
+
+static int expandFifo(struct ourfd * fd, struct cpioHeader * hdr) {
+ struct stat sb;
+
+ if (!lstat(hdr->path, &sb)) {
+ if (S_ISFIFO(sb.st_mode)) return 0;
+
+ if (unlink(hdr->path))
+ return CPIOERR_UNLINK_FAILED;
+ }
+
+ if (mkfifo(hdr->path, 0))
+ return CPIOERR_MKFIFO_FAILED;
+
+ return 0;
+}
+
+static int expandDevice(struct ourfd * fd, struct cpioHeader * hdr) {
+ struct stat sb;
+
+ if (!lstat(hdr->path, &sb)) {
+ if ((S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) &&
+ (sb.st_rdev == hdr->rdev))
+ return 0;
+ if (unlink(hdr->path))
+ return CPIOERR_UNLINK_FAILED;
+ }
+
+ if (mknod(hdr->path, hdr->mode & (~0777), hdr->rdev))
+ return CPIOERR_MKNOD_FAILED;
+
+ return 0;
+}
+
+static void freeLink(struct hardLink * li) {
+ int i;
+
+ for (i = 0; i < li->nlink; i++) {
+ if (li->files[i]) free(li->files[i]);
+ }
+ free(li->files);
+}
+
+static int createLinks(struct hardLink * li, const char ** failedFile) {
+ int i;
+ struct stat sb;
+
+ for (i = 0; i < li->nlink; i++) {
+ if (i == li->createdPath) continue;
+ if (!li->files[i]) continue;
+
+ if (!lstat(li->files[i], &sb)) {
+ if (unlink(li->files[i])) {
+ *failedFile = strdup(li->files[i]);
+ return CPIOERR_UNLINK_FAILED;
+ }
+ }
+
+ if (link(li->files[li->createdPath], li->files[i])) {
+ *failedFile = strdup(li->files[i]);
+ return CPIOERR_LINK_FAILED;
+ }
+
+ free(li->files[i]);
+ li->files[i] = NULL;
+ li->linksLeft--;
+ }
+
+ return 0;
+}
+
+static int eatBytes(struct ourfd * fd, unsigned long amount) {
+ char buf[4096];
+ unsigned long bite;
+
+ while (amount) {
+ bite = (amount > sizeof(buf)) ? sizeof(buf) : amount;
+ if (ourread(fd, buf, bite) != bite)
+ return CPIOERR_READ_FAILED;
+ amount -= bite;
+ }
+
+ return 0;
+}
+
+int myCpioInstallArchive(gzFile stream, struct cpioFileMapping * mappings,
+ int numMappings, cpioCallback cb, void * cbData,
+ const char ** failedFile) {
+ struct cpioHeader ch;
+ struct ourfd fd;
+ int rc = 0;
+ int linkNum = 0;
+ struct cpioFileMapping * map = NULL;
+ struct cpioFileMapping needle;
+ mode_t cpioMode;
+ int olderr;
+ struct cpioCallbackInfo cbInfo;
+ struct hardLink * links = NULL;
+ struct hardLink * li = NULL;
+
+ fd.fd = stream;
+ fd.pos = 0;
+
+ *failedFile = NULL;
+
+ do {
+ if ((rc = getNextHeader(&fd, &ch, NULL))) {
+ fprintf(stderr, _("error %d reading header: %s\n"), rc,
+ myCpioStrerror(rc));
+ return CPIOERR_BAD_HEADER;
+ }
+
+ if (!strcmp(ch.path, TRAILER)) {
+ free(ch.path);
+ break;
+ }
+
+ if (mappings) {
+ needle.archivePath = ch.path;
+ map = bsearch(&needle, mappings, numMappings, sizeof(needle),
+ myCpioFileMapCmp);
+ }
+
+ if (mappings && !map) {
+ eatBytes(&fd, ch.size);
+ } else {
+ cpioMode = ch.mode;
+
+ if (map) {
+ if (map->mapFlags & CPIO_MAP_PATH) {
+ free(ch.path);
+ ch.path = strdup(map->fsPath);
+ }
+
+ if (map->mapFlags & CPIO_MAP_MODE)
+ ch.mode = map->finalMode;
+ if (map->mapFlags & CPIO_MAP_UID)
+ ch.uid = map->finalUid;
+ if (map->mapFlags & CPIO_MAP_GID)
+ ch.gid = map->finalGid;
+ }
+
+ /* This won't get hard linked symlinks right, but I can't seem
+ to create those anyway */
+
+ if (S_ISREG(ch.mode) && ch.nlink > 1) {
+ li = links;
+ for (li = links; li; li = li->next) {
+ if (li->inode == ch.inode && li->dev == ch.dev) break;
+ }
+
+ if (!li) {
+ li = malloc(sizeof(*li));
+ li->inode = ch.inode;
+ li->dev = ch.dev;
+ li->nlink = ch.nlink;
+ li->linksLeft = ch.nlink;
+ li->createdPath = -1;
+ li->files = calloc(sizeof(char *), li->nlink);
+ li->next = links;
+ links = li;
+ }
+
+ for (linkNum = 0; linkNum < li->nlink; linkNum++)
+ if (!li->files[linkNum]) break;
+ li->files[linkNum] = strdup(ch.path);
+ }
+
+ if ((ch.nlink > 1) && S_ISREG(ch.mode) && !ch.size &&
+ li->createdPath == -1) {
+ /* defer file creation */
+ } else if ((ch.nlink > 1) && S_ISREG(ch.mode) &&
+ (li->createdPath != -1)) {
+ createLinks(li, failedFile);
+
+ /* this only happens for cpio archives which contain
+ hardlinks w/ the contents of each hardlink being
+ listed (intead of the data being given just once. This
+ shouldn't happen, but I've made it happen w/ buggy
+ code, so what the heck? GNU cpio handles this well fwiw */
+ if (ch.size) eatBytes(&fd, ch.size);
+ } else {
+ rc = checkDirectory(ch.path);
+
+ if (!rc) {
+ if (S_ISREG(ch.mode))
+ rc = expandRegular(&fd, &ch, cb, cbData);
+ else if (S_ISDIR(ch.mode))
+ rc = createDirectory(ch.path, 000);
+ else if (S_ISLNK(ch.mode))
+ rc = expandSymlink(&fd, &ch);
+ else if (S_ISFIFO(ch.mode))
+ rc = expandFifo(&fd, &ch);
+ else if (S_ISCHR(ch.mode) || S_ISBLK(ch.mode))
+ rc = expandDevice(&fd, &ch);
+ else if (S_ISSOCK(ch.mode)) {
+ /* this mimicks cpio but probably isnt' right */
+ rc = expandFifo(&fd, &ch);
+ } else {
+ rc = CPIOERR_INTERNAL;
+ }
+ }
+
+ if (!rc)
+ rc = setInfo(&ch);
+
+ if (S_ISREG(ch.mode) && ch.nlink > 1) {
+ li->createdPath = linkNum;
+ li->linksLeft--;
+ rc = createLinks(li, failedFile);
+ }
+ }
+
+ if (rc && !*failedFile) {
+ *failedFile = strdup(ch.path);
+
+ olderr = errno;
+ unlink(ch.path);
+ errno = olderr;
+ }
+ }
+
+ padinfd(&fd, 4);
+
+ if (!rc && cb) {
+ cbInfo.file = ch.path;
+ cbInfo.fileSize = ch.size;
+ cbInfo.fileComplete = ch.size;
+ cbInfo.bytesProcessed = fd.pos;
+ cb(&cbInfo, cbData);
+ }
+
+ free(ch.path);
+ } while (1 && !rc);
+
+ li = links;
+ while (li && !rc) {
+ if (li->linksLeft) {
+ if (li->createdPath == -1)
+ rc = CPIOERR_INTERNAL;
+ else
+ rc = createLinks(li, failedFile);
+ }
+
+ freeLink(li);
+
+ links = li;
+ li = li->next;
+ free(links);
+ links = li;
+ }
+
+ li = links;
+ /* if an error got us here links will still be eating some memory */
+ while (li) {
+ freeLink(li);
+ links = li;
+ li = li->next;
+ free(links);
+ }
+
+ return rc;
+}
+
+const char * myCpioStrerror(int rc)
+{
+ static char msg[256];
+ char *s;
+ int l, myerrno = errno;
+
+ strcpy(msg, "cpio: ");
+ switch (rc) {
+ default:
+ s = msg + strlen(msg);
+ sprintf(s, _("(error 0x%x)"), rc);
+ s = NULL;
+ break;
+ case CPIOERR_BAD_MAGIC: s = _("Bad magic"); break;
+ case CPIOERR_BAD_HEADER: s = _("Bad header"); break;
+
+ case CPIOERR_OPEN_FAILED: s = "open"; break;
+ case CPIOERR_CHMOD_FAILED: s = "chmod"; break;
+ case CPIOERR_CHOWN_FAILED: s = "chown"; break;
+ case CPIOERR_WRITE_FAILED: s = "write"; break;
+ case CPIOERR_UTIME_FAILED: s = "utime"; break;
+ case CPIOERR_UNLINK_FAILED: s = "unlink"; break;
+ case CPIOERR_SYMLINK_FAILED: s = "symlink"; break;
+ case CPIOERR_STAT_FAILED: s = "stat"; break;
+ case CPIOERR_MKDIR_FAILED: s = "mkdir"; break;
+ case CPIOERR_MKNOD_FAILED: s = "mknod"; break;
+ case CPIOERR_MKFIFO_FAILED: s = "mkfifo"; break;
+ case CPIOERR_LINK_FAILED: s = "link"; break;
+ case CPIOERR_READLINK_FAILED: s = "readlink"; break;
+ case CPIOERR_READ_FAILED: s = "read"; break;
+ case CPIOERR_COPY_FAILED: s = "copy"; break;
+
+ case CPIOERR_INTERNAL: s = _("Internal error"); break;
+ case CPIOERR_HDR_SIZE: s = _("Header size too big"); break;
+ case CPIOERR_UNKNOWN_FILETYPE: s = _("Unknown file type"); break;
+ }
+
+ l = sizeof(msg) - strlen(msg) - 1;
+ if (s != NULL) {
+ if (l > 0) strncat(msg, s, l);
+ l -= strlen(s);
+ }
+ if (rc & CPIOERR_CHECK_ERRNO) {
+ s = _(" failed - ");
+ if (l > 0) strncat(msg, s, l);
+ l -= strlen(s);
+ if (l > 0) strncat(msg, strerror(myerrno), l);
+ }
+ return msg;
+}
+
+static int copyFile(struct ourfd * inFd, struct ourfd * outFd,
+ struct cpioHeader * chp, struct cpioCrcPhysicalHeader * pHdr) {
+ char buf[8192];
+ int amount;
+ size_t size = chp->size;
+
+ amount = strlen(chp->path) + 1;
+ memcpy(pHdr->magic, CPIO_NEWC_MAGIC, sizeof(pHdr->magic));
+
+ gzip_write(outFd->fd, pHdr, PHYS_HDR_SIZE);
+ gzip_write(outFd->fd, chp->path, amount);
+
+ outFd->pos += PHYS_HDR_SIZE + amount;
+
+ padoutfd(outFd, &outFd->pos, 4);
+
+ while (size) {
+ amount = ourread(inFd, buf, size > sizeof(buf) ? sizeof(buf) : size);
+ gzip_write(outFd->fd, buf, amount);
+ size -= amount;
+ }
+
+ outFd->pos += chp->size;
+
+ padoutfd(outFd, &outFd->pos, 4);
+
+ return 0;
+}
+
+int myCpioFilterArchive(gzFile inStream, gzFile outStream, char ** patterns) {
+ struct ourfd inFd, outFd;
+ char ** aPattern;
+ struct cpioHeader ch;
+ int rc;
+ struct cpioCrcPhysicalHeader pHeader;
+
+ inFd.fd = inStream;
+ inFd.pos = 0;
+ outFd.fd = outStream;
+ outFd.pos = 0;
+
+ do {
+ if ((rc = getNextHeader(&inFd, &ch, &pHeader))) {
+ fprintf(stderr, _("error %d reading header: %s\n"), rc,
+ myCpioStrerror(rc));
+ return CPIOERR_BAD_HEADER;
+ }
+
+ if (!strcmp(ch.path, TRAILER)) {
+ free(ch.path);
+ break;
+ }
+
+ for (aPattern = patterns; *aPattern; aPattern++)
+ if (!fnmatch(*aPattern, ch.path, FNM_PATHNAME | FNM_PERIOD))
+ break;
+
+ if (!*aPattern)
+ eatBytes(&inFd, ch.size);
+ else
+ copyFile(&inFd, &outFd, &ch, &pHeader);
+
+ padinfd(&inFd, 4);
+
+ free(ch.path);
+ } while (1 && !rc);
+
+ memset(&pHeader, '0', sizeof(pHeader));
+ memcpy(pHeader.magic, CPIO_NEWC_MAGIC, sizeof(pHeader.magic));
+ memcpy(pHeader.nlink, "00000001", 8);
+ memcpy(pHeader.namesize, "0000000b", 8);
+ gzip_write(outFd.fd, &pHeader, PHYS_HDR_SIZE);
+ gzip_write(outFd.fd, "TRAILER!!!", 11);
+
+ outFd.pos += PHYS_HDR_SIZE + 11;
+
+ if ((rc = padoutfd(&outFd, &outFd.pos, 4)))
+ return rc;
+
+ if ((rc = padoutfd(&outFd, &outFd.pos, 512)))
+ return rc;
+
+ return 0;
+}
diff --git a/isys/vio.c b/isys/vio.c
new file mode 100644
index 0000000..9b06a3e
--- /dev/null
+++ b/isys/vio.c
@@ -0,0 +1,106 @@
+/*
+ * vio.c - probing for vio devices on the iSeries (viocd and viodasd)
+ *
+ * Copyright (C) 2003 Red Hat, Inc. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author(s): Jeremy Katz <katzj@redhat.com>
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if defined(__powerpc__)
+static int readFD (int fd, char **buf)
+{
+ char *p;
+ size_t size = 4096;
+ int s, filesize;
+
+ *buf = malloc (size);
+ if (*buf == 0)
+ return -1;
+
+ filesize = 0;
+ do {
+ p = &(*buf) [filesize];
+ s = read (fd, p, 4096);
+ if (s < 0)
+ break;
+ filesize += s;
+ if (s == 0)
+ break;
+ size += 4096;
+ *buf = realloc (*buf, size);
+ } while (1);
+
+ if (filesize == 0 && s < 0) {
+ free (*buf);
+ *buf = NULL;
+ return -1;
+ }
+
+ return filesize;
+}
+#endif
+
+int isVioConsole(void) {
+#if !defined(__powerpc__)
+ return 0;
+#else
+ int fd, i;
+ char *buf, *start;
+ char driver[50], device[50];
+ static int isviocons = -1;
+
+ if (isviocons != -1)
+ return isviocons;
+
+ fd = open("/proc/tty/drivers", O_RDONLY);
+ if (fd < 0) {
+ fprintf(stderr, "failed to open /proc/tty/drivers!\n");
+ return 0;
+ }
+ i = readFD(fd, &buf);
+ if (i < 1) {
+ close(fd);
+ fprintf(stderr, "error reading /proc/tty/drivers!\n");
+ return 0;
+ }
+ close(fd);
+ buf[i] = '\0';
+
+ isviocons = 0;
+ start = buf;
+ while (start && *start) {
+ if (sscanf(start, "%s %s", (char *) &driver, (char *) &device) == 2) {
+ if (!strcmp(driver, "vioconsole") && !strcmp(device, "/dev/tty")) {
+ isviocons = 1;
+ break;
+ }
+ }
+ start = strchr(start, '\n');
+ if (start)
+ start++;
+ }
+ free(buf);
+ return isviocons;
+#endif
+}