diff options
author | wiktor w brodlo <wiktor@brodlo.net> | 2011-06-15 16:59:54 +0000 |
---|---|---|
committer | wiktor w brodlo <wiktor@brodlo.net> | 2011-06-15 16:59:54 +0000 |
commit | 2590d96369d0217e31dc2812690dde61dac417b5 (patch) | |
tree | 82276f787b08a28548e342c7921486f1acefab9f /isys | |
parent | first commit (diff) | |
download | anaconda-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/.gitignore | 5 | ||||
-rw-r--r-- | isys/Makefile.am | 50 | ||||
-rw-r--r-- | isys/auditd.c | 135 | ||||
-rw-r--r-- | isys/auditd.h | 30 | ||||
-rw-r--r-- | isys/cpio.c | 46 | ||||
-rw-r--r-- | isys/cpio.h | 102 | ||||
-rw-r--r-- | isys/devices.c | 217 | ||||
-rw-r--r-- | isys/devices.h | 42 | ||||
-rw-r--r-- | isys/eddsupport.c | 339 | ||||
-rw-r--r-- | isys/eddsupport.h | 28 | ||||
-rw-r--r-- | isys/ethtool.c | 119 | ||||
-rw-r--r-- | isys/ethtool.h | 41 | ||||
-rw-r--r-- | isys/iface.c | 543 | ||||
-rw-r--r-- | isys/iface.h | 166 | ||||
-rw-r--r-- | isys/imount.c | 315 | ||||
-rw-r--r-- | isys/imount.h | 48 | ||||
-rw-r--r-- | isys/isofs.c | 55 | ||||
-rw-r--r-- | isys/isys.c | 700 | ||||
-rw-r--r-- | isys/isys.h | 38 | ||||
-rwxr-xr-x | isys/isys.py | 583 | ||||
-rw-r--r-- | isys/lang.c | 207 | ||||
-rw-r--r-- | isys/lang.h | 44 | ||||
-rw-r--r-- | isys/linkdetect.c | 202 | ||||
-rw-r--r-- | isys/log.c | 224 | ||||
-rw-r--r-- | isys/log.h | 51 | ||||
-rw-r--r-- | isys/stubs.h | 44 | ||||
-rw-r--r-- | isys/uncpio.c | 798 | ||||
-rw-r--r-- | isys/vio.c | 106 |
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, ¤tSig)) < 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(¤t_time, NULL); + t = gmtime(¤t_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 +} |