[Ocfs2-tools-commits] manish commits r799 - in trunk/ocfs2console:
. ocfs2interface
svn-commits at oss.oracle.com
svn-commits at oss.oracle.com
Tue Apr 12 21:02:33 CDT 2005
Author: manish
Date: 2005-04-12 21:02:31 -0500 (Tue, 12 Apr 2005)
New Revision: 799
Added:
trunk/ocfs2console/ocfs2interface/bosa.py
trunk/ocfs2console/ocfs2interface/classlabel.py
trunk/ocfs2console/ocfs2interface/fstab.py
trunk/ocfs2console/ocfs2interface/gidlemodule.c
trunk/ocfs2console/ocfs2interface/ls.py
trunk/ocfs2console/ocfs2interface/nodeconfig.py
trunk/ocfs2console/ocfs2interface/o2cbmodule.c
trunk/ocfs2console/ocfs2interface/plistmodule.c
trunk/ocfs2console/ocfs2interface/pushconfig.py
Removed:
trunk/ocfs2console/ocfs2interface/browser.py
trunk/ocfs2console/ocfs2interface/clconfig.py
Modified:
trunk/ocfs2console/ocfs2console
trunk/ocfs2console/ocfs2interface/
trunk/ocfs2console/ocfs2interface/Makefile
trunk/ocfs2console/ocfs2interface/about.py
trunk/ocfs2console/ocfs2interface/console.py
trunk/ocfs2console/ocfs2interface/format.py
trunk/ocfs2console/ocfs2interface/general.py
trunk/ocfs2console/ocfs2interface/guiutil.py
trunk/ocfs2console/ocfs2interface/menu.py
trunk/ocfs2console/ocfs2interface/mount.py
trunk/ocfs2console/ocfs2interface/ocfs2module.c
trunk/ocfs2console/ocfs2interface/partitionview.py
trunk/ocfs2console/ocfs2interface/tune.py
Log:
Massive ocfs2console refactoring
Modified: trunk/ocfs2console/ocfs2console
===================================================================
--- trunk/ocfs2console/ocfs2console 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2console 2005-04-13 02:02:31 UTC (rev 799)
@@ -4,7 +4,7 @@
#!/usr/bin/python -W ignore::DeprecationWarning
from ocfs2interface.about import process_args
-clusterconf = process_args()
+nodeconf = process_args()
try:
import gtk
@@ -14,9 +14,9 @@
Make sure a proper setup for your display environment exists.\n'''
sys.exit(1)
-if clusterconf:
- from ocfs2interface.clconfig import cluster_configurator
- cluster_configurator()
+if nodeconf:
+ from ocfs2interface.nodeconfig import node_config
+ node_config()
else:
from ocfs2interface.console import main
main()
Property changes on: trunk/ocfs2console/ocfs2interface
___________________________________________________________________
Name: svn:ignore
- *.d
*.pyc
*.pyo
ocfs2module.so
+ *.d
*.pyc
*.pyo
plistmodule.so
gidlemodule.so
ocfs2module.so
o2cbmodule.so
Modified: trunk/ocfs2console/ocfs2interface/Makefile
===================================================================
--- trunk/ocfs2console/ocfs2interface/Makefile 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/Makefile 2005-04-13 02:02:31 UTC (rev 799)
@@ -11,6 +11,8 @@
CFLAGS = $(OPTS) $(WARNINGS) -fPIC
+PYMOD_CFLAGS = $(CFLAGS) -fno-strict-aliasing $(PYTHON_INCLUDES)
+
LIBOCFS2_CFLAGS = -I$(TOPDIR)/libocfs2/include
LIBOCFS2_LIBS = -L$(TOPDIR)/libocfs2 -locfs2
LIBOCFS2_DEPS = $(TOPDIR)/libocfs2/libocfs2.a
@@ -32,55 +34,85 @@
BLKID_LIBS = -L$(TOPDIR)/ocfs2console/blkid -lblkid-internal $(UUID_LIBS)
endif
-DEFINES = -DOCFS2_FLAT_INCLUDES -DO2DLM_FLAT_INCLUDES -DO2CB_FLAT_INCLUDES -DG_DISABLE_DEPRECATED
-INCLUDES = $(LIBOCFS2_CFLAGS) $(LIBO2DLM_CFLAGS) $(LIBO2CB_CFLAGS) $(BLKID_CFLAGS) $(PYTHON_INCLUDES) $(GLIB_CFLAGS)
+O2CB_CPPFLAGS = -DO2CB_FLAT_INCLUDES $(LIBO2CB_CFLAGS)
+OCFS2_CPPFLAGS = -DOCFS2_FLAT_INCLUDES -DO2DLM_FLAT_INCLUDES $(LIBOCFS2_CFLAGS) $(LIBO2DLM_CFLAGS) $(O2CB_CPPFLAGS)
+GLIB_CPPFLAGS = $(GLIB_CFLAGS) -DG_DISABLE_DEPRECATED
+
OPTIMIZE = -O2
OPTIMIZE = -O0
CFLAGS += $(OPTIMIZE)
-CBITS = \
- ocfsplist.c
+PLIST_CBITS = ocfsplist.c
+PLIST_CFILES = $(PLIST_CBITS) plistmodule.c
+PLIST_HFILES = $(subst .c,.h,$(PLIST_CBITS))
-HBITS = $(subst .c,.h,$(CBITS))
+ocfsplist_CPPFLAGS = $(OCFS2_CPPFLAGS) $(GLIB_CPPFLAGS) $(BLKID_CFLAGS)
+plistmodule_CPPFLAGS = $(GLIB_CPPFLAGS)
+plistmodule_CFLAGS = $(PYMOD_CFLAGS)
-CFILES = $(CBITS) ocfs2module.c
-HFILES = $(HBITS)
+GIDLE_CFILES = gidlemodule.c
+gidlemodule_CPPFLAGS = $(GLIB_CPPFLAGS)
+gidlemodule_CFLAGS = $(PYMOD_CFLAGS)
-OBJS = $(subst .c,.o,$(CFILES))
+O2CB_CFILES = o2cbmodule.c
+o2cbmodule_CPPFLAGS = $(O2CB_CPPFLAGS)
+o2cbmodule_CFLAGS = $(PYMOD_CFLAGS)
-LIBRARIES = ocfs2module.so
+OCFS2_CFILES = ocfs2module.c
+ocfs2module_CPPFLAGS = $(OCFS2_CPPFLAGS)
+ocfs2module_CFLAGS = $(PYMOD_CFLAGS)
+PLIST_OBJS = $(subst .c,.o,$(PLIST_CFILES))
+GIDLE_OBJS = $(subst .c,.o,$(GIDLE_CFILES))
+OCFS2_OBJS = $(subst .c,.o,$(OCFS2_CFILES))
+O2CB_OBJS = $(subst .c,.o,$(O2CB_CFILES))
+
+LIBRARIES = plistmodule.so gidlemodule.so ocfs2module.so o2cbmodule.so
+
PYSRC = \
- __init__.py \
- about.py \
- browser.py \
- clconfig.py \
- console.py \
- format.py \
- fsck.py \
- fswidgets.py \
- general.py \
- guiutil.py \
- ipwidget.py \
- mount.py \
- menu.py \
- partitionview.py \
- process.py \
- terminal.py \
- toolbar.py \
+ __init__.py \
+ about.py \
+ bosa.py \
+ classlabel.py \
+ console.py \
+ format.py \
+ fsck.py \
+ fstab.py \
+ fswidgets.py \
+ general.py \
+ guiutil.py \
+ ipwidget.py \
+ ls.py \
+ mount.py \
+ menu.py \
+ nodeconfig.py \
+ partitionview.py \
+ process.py \
+ pushconfig.py \
+ terminal.py \
+ toolbar.py \
tune.py
PYLIB = $(LIBRARIES) $(PYSRC)
INSTALL_RULES = install-pylib
-DIST_FILES = $(CFILES) $(HFILES) $(PYSRC)
+DIST_FILES = $(PLIST_CFILES) $(PLIST_HFILES) $(GIDLE_CFILES) $(OCFS2_CFILES) $(O2CB_CFILES) $(PYSRC)
-ocfs2module.so: $(OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(BLKID_DEPS)
+plistmodule.so: $(PLIST_OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS) $(BLKID_DEPS)
$(LINK) -shared $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(BLKID_LIBS) $(COM_ERR_LIBS) $(GLIB_LIBS)
+gidlemodule.so: $(GIDLE_OBJS)
+ $(LINK) -shared $(GLIB_LIBS)
+
+ocfs2module.so: $(OCFS2_OBJS) $(LIBOCFS2_DEPS) $(LIBO2DLM_DEPS) $(LIBO2CB_DEPS)
+ $(LINK) -shared $(LIBOCFS2_LIBS) $(LIBO2DLM_LIBS) $(LIBO2CB_LIBS) $(COM_ERR_LIBS) $(UUID_LIBS)
+
+o2cbmodule.so: $(O2CB_OBJS) $(LIBO2CB_DEPS)
+ $(LINK) -shared $(LIBO2CB_LIBS) $(COM_ERR_LIBS)
+
install-pylib:
$(SHELL) $(TOPDIR)/mkinstalldirs $(DESTDIR)$(pyexecdir)/ocfs2interface
for f in $(PYLIB); do \
Modified: trunk/ocfs2console/ocfs2interface/about.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/about.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/about.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -25,12 +25,12 @@
def print_usage(name):
print '''Usage: %s [OPTION]...
Options:
- -C, --clusterconf run cluster configurator only
+ -N, --node-config run node configurator only
-V, --version print version information and exit
--help display this help and exit''' % name
def process_args():
- clusterconf = False
+ nodeconf = False
for arg in sys.argv[1:]:
if arg in ('--version', '-V'):
@@ -39,10 +39,10 @@
elif arg in ('--help',):
print_usage(sys.argv[0])
sys.exit(0)
- elif arg in ('--clusterconf', '-C'):
- clusterconf = True
+ elif arg in ('--node-config', '-N'):
+ nodeconf = True
- return clusterconf
+ return nodeconf
def process_gui_args():
if len(sys.argv) > 1 and sys.argv[1] not in ('--clusterconf', '-C'):
Added: trunk/ocfs2console/ocfs2interface/bosa.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/bosa.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/bosa.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,223 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2002, 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+import gtk
+import gobject
+import pango
+
+import ocfs2
+
+from guiutil import set_props
+
+from ls import fields
+
+INFO_LABEL_FONT = pango.FontDescription('monospace')
+
+(
+ COLUMN_NAME,
+ COLUMN_INFO_OBJECT,
+ COLUMN_ICON,
+ COLUMN_ITALIC
+) = range(4)
+
+sample = ('-rw-r--r--', '1', 'manish', 'manish', '133194', '262144', 'Sep 29 12:46', 'closobo.c')
+
+STOCK_LOADING = gtk.STOCK_REFRESH
+STOCK_EMPTY = gtk.STOCK_STOP
+STOCK_ERROR = gtk.STOCK_DIALOG_ERROR
+
+try:
+ STOCK_FILE = gtk.STOCK_FILE
+except AttributeError:
+ STOCK_FILE = gtk.STOCK_NEW
+
+try:
+ STOCK_DIRECTORY = gtk.STOCK_DIRECTORY
+except AttributeError:
+ STOCK_DIRECTORY = gtk.STOCK_OPEN
+
+class InfoLabel(gtk.Label):
+ def __init__(self, field_type):
+ gtk.Label.__init__(self)
+
+ self.field_type = field_type
+
+ if field_type.right_justify:
+ set_props(self, xalign=1.0)
+ else:
+ set_props(self, xalign=0.0)
+
+ self.modify_font(INFO_LABEL_FONT)
+
+ def update(self, dentry, dinode):
+ field = self.field_type(dentry, dinode)
+ self.set_text(field.text)
+
+class Browser(gtk.VBox):
+ def __init__(self, device=None):
+ gtk.VBox.__init__(self, spacing=4)
+
+ label = gtk.Label('/')
+ set_props(label, xalign=0.0)
+ self.pack_start(label, expand=False)
+
+ self.path_label = label
+
+ self.scrl_win = gtk.ScrolledWindow()
+ self.scrl_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+ self.add(self.scrl_win)
+
+ self.store = gtk.TreeStore(str, gobject.TYPE_PYOBJECT,
+ str, gobject.TYPE_BOOLEAN)
+
+ self.make_file_view()
+
+ self.make_ls_fields()
+
+ self.fs = None
+
+ if device:
+ try:
+ self.fs = ocfs2.Filesystem(device)
+ except ocfs2.error:
+ self.make_error_node()
+ else:
+ self.make_empty_node()
+
+ self.connect('destroy', self.destroy)
+
+ def make_file_view(self):
+ tv = gtk.TreeView(self.store)
+ self.scrl_win.add(tv)
+
+ set_props(tv, headers_visible=False,
+ rules_hint=True)
+
+ column = gtk.TreeViewColumn()
+
+ renderer = gtk.CellRendererPixbuf()
+ column.pack_start(renderer, expand=False)
+ column.set_attributes(renderer, stock_id=COLUMN_ICON)
+
+ renderer = gtk.CellRendererText()
+ renderer.set_property('style', pango.STYLE_ITALIC)
+ column.pack_start(renderer, expand=True)
+ column.set_attributes(renderer, text=COLUMN_NAME,
+ style_set=COLUMN_ITALIC)
+
+ tv.append_column(column)
+
+ #tv.connect('test_expand_row', self.test_expand_row)
+ #tv.connect('test_collapse_row', self.test_collapse_row)
+ #tv.connect('row_activated', self.row_activated)
+
+ #sel = tv.get_selection()
+ #sel.connect('changed', self.select)
+
+ def make_ls_fields(self):
+ table = gtk.Table(rows=2, columns=7)
+ set_props(table, row_spacing=4,
+ column_spacing=4,
+ border_width=4)
+ self.pack_end(table, expand=False, fill=False)
+
+ self.info_labels = []
+
+ column = 0
+
+ for field in fields:
+ label = gtk.Label(field.label)
+ set_props(label, xalign=0.0)
+ table.attach(label, column, column + 1, 0, 1)
+
+ label = InfoLabel(field)
+ table.attach(label, column, column + 1, 1, 2)
+
+ self.info_labels.append(label)
+
+ column += 1
+
+ def destroy(self, obj):
+ pass
+
+ def make_dentry_node(self, dentry, stock_id, parent=None):
+ self.store.append(parent, (dentry.name, dentry, stock_id, False))
+
+ def make_file_node(self, dentry, parent=None):
+ self.make_dentry_node(dentry, STOCK_FILE, parent)
+
+ def make_dir_node(self, dentry, parent=None):
+ iter = self.make_dentry_node(dentry, STOCK_DIRECTORY, parent)
+ self.store_append(iter, ('.', dentry, None, False))
+
+ def make_loading_node(self, parent=None):
+ self.store.append(parent, ('Loading...', None, STOCK_LOADING, True))
+
+ def make_empty_node(self, parent=None):
+ self.store.append(parent, ('Empty', None, STOCK_EMPTY, True))
+
+ def make_error_node(self, parent=None):
+ self.store.append(parent, ('Error', None, STOCK_ERROR, True))
+
+ def refresh(self):
+ pass
+
+ def add_level(self, dentry=None, parent=None):
+ if parent:
+ iter = self.store.iter_children(parent)
+
+ name = self.store[iter][COLUMN_NAME]
+ if name != '.':
+ return
+
+ del self.store[iter]
+
+ try:
+ level = TreeLevel(self, dentry)
+ except ocfs2.error:
+ self.make_erro_node(parent)
+ return
+
+ self.make_loading_node(parent)
+
+
+ #self.levels.append(TreeLevel(self, dentry))
+
+class TreeLevel:
+ def __init__(self, browser, dentry=None):
+ self.dentry = dentry
+ self.browser = browser
+ self.diriter = dentry.fs.iterdir(dentry)
+
+def main():
+ import sys
+
+ def dummy(*args):
+ gtk.main_quit()
+
+ window = gtk.Window()
+ window.connect('delete_event', dummy)
+
+ browser = Browser(sys.argv[1])
+ window.add(browser)
+
+ window.show_all()
+
+ gtk.main()
+
+if __name__ == '__main__':
+ main()
Deleted: trunk/ocfs2console/ocfs2interface/browser.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/browser.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/browser.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -1,82 +0,0 @@
-# OCFS2Console - GUI frontend for OCFS2 management and debugging
-# Copyright (C) 2002, 2005 Oracle. 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
-
-import gtk
-import pango
-
-import ocfs2
-
-from guiutil import set_props
-
-fields = ('Perms', '# Links', 'Owner', 'Group', 'Size', 'Alloc Size',
- 'Timestamp', 'Name')
-sample = ('-rw-r--r--', '1', 'manish', 'manish', '133194', '262144', 'Sep 29 12:46', 'closobo.c')
-
-class Browser:
- def __init__(self, device=None):
- self.widget = gtk.VBox(spacing=4)
-
- scrl_win = gtk.ScrolledWindow()
- scrl_win.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
- self.widget.add(scrl_win)
-
- tv = gtk.TreeView()
- scrl_win.add(tv)
-
- tv.insert_column_with_attributes(-1, 'File', gtk.CellRendererText(),
- text=0)
-
- table = gtk.Table(rows=2, columns=7)
- set_props(table, row_spacing=4,
- column_spacing=4,
- border_width=4)
- self.widget.pack_end(table, expand=False, fill=False)
-
- font = pango.FontDescription('Monospace')
-
- for i in range(0, len(fields)):
- label = gtk.Label(fields[i])
- set_props(label, xalign=0.0)
- table.attach(label, i, i + 1, 0, 1)
-
- label = gtk.Label(sample[i])
- if i == 1 or i == 4 or i == 5:
- set_props(label, xalign=1.0)
- else:
- set_props(label, xalign=0.0)
- table.attach(label, i, i + 1, 1, 2)
-
- label.modify_font(font)
-
-def main():
- import sys
-
- def dummy(*args):
- gtk.main_quit()
-
- window = gtk.Window()
- window.connect('delete_event', dummy)
-
- browser = Browser(sys.argv[1]).widget
- window.add(browser)
-
- window.show_all()
-
- gtk.main()
-
-if __name__ == '__main__':
- main()
Added: trunk/ocfs2console/ocfs2interface/classlabel.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/classlabel.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/classlabel.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,38 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+import re
+
+caps = re.compile('(?!\A)[A-Z][a-z]')
+
+def make_title(m):
+ return ' ' + m.group()
+
+class class_label(object):
+ def __get__(self, obj, cls):
+ return caps.sub(make_title, cls.__name__)
+
+class_label = class_label()
+
+def main():
+ import sys
+
+ cls = type(sys.argv[1], (), {'label': class_label})
+ print cls.label
+
+if __name__ == '__main__':
+ main()
Deleted: trunk/ocfs2console/ocfs2interface/clconfig.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/clconfig.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/clconfig.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -1,536 +0,0 @@
-# OCFS2Console - GUI frontend for OCFS2 management and debugging
-# Copyright (C) 2002, 2005 Oracle. 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
-
-import os
-import types
-
-import gtk
-import gobject
-import pango
-
-from cStringIO import StringIO
-
-import ocfs2
-
-from guiutil import Dialog, set_props, error_box
-from process import Process
-from ipwidget import IPEditor, IPMissing, IPError
-
-CLUSTER_NAME = 'ocfs2'
-CONFIG_FS_PATH = '/config/cluster'
-
-O2CB_INIT = '/etc/init.d/o2cb'
-O2CB_CTL = 'o2cb_ctl'
-
-PORT_DEFAULT = 7777
-PORT_MINIMUM = 1000
-PORT_MAXIMUM = 30000
-
-(
- COLUMN_NEW_NODE,
- COLUMN_NAME,
- COLUMN_NODE,
- COLUMN_IP_ADDR,
- COLUMN_IP_PORT
-) = range(5)
-
-fields = (
- (COLUMN_NEW_NODE, 'Active', None, bool),
- (COLUMN_NAME, 'Name', gtk.Entry, str),
- (COLUMN_NODE, 'Node', None, int),
- (COLUMN_IP_ADDR, 'IP Address', IPEditor, str),
- (COLUMN_IP_PORT, 'IP Port', gtk.SpinButton, str)
-)
-
-typemap = { bool: gobject.TYPE_BOOLEAN }
-
-class ConfigError(Exception):
- pass
-
-class ClusterConfig(Dialog):
- def __init__(self, parent=None):
- self.new_nodes = 0
-
- Dialog.__init__(self, parent=parent, title='Cluster Configurator',
- buttons=(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
- gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
-
- if parent is None:
- self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
-
- frame = gtk.Frame()
- frame.set_shadow_type(gtk.SHADOW_NONE)
- self.vbox.add(frame)
-
- label = gtk.Label()
- label.set_text_with_mnemonic('_Nodes:')
- frame.set_label_widget(label)
-
- hbox = gtk.HBox(spacing=4)
- hbox.set_border_width(4)
- frame.add(hbox)
-
- scrl_win = gtk.ScrolledWindow()
- scrl_win.set_policy(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
- vscrollbar_policy=gtk.POLICY_AUTOMATIC)
- hbox.pack_start(scrl_win)
-
- self.setup_treeview()
- scrl_win.add(self.tv)
-
- vbbox = gtk.VButtonBox()
- set_props(vbbox, layout_style=gtk.BUTTONBOX_START,
- spacing=5,
- border_width=5)
- hbox.pack_end(vbbox, expand=False, fill=False)
-
- self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
- self.add_button.connect('clicked', self.add_node)
- vbbox.add(self.add_button)
-
- try:
- edit_construct_args = {'stock': gtk.STOCK_EDIT}
- except AttributeError:
- edit_construct_args = {'label': '_Edit'}
-
- self.edit_button = gtk.Button(**edit_construct_args)
- self.edit_button.connect('clicked', self.edit_node)
- vbbox.add(self.edit_button)
-
- self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
- self.remove_button.connect('clicked', self.remove_node)
- vbbox.add(self.remove_button)
-
- self.can_edit(False)
- self.can_apply(False)
-
- self.sel = self.tv.get_selection()
- self.sel.connect('changed', self.on_select)
-
- def load_cluster_state(self):
- query_args = '-I -t node -o'
- o2cb_ctl = O2CBCtl(query_args, 'Querying nodes...', self)
- success, output, k = o2cb_ctl.reap()
-
- if not success:
- raise ConfError, output
-
- self.store = gtk.ListStore(*[typemap.get(f[3], f[3]) for f in fields])
-
- def node_compare(store, a, b):
- n1 = store[a][COLUMN_NODE]
- n2 = store[b][COLUMN_NODE]
-
- if n1 < 0 and n2 >= 0:
- return 1
- elif n1 >= 0 and n2 < 0:
- return -1
- else:
- return cmp(abs(n1), abs(n2))
-
- self.store.set_sort_func(COLUMN_NODE, node_compare)
- self.store.set_sort_column_id(COLUMN_NODE, gtk.SORT_ASCENDING)
-
- buffer = StringIO(output)
-
- for line in buffer:
- if line.startswith('#'):
- continue
-
- data = list((None,) * len(fields))
-
- try:
- data[COLUMN_NEW_NODE] = False
-
- (data[COLUMN_NAME],
- cluster,
- data[COLUMN_NODE],
- data[COLUMN_IP_ADDR],
- data[COLUMN_IP_PORT],
- state) = line.split(':')
-
- for i in range(0, len(fields)):
- data[i] = fields[i][3](data[i])
- except ValueError:
- continue
-
- if cluster == CLUSTER_NAME:
- self.store.append(data)
-
- self.new_nodes = 0
-
- self.tv.set_model(self.store)
- self.sel.select_iter(self.store.get_iter_first())
-
- def setup_treeview(self):
- self.tv = gtk.TreeView()
- self.tv.set_size_request(350, 200)
-
- for col, title, widget_type, field_type in fields:
- if col == COLUMN_NEW_NODE:
- self.tv.insert_column_with_data_func(-1, title,
- gtk.CellRendererPixbuf(),
- self.active_set_func)
- elif col == COLUMN_NODE:
- self.tv.insert_column_with_data_func(-1, title,
- gtk.CellRendererText(),
- self.node_set_func)
- else:
- cell_renderer = gtk.CellRendererText()
- cell_renderer.set_property('style', pango.STYLE_ITALIC)
-
- self.tv.insert_column_with_attributes(-1, title,
- cell_renderer,
- text=col,
- style_set=COLUMN_NEW_NODE)
-
- def active_set_func(self, tree_column, cell, model, iter):
- if model[iter][COLUMN_NEW_NODE]:
- stock_id = None
- else:
- stock_id = gtk.STOCK_EXECUTE
-
- cell.set_property('stock_id', stock_id)
-
- def node_set_func(self, tree_column, cell, model, iter):
- if model[iter][COLUMN_NEW_NODE]:
- text = ''
- else:
- text = str(model[iter][COLUMN_NODE])
-
- cell.set_property('text', text)
-
- def on_select(self, sel):
- store, iter = sel.get_selected()
-
- if iter:
- editable = store[iter][COLUMN_NEW_NODE]
- else:
- editable = False
-
- self.can_edit(editable)
-
- def can_edit(self, state):
- self.edit_button.set_sensitive(state)
- self.remove_button.set_sensitive(state)
-
- def can_apply(self, state):
- self.set_response_sensitive(gtk.RESPONSE_APPLY, state)
-
- def add_node(self, b):
- if len(self.store) == ocfs2.MAX_NODES:
- error_box(self, 'Cannot have more than %d nodes in a cluster' %
- ocfs2.MAX_NODES)
- return
-
- node_attrs = self.node_query(title='Add Node')
-
- if node_attrs is None:
- return
-
- self.new_nodes += 1
-
- name, ip_addr, ip_port = node_attrs
-
- iter = self.store.append((True, name, -self.new_nodes,
- ip_addr, ip_port))
- self.sel.select_iter(iter)
-
- self.can_apply(True)
-
- def edit_node(self, b):
- store, iter = self.sel.get_selected()
- attrs = store[iter]
-
- node_attrs = self.node_query(title='Edit Node', defaults=attrs)
-
- if node_attrs is None:
- return
-
- (attrs[COLUMN_NAME],
- attrs[COLUMN_IP_ADDR],
- attrs[COLUMN_IP_PORT]) = node_attrs
-
- def remove_node(self, b):
- store, iter = self.sel.get_selected()
-
- msg = ('Are you sure you want to delete node %s?' %
- store[iter][COLUMN_NAME])
-
- ask = gtk.MessageDialog(parent=self,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
- type=gtk.MESSAGE_QUESTION,
- buttons=gtk.BUTTONS_YES_NO,
- message_format=msg)
-
- response = ask.run()
- ask.destroy()
-
- if response == gtk.RESPONSE_YES:
- del store[iter]
- self.new_nodes -= 1
-
- if self.new_nodes == 0:
- self.can_apply(False)
-
- self.sel.select_iter(self.store.get_iter_first())
-
- def new_node_attrs(self):
- attrs = []
-
- for row in self.store:
- if row[COLUMN_NEW_NODE]:
- attrs.append((row[COLUMN_NAME],
- row[COLUMN_IP_ADDR],
- row[COLUMN_IP_PORT]))
-
- return attrs
-
- def apply_changes(self):
- success = False
-
- for name, ip_addr, ip_port in self.new_node_attrs():
- add_node_args = ('-C', '-n', name, '-t', 'node',
- '-a', 'cluster=%s' % CLUSTER_NAME,
- '-a', 'ip_address=%s' % ip_addr,
- '-a', 'ip_port=%s' % ip_port,
- '-i')
-
- o2cb_ctl = O2CBCtl(add_node_args, 'Adding node %s...' % name, self)
- success, output, k = o2cb_ctl.reap()
-
- if not success:
- error_box(self, '%s\nCould not add node %s' % (output, name))
- break
-
- self.load_cluster_state()
- return success
-
- def node_query(self, title='Node Attributes', defaults=None):
- existing_names = {}
- existing_ip_addrs = {}
-
- for row in self.store:
- name = row[COLUMN_NAME]
- ip_addr = row[COLUMN_IP_ADDR]
-
- existing_names[name] = 1
- existing_ip_addrs[ip_addr] = name
-
- dialog = Dialog(parent=self, title=title,
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OK, gtk.RESPONSE_OK))
-
- dialog.set_alternative_button_order((gtk.RESPONSE_OK,
- gtk.RESPONSE_CANCEL))
-
- dialog.set_default_response(gtk.RESPONSE_OK)
-
- table = gtk.Table(rows=4, columns=2)
- set_props(table, row_spacing=4,
- column_spacing=4,
- border_width=4,
- parent=dialog.vbox)
-
- widgets = []
- row = 0
-
- for col, title, widget_type, field_type in fields:
- if widget_type is None:
- widgets.append(None)
- continue
-
- label = gtk.Label(title + ':')
- set_props(label, xalign=1.0)
- table.attach(label, 0, 1, row, row + 1)
-
- widget = widget_type()
- table.attach(widget, 1, 2, row, row + 1)
-
- if isinstance(widget, gtk.SpinButton):
- widget.set_numeric(True)
-
- adjustment = gtk.Adjustment(PORT_DEFAULT,
- PORT_MINIMUM, PORT_MAXIMUM,
- 1, 100)
-
- widget.set_adjustment(adjustment)
- widget.set_value(PORT_DEFAULT)
-
- widgets.append(widget)
-
- row = row + 1
-
- if defaults:
- for w, d in zip(widgets, defaults):
- if w and d:
- w.set_text(d)
-
- dialog.show_all()
-
- while 1:
- if dialog.run() != gtk.RESPONSE_OK:
- dialog.destroy()
- return None
-
- ip_port = widgets[COLUMN_IP_PORT].get_text()
-
- name = widgets[COLUMN_NAME].get_text()
-
- if not name:
- error_box(dialog, 'Node name not specified')
- continue
-
- try:
- ip_addr = widgets[COLUMN_IP_ADDR].get_text()
- except (IPMissing, IPError), msg:
- error_box(dialog, msg[0])
- continue
-
- if name in existing_names:
- error_box(dialog,
- 'Node %s already exists in the configuration' % name)
- elif ip_addr in existing_ip_addrs:
- error_box(dialog,
- 'IP %s is already assigned to node %s' %
- (ip_addr, existing_ip_addrs[ip_addr]))
- else:
- break
-
- dialog.destroy()
-
- return name, ip_addr, ip_port
-
- def run(self):
- self.show_all()
-
- while 1:
- if Dialog.run(self) == gtk.RESPONSE_APPLY:
- self.apply_changes()
- elif len(self.new_node_attrs()):
- msg = ('New nodes have been created, but they have not been '
- 'applied to the cluster configuration. Do you want to '
- 'apply the changes now?')
-
- ask = gtk.MessageDialog(parent=self,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
- type=gtk.MESSAGE_QUESTION,
- buttons=gtk.BUTTONS_YES_NO,
- message_format=msg)
-
- if ask.run() == gtk.RESPONSE_NO:
- break
- elif self.apply_changes():
- break
- else:
- break
-
-class O2CBProcess(Process):
- def __init__(self, args, desc, parent=None):
- if isinstance(args, types.StringTypes):
- command = '%s %s' % (self.o2cb_program, args)
- else:
- command = (self.o2cb_program,) + tuple(args)
-
- Process.__init__(self, command, self.o2cb_title, desc, parent)
-
-class O2CBCtl(O2CBProcess):
- o2cb_program = O2CB_CTL
- o2cb_title = 'Cluster Control'
-
-class O2CBInit(O2CBProcess):
- o2cb_program = O2CB_INIT
- o2cb_title = 'Cluster Stack'
-
-def cluster_configurator(parent=None):
- if not os.access(CONFIG_FS_PATH, os.F_OK):
- load_args = ('load',)
- o2cb_init = O2CBInit(load_args, 'Starting cluster stack...', parent)
- success, output, k = o2cb_init.reap()
-
- if success:
- msg_type = gtk.MESSAGE_INFO
- msg = ('The cluster stack has been started. It needs to be '
- 'running for any clustering functionality to happen. '
- 'Please run "%s enable" to have it started upon bootup.'
- % o2cb_init.o2cb_program)
- else:
- msg_type = gtk.MESSAGE_WARNING
- msg = ('Could not start cluster stack. This must be resolved '
- 'before any OCFS2 filesystem can be mounted')
-
- info = gtk.MessageDialog(parent=parent,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
- type=msg_type,
- buttons=gtk.BUTTONS_CLOSE,
- message_format=msg)
-
- info.run()
- info.destroy()
-
- if not success:
- return
-
- query_args = '-I -t cluster -n %s -o' % CLUSTER_NAME
- o2cb_ctl = O2CBCtl(query_args, 'Querying cluster...', parent)
- success, output, k = o2cb_ctl.reap()
-
- if not success:
- create_args = '-C -n %s -t cluster -i' % CLUSTER_NAME
- o2cb_ctl = O2CBCtl(query_args, 'Creating cluster...', parent)
- success, output, k = o2cb_ctl.reap()
-
- if not success:
- error_box(parent, '%s\nCould not create cluster' % output)
- return
-
- conf = ClusterConfig(parent)
-
- try:
- conf.load_cluster_state()
- except ConfigError, e:
- error_box(parent, '%s: Could not query cluster configuration' % str(e))
- return
-
- conf.run()
- conf.destroy()
-
- if not os.access(os.path.join(CONFIG_FS_PATH, CLUSTER_NAME), os.F_OK):
- online_args = ('online', CLUSTER_NAME),
- o2cb_init = O2CBInit(online_args, 'Starting OCFS2 cluster...', parent)
- success, output, k = o2cb_init.reap()
-
- if not success:
- msg = ('Could not bring OCFS2 cluster online. This must be '
- 'resolved before any OCFS2 filesystem can be mounted')
-
- info = gtk.MessageDialog(parent=parent,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
- type=gtk.MESSAGE_WARNING,
- buttons=gtk.BUTTONS_CLOSE,
- message_format=msg)
-
- info.run()
- info.destroy()
-
-def main():
- from about import process_gui_args
- process_gui_args()
- cluster_configurator()
-
-if __name__ == '__main__':
- main()
Modified: trunk/ocfs2console/ocfs2interface/console.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/console.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/console.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -17,7 +17,7 @@
import gtk
-from guiutil import set_props, error_box, query_text
+from guiutil import set_props, error_box
from partitionview import PartitionView
from menu import Menu
@@ -25,11 +25,12 @@
from about import about, process_gui_args
from mount import mount, unmount
from format import format_partition
+from fsck import fsck_volume
from tune import tune_label, tune_nodes
from general import General
-from browser import Browser
-from clconfig import cluster_configurator
-from fsck import fsck_volume
+from bosa import Browser
+from nodeconfig import node_config
+from pushconfig import push_config
info_items = (
('General', General),
@@ -136,9 +137,12 @@
def repair(self):
fsck_volume(self, self.pv.get_device(), check=False)
- def clconfig(self):
- cluster_configurator(self)
+ def node_config(self):
+ node_config(self)
+ def push_config(self):
+ push_config(self)
+
def main():
from about import process_gui_args
process_gui_args()
Modified: trunk/ocfs2console/ocfs2interface/format.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/format.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/format.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -17,7 +17,7 @@
import gtk
-import ocfs2
+from plist import partition_list
from guiutil import Dialog, set_props, error_box, format_bytes
from process import Process
@@ -48,7 +48,7 @@
def add_partition(device, fstype):
partitions.append((device, fstype))
- ocfs2.partition_list(add_partition, unmounted=True)
+ partition_list(add_partition, unmounted=True)
if not partitions:
error_box(parent, 'No unmounted partitions')
Added: trunk/ocfs2console/ocfs2interface/fstab.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/fstab.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/fstab.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,100 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+PATH_FSTAB = '/etc/fstab'
+
+class FSTab:
+ def __init__(self):
+ self.refresh()
+
+ def refresh(self):
+ self.entries = []
+
+ try:
+ fstab_file = open(PATH_FSTAB)
+ lines = fstab_file.readlines()
+ fstab_file.close()
+ except IOError:
+ return
+
+ for line in lines:
+ line = line.strip()
+
+ if line.startswith('#'):
+ continue
+
+ try:
+ entry = FSTabEntry(*line.split())
+ except (ValueError, TypeError):
+ continue
+
+ self.entries.append(entry)
+
+ def get(self, device=None, label=None, uuid=None):
+ valid_specs = {}
+
+ if device:
+ valid_specs[device] = True
+
+ if label:
+ spec = 'LABEL=' + label
+ valid_specs[spec] = True
+
+ if uuid:
+ spec = 'UUID=' + uuid.lower()
+ valid_specs[spec] = True
+
+ for entry in self.entries:
+ if entry.spec in valid_specs:
+ return entry
+
+ return None
+
+str_fields = ('spec', 'mountpoint', 'vfstype', 'options')
+int_fields = ('freq', 'passno')
+
+entry_fmt = ('\t'.join(['%%(%s)s' % f for f in str_fields]) + '\t' +
+ '\t'.join(['%%(%s)d' % f for f in int_fields]))
+
+class FSTabEntry:
+ def __init__(self, spec, mountpoint, vfstype, options, freq=0, passno=0):
+ symtab = locals()
+
+ for attr in str_fields:
+ setattr(self, attr, symtab[attr])
+
+ for attr in int_fields:
+ setattr(self, attr, int(symtab[attr]))
+
+ if self.spec.startswith('UUID='):
+ self.spec = 'UUID=' + self.spec[5:].lower()
+
+ def __str__(self):
+ return entry_fmt % self.__dict__
+
+ def __repr__(self):
+ return "<FSTabEntry: '%s'>" % str(self)
+
+def main():
+ import sys
+ spec = sys.argv[1]
+
+ fstab = FSTab()
+ print fstab.get(device=spec, label=spec, uuid=spec)
+
+if __name__ == '__main__':
+ main()
Modified: trunk/ocfs2console/ocfs2interface/general.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/general.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/general.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -19,80 +19,117 @@
import ocfs2
+from classlabel import class_label
from guiutil import set_props, format_bytes
-fields = (
- ('Version', 'version'),
- ('Label', 's_label'),
- ('UUID', 's_uuid'),
- ('Maximum Nodes', 's_max_nodes'),
- ('Cluster Size', 's_clustersize_bits'),
- ('Block Size', 's_blocksize_bits'),
- ('Free Space', 'freebits'),
- ('Total Space', 'numbits'),
-)
+EMPTY_TEXT = 'N/A'
-class General:
+class Field(object):
+ def __init__(self, fs, super, dinode):
+ self.fs = fs
+ self.super = super
+ self.dinode = dinode
+
+ def get_text(self):
+ if self.super:
+ return self.real_get_text()
+ else:
+ return EMPTY_TEXT
+
+ text = property(get_text)
+
+ label = class_label
+
+class Version(Field):
+ def real_get_text(self):
+ return '%d.%d' % (self.super.s_major_rev_level,
+ self.super.s_minor_rev_level)
+
+class Label(Field):
+ def real_get_text(self):
+ text = self.super.s_label
+
+ if not text:
+ text = EMPTY_TEXT
+
+ return text
+
+class UUID(Field):
+ def real_get_text(self):
+ return self.super.uuid_unparsed
+
+class MaximumNodes(Field):
+ def real_get_text(self):
+ return str(self.super.s_max_nodes)
+
+class FSSize(Field):
+ def real_get_text(self):
+ return format_bytes(getattr(self.fs, self.member))
+
+class ClusterSize(FSSize):
+ member = 'fs_clustersize'
+
+class BlockSize(FSSize):
+ member = 'fs_blocksize'
+
+class Space(Field):
+ def real_get_text(self):
+ if self.dinode:
+ block_bits = self.fs.fs_clustersize >> self.super.s_blocksize_bits
+ bytes = self.get_bits() * block_bits * self.fs.fs_blocksize
+ return format_bytes(bytes, show_bytes=True)
+ else:
+ return EMPTY_TEXT
+
+class FreeSpace(Space):
+ def get_bits(self):
+ return self.dinode.i_total - self.dinode.i_used
+
+class TotalSpace(Space):
+ def get_bits(self):
+ return self.dinode.i_total
+
+fields = (Version, Label, UUID, MaximumNodes,
+ ClusterSize, BlockSize,
+ FreeSpace, TotalSpace)
+
+class General(gtk.Table):
def __init__(self, device=None):
- self.widget = gtk.Table(rows=5, columns=2)
+ gtk.Table.__init__(self, rows=5, columns=2)
- set_props(self.widget, row_spacing=4,
- column_spacing=4,
- border_width=4)
+ set_props(self, row_spacing=4,
+ column_spacing=4,
+ border_width=4)
- super = None
- numbits = 0
+ fs = super = dinode = None
if device:
try:
- super = ocfs2.get_super(device)
- numbits, freebits = ocfs2.get_space_usage(device)
+ fs = ocfs2.Filesystem(device)
+ super = fs.fs_super
- clustersize = 1L << super.s_clustersize_bits
- blocksize = 1L << super.s_blocksize_bits
+ blkno = fs.lookup_system_inode(ocfs2.GLOBAL_BITMAP_SYSTEM_INODE)
+ dinode = fs.read_cached_inode(blkno)
except ocfs2.error:
pass
- self.pos = 0
+ row = 0
- for desc, member in fields:
- if super:
- if member == 'version':
- val = '%d.%d' % super[0:2]
- elif member == 's_label':
- val = super.s_label
- if not val:
- val = 'N/A'
- elif member == 'numbits' or member == 'freebits':
- if numbits:
- blocks = (vars()[member] *
- (clustersize >> super.s_blocksize_bits))
- val = format_bytes(blocks * blocksize, show_bytes=True)
- else:
- val = 'N/A'
- else:
- val = getattr(super, member)
+ for field_type in fields:
+ field = field_type(fs, super, dinode)
- if member.endswith('_bits'):
- val = format_bytes(1 << val)
- else:
- val = 'N/A'
+ label = gtk.Label(field.label + ':')
+ set_props(label, xalign=1.0)
+ self.attach(label, 0, 1, row, row + 1,
+ xoptions=gtk.FILL, yoptions=gtk.FILL)
- self.add_field(desc, val)
+ label = gtk.Label(field.text)
+ set_props(label, xalign=0.0)
+ self.attach(label, 1, 2, row, row + 1,
+ xoptions=gtk.FILL, yoptions=gtk.FILL)
- def add_field(self, desc, val):
- label = gtk.Label(desc + ':')
- set_props(label, xalign=1.0)
- self.widget.attach(label, 0, 1, self.pos, self.pos + 1,
- xoptions=gtk.FILL, yoptions=gtk.FILL)
+ row += 1
- label = gtk.Label(str(val))
- set_props(label, xalign=0.0)
- self.widget.attach(label, 1, 2, self.pos, self.pos + 1,
- xoptions=gtk.FILL, yoptions=gtk.FILL)
-
- self.pos += 1
-
def main():
import sys
@@ -102,7 +139,7 @@
window = gtk.Window()
window.connect('delete_event', dummy)
- general = General(sys.argv[1]).widget
+ general = General(sys.argv[1])
window.add(general)
window.show_all()
Added: trunk/ocfs2console/ocfs2interface/gidlemodule.c
===================================================================
--- trunk/ocfs2console/ocfs2interface/gidlemodule.c 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/gidlemodule.c 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,43 @@
+/*
+ * gidlemodule.c
+ *
+ * Fuller interface to GLIB's idle sources.
+ *
+ * Copyright (C) 2005 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <Python.h>
+
+#include <glib.h>
+
+static PyMethodDef gidle_methods[] = {
+ {NULL, NULL} /* sentinel */
+};
+
+void
+initgidle (void)
+{
+ PyObject *m;
+
+ m = Py_InitModule ("gidle", gidle_methods);
+
+ if (PyErr_Occurred ())
+ Py_FatalError ("can't initialize module gidle");
+}
Modified: trunk/ocfs2console/ocfs2interface/guiutil.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/guiutil.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/guiutil.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -50,37 +50,6 @@
dialog.run()
dialog.destroy()
-def query_text(parent, prompt):
- dialog = gtk.Dialog(parent=parent,
- flags=gtk.DIALOG_DESTROY_WITH_PARENT,
- buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
- gtk.STOCK_OK, gtk.RESPONSE_OK))
-
- table = gtk.Table(rows=1, columns=2)
- set_props(table, row_spacing=4,
- column_spacing=4,
- border_width=4,
- parent=dialog.vbox)
-
- label = gtk.Label(prompt + ':')
- set_props(label, xalign=1.0)
- table.attach(label, 0, 1, 0, 1)
-
- entry = gtk.Entry()
- entry.set_activates_default(True)
- table.attach(entry, 1, 2, 0, 1)
-
- dialog.show_all()
-
- if dialog.run() == gtk.RESPONSE_OK:
- text = entry.get_text()
- else:
- text = None
-
- dialog.destroy()
-
- return text
-
def make_callback(obj, callback, sub_callback):
cb = getattr(obj, callback)
Added: trunk/ocfs2console/ocfs2interface/ls.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/ls.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/ls.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,163 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+import stat
+import pwd
+import grp
+import time
+
+import ocfs2
+
+from classlabel import class_label
+
+class Field(object):
+ def __init__(self, dentry, dinode):
+ self.dentry = dentry
+ self.dinode = dinode
+
+ def real_get_text(self):
+ return str(getattr(self.dinode, self.dinode_member))
+
+ def get_text(self):
+ return self.real_get_text()
+
+ text = property(get_text)
+
+ label = class_label
+
+ right_justify = False
+
+file_type = {
+ ocfs2.FT_UNKNOWN : '?',
+ ocfs2.FT_REG_FILE : '-',
+ ocfs2.FT_DIR : 'd',
+ ocfs2.FT_CHRDEV : 'c',
+ ocfs2.FT_BLKDEV : 'b',
+ ocfs2.FT_FIFO : 'p',
+ ocfs2.FT_SOCK : 's',
+ ocfs2.FT_SYMLINK : 'l',
+}
+
+class Mode(Field):
+ def real_get_text(self):
+ text = ['-'] * 10
+
+ text[0] = file_type[self.dentry.file_type]
+
+ mode = self.dinode.i_mode
+ pos = 0
+
+ for t in 'USR', 'GRP', 'OTH':
+ for b in 'R', 'W', 'X':
+ pos += 1
+
+ if mode & getattr(stat, 'S_I%s%s' % (b, t)):
+ text[pos] = b.lower()
+
+ pos = 0
+
+ for t, b in (('UID', 'S'), ('GID', 'S'), ('VTX', 'T')):
+ pos += 3
+
+ if mode & getattr(stat, 'S_IS%s' % t):
+ if text[pos] == 'x':
+ text[pos] = b
+ else:
+ text[pos] = b.lower()
+
+ return ''.join(text)
+
+class Links(Field):
+ label = '# Links'
+ dinode_member = 'i_links_count'
+ right_justify = True
+
+class ID2Name(Field):
+ def real_get_text(self):
+ idnum = getattr(self.dinode, self.dinode_member)
+
+ try:
+ return self.get_name(idnum)[0]
+ except KeyError:
+ return str(idnum)
+
+class Owner(ID2Name):
+ dinode_member = 'i_uid'
+ get_name = pwd.getpwuid
+
+class Group(ID2Name):
+ dinode_member = 'i_gid'
+ get_name = grp.getgrgid
+
+class Size(Field):
+ dinode_member = 'i_size'
+ right_justify = True
+
+class AllocSize(Field):
+ right_justify = True
+
+ def real_get_text(self):
+ return str(self.dinode.i_clusters * self.dinode.fs.fs_clustersize)
+
+class Timestamp(Field):
+ # Ported from GNU coreutils ls
+ time_formats = ('%b %e %Y', '%b %e %H:%M')
+
+ def real_get_text(self):
+ when = self.dinode.i_mtime
+ when_local = time.localtime(when)
+
+ current_time = long(time.time())
+
+ six_months_ago = current_time - 31556952 / 2
+ recent = (six_months_ago <= when and when < current_time)
+ fmt = self.time_formats[recent]
+
+ return time.strftime(fmt, when_local)
+
+class Name(Field):
+ def real_get_text(self):
+ return self.dentry.name
+
+fields = (Mode, Links, Owner, Group, Size, AllocSize, Timestamp, Name)
+
+def main():
+ import sys
+
+ fs = ocfs2.Filesystem(sys.argv[1])
+
+ dentries = []
+
+ def walk(dentry, offset, blocksize):
+ dentries.append(dentry)
+
+ fs.dir_iterate(walk)
+
+ try:
+ dentry = dentries[int(sys.argv[2])]
+ except (IndexError, ValueError):
+ dentry = dentries[0]
+
+ dinode = fs.read_cached_inode(dentry.inode)
+
+ for field_type in fields:
+ field = field_type(dentry, dinode)
+
+ print '%s: %s' % (field.label, field.text)
+
+if __name__ == '__main__':
+ main()
Modified: trunk/ocfs2console/ocfs2interface/menu.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/menu.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/menu.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -41,6 +41,12 @@
stock_about)
)
+cluster_menu_data = (
+ ('/_Cluster', None, None, 0, '<Branch>'),
+ ('/Cluster/_Configure Nodes...', None, 'node_config'),
+ ('/Cluster/_Propagate Configuration...', None, 'push_config')
+)
+
if fsck_ok:
task_menu_fsck_data = (
('/Tasks/Chec_k...', '<control>K', 'check', 'refresh',
@@ -61,15 +67,13 @@
task_menu_tail_data = (
('/Tasks/Change _Label...', None, 'relabel', 'refresh',
UNMOUNTED_ONLY),
- ('/Tasks/Edit _Node Count...', None, 'node_num', 'refresh',
+ ('/Tasks/_Edit Node Count...', None, 'node_num', 'refresh',
UNMOUNTED_ONLY),
- ('/Tasks/---', None, None, 0, '<Separator>'),
- ('/Tasks/_Cluster Config...', None, 'clconfig')
)
task_menu_data = task_menu_head_data + task_menu_fsck_data + task_menu_tail_data
-menu_data = file_menu_data + task_menu_data + help_menu_data
+menu_data = file_menu_data + cluster_menu_data + task_menu_data + help_menu_data
class Menu:
def __init__(self, window):
Modified: trunk/ocfs2console/ocfs2interface/mount.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/mount.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/mount.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -17,18 +17,26 @@
import gtk
-from guiutil import set_props, error_box, query_text
+import ocfs2
+from guiutil import set_props, error_box
+
+from fstab import FSTab
from process import Process
def mount(parent, device):
- mountpoint = query_text(parent, 'Mountpoint')
+ mountpoint, options = query_mount(parent, device)
+
if not mountpoint:
return None
command = ('mount', '-t', 'ocfs2', device, mountpoint)
- p = Process(command, 'Mount', 'Mounting...', parent)
+ if options:
+ command = list(command)
+ command[1:1] = ('-o', options)
+
+ p = Process(command, 'Mount', 'Mounting...', parent, spin_now=True)
success, output, killed = p.reap()
if not success:
@@ -57,6 +65,83 @@
else:
error_box(parent, '%s: Could not unmount %s mounted on %s' %
(output, device, mountpoint))
+
+def query_mount(parent, device):
+ default_mountpoint, default_options = get_defaults(device)
+
+ dialog = gtk.Dialog(parent=parent,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OK, gtk.RESPONSE_OK))
+
+ table = gtk.Table(rows=2, columns=2)
+ set_props(table, row_spacing=6,
+ column_spacing=6,
+ border_width=6,
+ parent=dialog.vbox)
+
+ def text_changed(entry):
+ text = entry.get_text()
+ valid = len(text) > 1 and text.startswith('/')
+ dialog.set_response_sensitive(gtk.RESPONSE_OK, valid)
+
+ mountpoint = gtk.Entry()
+ mountpoint.connect('changed', text_changed)
+
+ mountpoint.set_text(default_mountpoint)
+ text_changed(mountpoint)
+
+ options = gtk.Entry()
+ options.set_text(default_options)
+
+ row = 0
+ for prompt, entry in (('_Mountpoint', mountpoint),
+ ('O_ptions', options)):
+ label = gtk.Label()
+ label.set_text_with_mnemonic(prompt + ':')
+ set_props(label, xalign=0.0)
+ table.attach(label, 0, 1, row, row + 1)
+
+ entry.set_activates_default(True)
+ label.set_mnemonic_widget(entry)
+ table.attach(entry, 1, 2, row, row + 1)
+
+ row = row + 1
+
+ dialog.show_all()
+
+ if dialog.run() == gtk.RESPONSE_OK:
+ mount_params = mountpoint.get_text(), options.get_text()
+ else:
+ mount_params = None, None
+
+ dialog.destroy()
+
+ return mount_params
+
+def get_defaults(device):
+ label, uuid = get_ocfs2_id(device)
+
+ fstab = FSTab()
+ entry = fstab.get(device=device, label=label, uuid=uuid)
+
+ if entry and entry.vfstype == 'ocfs2':
+ return entry.mountpoint, entry.options
+ else:
+ return '', ''
+
+def get_ocfs2_id(device):
+ try:
+ fs = ocfs2.Filesystem(device)
+ super = fs.fs_super
+
+ label = super.s_label
+ uuid = super.uuid_unparsed
+ except ocfs2.error:
+ label = uuid = None
+
+ return (label, uuid)
+
def main():
import sys
Copied: trunk/ocfs2console/ocfs2interface/nodeconfig.py (from rev 789, trunk/ocfs2console/ocfs2interface/clconfig.py)
===================================================================
--- trunk/ocfs2console/ocfs2interface/clconfig.py 2005-04-06 02:39:39 UTC (rev 789)
+++ trunk/ocfs2console/ocfs2interface/nodeconfig.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,549 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2002, 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+import os
+import types
+
+import gtk
+import gobject
+import pango
+
+from cStringIO import StringIO
+
+import ocfs2
+import o2cb
+
+from guiutil import Dialog, set_props, error_box
+from process import Process
+from ipwidget import IPEditor, IPMissing, IPError
+
+CLUSTER_NAME = 'ocfs2'
+
+O2CB_INIT = '/etc/init.d/o2cb'
+O2CB_CTL = 'o2cb_ctl'
+
+PORT_DEFAULT = 7777
+PORT_MINIMUM = 1000
+PORT_MAXIMUM = 30000
+
+(
+ COLUMN_NEW_NODE,
+ COLUMN_NAME,
+ COLUMN_NODE,
+ COLUMN_IP_ADDR,
+ COLUMN_IP_PORT
+) = range(5)
+
+fields = (
+ (COLUMN_NEW_NODE, 'Active', None, bool),
+ (COLUMN_NAME, 'Name', gtk.Entry, str),
+ (COLUMN_NODE, 'Node', None, int),
+ (COLUMN_IP_ADDR, 'IP Address', IPEditor, str),
+ (COLUMN_IP_PORT, 'IP Port', gtk.SpinButton, str)
+)
+
+# Hate your ancient distros shipping old pygtks
+typemap = { bool: gobject.TYPE_BOOLEAN }
+
+class ConfigError(Exception):
+ pass
+
+class ClusterConfig(Dialog):
+ def __init__(self, parent=None):
+ self.new_nodes = 0
+
+ Dialog.__init__(self, parent=parent, title='Node Configuration',
+ buttons=(gtk.STOCK_APPLY, gtk.RESPONSE_APPLY,
+ gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
+
+ if parent is None:
+ self.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_NORMAL)
+
+ frame = gtk.Frame()
+ frame.set_shadow_type(gtk.SHADOW_NONE)
+ self.vbox.add(frame)
+
+ label = gtk.Label()
+ label.set_text_with_mnemonic('_Nodes:')
+ frame.set_label_widget(label)
+
+ hbox = gtk.HBox(spacing=4)
+ hbox.set_border_width(4)
+ frame.add(hbox)
+
+ scrl_win = gtk.ScrolledWindow()
+ scrl_win.set_policy(hscrollbar_policy=gtk.POLICY_AUTOMATIC,
+ vscrollbar_policy=gtk.POLICY_AUTOMATIC)
+ hbox.pack_start(scrl_win)
+
+ self.setup_treeview()
+ label.set_mnemonic_widget(self.tv)
+ scrl_win.add(self.tv)
+
+ vbbox = gtk.VButtonBox()
+ set_props(vbbox, layout_style=gtk.BUTTONBOX_START,
+ spacing=5,
+ border_width=5)
+ hbox.pack_end(vbbox, expand=False, fill=False)
+
+ self.add_button = gtk.Button(stock=gtk.STOCK_ADD)
+ self.add_button.connect('clicked', self.add_node)
+ vbbox.add(self.add_button)
+
+ try:
+ edit_construct_args = {'stock': gtk.STOCK_EDIT}
+ except AttributeError:
+ edit_construct_args = {'label': '_Edit'}
+
+ self.edit_button = gtk.Button(**edit_construct_args)
+ self.edit_button.connect('clicked', self.edit_node)
+ vbbox.add(self.edit_button)
+
+ self.remove_button = gtk.Button(stock=gtk.STOCK_REMOVE)
+ self.remove_button.connect('clicked', self.remove_node)
+ vbbox.add(self.remove_button)
+
+ self.can_edit(False)
+ self.can_apply(False)
+
+ self.sel = self.tv.get_selection()
+ self.sel.connect('changed', self.on_select)
+
+ def load_cluster_state(self):
+ query_args = '-I -t node -o'
+ o2cb_ctl = O2CBCtl(query_args, 'Querying nodes...', self)
+ success, output, k = o2cb_ctl.reap()
+
+ if not success:
+ raise ConfError, output
+
+ self.store = gtk.ListStore(*[typemap.get(f[3], f[3]) for f in fields])
+
+ def node_compare(store, a, b):
+ n1 = store[a][COLUMN_NODE]
+ n2 = store[b][COLUMN_NODE]
+
+ if n1 < 0 and n2 >= 0:
+ return 1
+ elif n1 >= 0 and n2 < 0:
+ return -1
+ else:
+ return cmp(abs(n1), abs(n2))
+
+ self.store.set_sort_func(COLUMN_NODE, node_compare)
+ self.store.set_sort_column_id(COLUMN_NODE, gtk.SORT_ASCENDING)
+
+ buffer = StringIO(output)
+
+ for line in buffer:
+ if line.startswith('#'):
+ continue
+
+ data = list((None,) * len(fields))
+
+ try:
+ data[COLUMN_NEW_NODE] = False
+
+ (data[COLUMN_NAME],
+ cluster,
+ data[COLUMN_NODE],
+ data[COLUMN_IP_ADDR],
+ data[COLUMN_IP_PORT],
+ state) = line.split(':')
+
+ for i in range(0, len(fields)):
+ data[i] = fields[i][3](data[i])
+ except ValueError:
+ continue
+
+ if cluster == CLUSTER_NAME:
+ self.store.append(data)
+
+ self.new_nodes = 0
+
+ self.tv.set_model(self.store)
+ self.sel.select_iter(self.store.get_iter_first())
+
+ def setup_treeview(self):
+ self.tv = gtk.TreeView()
+ self.tv.set_size_request(350, 200)
+
+ for col, title, widget_type, field_type in fields:
+ if col == COLUMN_NEW_NODE:
+ self.tv.insert_column_with_data_func(-1, title,
+ gtk.CellRendererPixbuf(),
+ self.active_set_func)
+ elif col == COLUMN_NODE:
+ self.tv.insert_column_with_data_func(-1, title,
+ gtk.CellRendererText(),
+ self.node_set_func)
+ else:
+ cell_renderer = gtk.CellRendererText()
+ cell_renderer.set_property('style', pango.STYLE_ITALIC)
+
+ self.tv.insert_column_with_attributes(-1, title,
+ cell_renderer,
+ text=col,
+ style_set=COLUMN_NEW_NODE)
+
+ def active_set_func(self, tree_column, cell, model, iter):
+ if model[iter][COLUMN_NEW_NODE]:
+ stock_id = None
+ else:
+ stock_id = gtk.STOCK_EXECUTE
+
+ cell.set_property('stock_id', stock_id)
+
+ def node_set_func(self, tree_column, cell, model, iter):
+ if model[iter][COLUMN_NEW_NODE]:
+ text = ''
+ else:
+ text = str(model[iter][COLUMN_NODE])
+
+ cell.set_property('text', text)
+
+ def on_select(self, sel):
+ store, iter = sel.get_selected()
+
+ if iter:
+ editable = store[iter][COLUMN_NEW_NODE]
+ else:
+ editable = False
+
+ self.can_edit(editable)
+
+ def can_edit(self, state):
+ self.edit_button.set_sensitive(state)
+ self.remove_button.set_sensitive(state)
+
+ def can_apply(self, state):
+ self.set_response_sensitive(gtk.RESPONSE_APPLY, state)
+
+ def add_node(self, b):
+ if len(self.store) == ocfs2.MAX_NODES:
+ error_box(self, 'Cannot have more than %d nodes in a cluster' %
+ ocfs2.MAX_NODES)
+ return
+
+ node_attrs = self.node_query(title='Add Node')
+
+ if node_attrs is None:
+ return
+
+ self.new_nodes += 1
+
+ name, ip_addr, ip_port = node_attrs
+
+ iter = self.store.append((True, name, -self.new_nodes,
+ ip_addr, ip_port))
+ self.sel.select_iter(iter)
+
+ self.can_apply(True)
+
+ def edit_node(self, b):
+ store, iter = self.sel.get_selected()
+ attrs = store[iter]
+
+ node_attrs = self.node_query(title='Edit Node', defaults=attrs)
+
+ if node_attrs is None:
+ return
+
+ (attrs[COLUMN_NAME],
+ attrs[COLUMN_IP_ADDR],
+ attrs[COLUMN_IP_PORT]) = node_attrs
+
+ def remove_node(self, b):
+ store, iter = self.sel.get_selected()
+
+ msg = ('Are you sure you want to delete node %s?' %
+ store[iter][COLUMN_NAME])
+
+ ask = gtk.MessageDialog(parent=self,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ type=gtk.MESSAGE_QUESTION,
+ buttons=gtk.BUTTONS_YES_NO,
+ message_format=msg)
+
+ response = ask.run()
+ ask.destroy()
+
+ if response == gtk.RESPONSE_YES:
+ del store[iter]
+ self.new_nodes -= 1
+
+ if self.new_nodes == 0:
+ self.can_apply(False)
+
+ self.sel.select_iter(self.store.get_iter_first())
+
+ def new_node_attrs(self):
+ attrs = []
+
+ for row in self.store:
+ if row[COLUMN_NEW_NODE]:
+ attrs.append((row[COLUMN_NAME],
+ row[COLUMN_IP_ADDR],
+ row[COLUMN_IP_PORT]))
+
+ return attrs
+
+ def apply_changes(self):
+ success = False
+
+ for name, ip_addr, ip_port in self.new_node_attrs():
+ add_node_args = ('-C', '-n', name, '-t', 'node',
+ '-a', 'cluster=%s' % CLUSTER_NAME,
+ '-a', 'ip_address=%s' % ip_addr,
+ '-a', 'ip_port=%s' % ip_port,
+ '-i')
+
+ o2cb_ctl = O2CBCtl(add_node_args, 'Adding node %s...' % name, self)
+ success, output, k = o2cb_ctl.reap()
+
+ if not success:
+ error_box(self, '%s\nCould not add node %s' % (output, name))
+ break
+
+ self.load_cluster_state()
+ return success
+
+ def node_query(self, title='Node Attributes', defaults=None):
+ existing_names = {}
+ existing_ip_addrs = {}
+
+ for row in self.store:
+ name = row[COLUMN_NAME]
+ ip_addr = row[COLUMN_IP_ADDR]
+
+ existing_names[name] = 1
+ existing_ip_addrs[ip_addr] = name
+
+ dialog = Dialog(parent=self, title=title,
+ buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
+ gtk.STOCK_OK, gtk.RESPONSE_OK))
+
+ dialog.set_alternative_button_order((gtk.RESPONSE_OK,
+ gtk.RESPONSE_CANCEL))
+
+ dialog.set_default_response(gtk.RESPONSE_OK)
+
+ table = gtk.Table(rows=4, columns=2)
+ set_props(table, row_spacing=4,
+ column_spacing=4,
+ border_width=4,
+ parent=dialog.vbox)
+
+ widgets = []
+ row = 0
+
+ for col, title, widget_type, field_type in fields:
+ if widget_type is None:
+ widgets.append(None)
+ continue
+
+ label = gtk.Label(title + ':')
+ set_props(label, xalign=1.0)
+ table.attach(label, 0, 1, row, row + 1)
+
+ widget = widget_type()
+ table.attach(widget, 1, 2, row, row + 1)
+
+ if col == COLUMN_NAME:
+ #XXX widget.set_max_length(ocfs2.MAX_NODE_NAME_LENGTH)
+ pass
+ elif col == COLUMN_IP_PORT:
+ widget.set_numeric(True)
+
+ adjustment = gtk.Adjustment(PORT_DEFAULT,
+ PORT_MINIMUM, PORT_MAXIMUM,
+ 1, 100)
+
+ widget.set_adjustment(adjustment)
+ widget.set_value(PORT_DEFAULT)
+
+ widgets.append(widget)
+
+ row = row + 1
+
+ if defaults:
+ for w, d in zip(widgets, defaults):
+ if w and d:
+ w.set_text(d)
+
+ dialog.show_all()
+
+ while 1:
+ if dialog.run() != gtk.RESPONSE_OK:
+ dialog.destroy()
+ return None
+
+ ip_port = widgets[COLUMN_IP_PORT].get_text()
+
+ name = widgets[COLUMN_NAME].get_text()
+
+ if not name:
+ error_box(dialog, 'Node name not specified')
+ continue
+
+ try:
+ ip_addr = widgets[COLUMN_IP_ADDR].get_text()
+ except (IPMissing, IPError), msg:
+ error_box(dialog, msg[0])
+ continue
+
+ if name in existing_names:
+ error_box(dialog,
+ 'Node %s already exists in the configuration' % name)
+ elif ip_addr in existing_ip_addrs:
+ error_box(dialog,
+ 'IP %s is already assigned to node %s' %
+ (ip_addr, existing_ip_addrs[ip_addr]))
+ else:
+ break
+
+ dialog.destroy()
+
+ return name, ip_addr, ip_port
+
+ def run(self):
+ self.show_all()
+
+ while 1:
+ if Dialog.run(self) == gtk.RESPONSE_APPLY:
+ self.apply_changes()
+ elif len(self.new_node_attrs()):
+ msg = ('New nodes have been created, but they have not been '
+ 'applied to the cluster configuration. Do you want to '
+ 'apply the changes now?')
+
+ ask = gtk.MessageDialog(parent=self,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ type=gtk.MESSAGE_QUESTION,
+ buttons=gtk.BUTTONS_YES_NO,
+ message_format=msg)
+
+ if ask.run() == gtk.RESPONSE_NO:
+ break
+ elif self.apply_changes():
+ break
+ else:
+ break
+
+class O2CBProcess(Process):
+ def __init__(self, args, desc, parent=None):
+ if isinstance(args, types.StringTypes):
+ command = '%s %s' % (self.o2cb_program, args)
+ else:
+ command = (self.o2cb_program,) + tuple(args)
+
+ Process.__init__(self, command, self.o2cb_title, desc, parent)
+
+class O2CBCtl(O2CBProcess):
+ o2cb_program = O2CB_CTL
+ o2cb_title = 'Cluster Control'
+
+class O2CBInit(O2CBProcess):
+ o2cb_program = O2CB_INIT
+ o2cb_title = 'Cluster Stack'
+
+def node_config(parent=None):
+ if not os.access(o2cb.FORMAT_CLUSTER_DIR, os.F_OK):
+ load_args = ('load',)
+ o2cb_init = O2CBInit(load_args, 'Starting cluster stack...', parent)
+ success, output, k = o2cb_init.reap()
+
+ if success:
+ msg_type = gtk.MESSAGE_INFO
+ msg = ('The cluster stack has been started. It needs to be '
+ 'running for any clustering functionality to happen. '
+ 'Please run "%s enable" to have it started upon bootup.'
+ % o2cb_init.o2cb_program)
+ else:
+ msg_type = gtk.MESSAGE_WARNING
+ msg = ('Could not start cluster stack. This must be resolved '
+ 'before any OCFS2 filesystem can be mounted')
+
+ info = gtk.MessageDialog(parent=parent,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ type=msg_type,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format=msg)
+
+ info.run()
+ info.destroy()
+
+ if not success:
+ return
+
+# msg = ('Currently, the clustering software can only handle '
+# 'one cluster at a time. To keep things simple, you '
+# 'are expected to name your cluster "%s". Your '
+# 'configuration file contains a cluster named "%s". '
+# 'Please rename or delete that cluster, and restart '
+# 'the cluster stack before trying to run the cluster '
+# 'configurator again.' % (CLUSTER_NAME, cluster))
+
+ query_args = '-I -t cluster -n %s -o' % CLUSTER_NAME
+ o2cb_ctl = O2CBCtl(query_args, 'Querying cluster...', parent)
+ success, output, k = o2cb_ctl.reap()
+
+ if not success:
+ create_args = '-C -n %s -t cluster -i' % CLUSTER_NAME
+ o2cb_ctl = O2CBCtl(query_args, 'Creating cluster...', parent)
+ success, output, k = o2cb_ctl.reap()
+
+ if not success:
+ error_box(parent, '%s\nCould not create cluster' % output)
+ return
+
+ conf = ClusterConfig(parent)
+
+ try:
+ conf.load_cluster_state()
+ except ConfigError, e:
+ error_box(parent, '%s: Could not query cluster configuration' % str(e))
+ return
+
+ conf.run()
+ conf.destroy()
+
+ if not os.access(o2cb.FORMAT_CLUSTER % CLUSTER_NAME, os.F_OK):
+ online_args = ('online', CLUSTER_NAME),
+ o2cb_init = O2CBInit(online_args, 'Starting OCFS2 cluster...', parent)
+ success, output, k = o2cb_init.reap()
+
+ if not success:
+ msg = ('Could not bring OCFS2 cluster online. This must be '
+ 'resolved before any OCFS2 filesystem can be mounted')
+
+ info = gtk.MessageDialog(parent=parent,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ type=gtk.MESSAGE_WARNING,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format=msg)
+
+ info.run()
+ info.destroy()
+
+def main():
+ from about import process_gui_args
+ process_gui_args()
+ node_config()
+
+if __name__ == '__main__':
+ main()
Added: trunk/ocfs2console/ocfs2interface/o2cbmodule.c
===================================================================
--- trunk/ocfs2console/ocfs2interface/o2cbmodule.c 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/o2cbmodule.c 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,554 @@
+/*
+ * o2cbmodule.c
+ *
+ * O2CB python binding.
+ *
+ * Copyright (C) 2005 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "o2cb.h"
+#include "o2cb_abi.h"
+
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *name;
+} O2CBObject;
+
+#define O2CB_OBJECT_NAME(obj) (((O2CBObject *) (obj))->name)
+
+typedef O2CBObject Cluster;
+
+typedef struct {
+ O2CBObject object;
+ Cluster *cluster;
+} Node;
+
+
+static PyObject *o2cb_error;
+
+#define CHECK_ERROR(call) do { \
+ ret = call; \
+ if (ret) \
+ { \
+ PyErr_SetString (o2cb_error, error_message (ret)); \
+ return NULL; \
+ } \
+} while (0)
+
+
+static void
+o2cb_object_dealloc (O2CBObject *self)
+{
+ Py_XDECREF (self->name);
+ PyObject_DEL (self);
+}
+
+static PyObject *
+o2cb_object_repr (O2CBObject *self,
+ const char *type_name)
+{
+ return PyString_FromFormat ("<o2cb.%s '%s'>", type_name,
+ PyString_AS_STRING (self->name));
+}
+
+static PyMemberDef o2cb_object_members[] = {
+ {"name", T_OBJECT, offsetof (O2CBObject, name), RO},
+ {0}
+};
+
+static PyObject *
+o2cb_object_new (O2CBObject *self,
+ const char *name)
+{
+ if (self == NULL)
+ return NULL;
+
+ self->name = PyString_FromString (name);
+
+ if (self->name == NULL)
+ {
+ PyObject_DEL (self);
+ return NULL;
+ }
+
+ return (PyObject *) self;
+}
+
+static PyObject *
+node_number (Node *self, void *closure)
+{
+ errcode_t ret;
+ uint16_t node_num;
+
+ CHECK_ERROR (o2cb_get_node_num (PyString_AS_STRING (self->cluster->name),
+ PyString_AS_STRING (O2CB_OBJECT_NAME (self)),
+ &node_num));
+
+ return PyInt_FromLong (node_num);
+}
+
+static PyGetSetDef node_getsets[] = {
+ {"number", (getter)node_number, (setter)0},
+ {NULL}
+};
+
+static void
+node_dealloc (Node *self)
+{
+ Py_XDECREF (self->cluster);
+ o2cb_object_dealloc ((O2CBObject *) self);
+}
+
+static PyObject *
+node_repr (Node *self)
+{
+ return o2cb_object_repr ((O2CBObject *) self, "Node");
+}
+
+static PyTypeObject Node_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "o2cb.Node", /* tp_name */
+ sizeof(Node), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)node_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)node_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ o2cb_object_members, /* tp_members */
+ node_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ 0, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static PyObject *
+node_new (Cluster *cluster,
+ const char *name)
+{
+ Node *self;
+
+ self = PyObject_NEW (Node, &Node_Type);
+
+ self = (Node *) o2cb_object_new ((O2CBObject *) self, name);
+
+ if (self)
+ {
+ Py_INCREF (cluster);
+ self->cluster = cluster;
+ }
+
+ return (PyObject *) self;
+}
+
+static PyObject *
+cluster_add_node (Cluster *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ /* XXX: We could be smarter about type conversions here */
+ const char *node_name, *node_num, *ip_address, *ip_port, *local;
+ errcode_t ret;
+
+ static char *kwlist[] = { "node_name", "node_num",
+ "ip_address", "ip_port", "local",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs, "sssss:add_node", kwlist,
+ &node_name, &node_num,
+ &ip_address, &ip_port, &local))
+ return NULL;
+
+ CHECK_ERROR (o2cb_add_node (PyString_AS_STRING (self->name),
+ node_name, node_num,
+ ip_address, ip_port, local));
+
+ return node_new (self, node_name);
+}
+
+static PyObject *
+cluster_create_heartbeat_region_disk (Cluster *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ const char *region_name, *device_name;
+ int block_bytes;
+ uint64_t start_block, blocks;
+ errcode_t ret;
+
+ static char *kwlist[] = { "region_name", "device_name",
+ "block_bytes", "start_block", "blocks",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "ssiKK:create_heartbeat_region_disk",
+ kwlist,
+ ®ion_name, &device_name,
+ &block_bytes, &start_block, &blocks))
+ return NULL;
+
+ CHECK_ERROR
+ (o2cb_create_heartbeat_region_disk (PyString_AS_STRING (self->name),
+ region_name, device_name,
+ block_bytes, start_block, blocks));
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static PyObject *
+cluster_remove_heartbeat_region_disk (Cluster *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ const char *region_name;
+ errcode_t ret;
+
+ static char *kwlist[] = { "region_name", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "s:remove_heartbeat_region_disk", kwlist,
+ ®ion_name))
+ return NULL;
+
+ CHECK_ERROR
+ (o2cb_remove_heartbeat_region_disk (PyString_AS_STRING (self->name),
+ region_name));
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static PyMethodDef cluster_methods[] = {
+ {"add_node", (PyCFunction)cluster_add_node, METH_VARARGS | METH_KEYWORDS},
+ {"create_heartbeat_region_disk", (PyCFunction)cluster_create_heartbeat_region_disk, METH_VARARGS | METH_KEYWORDS},
+ {"remove_heartbeat_region_disk", (PyCFunction)cluster_remove_heartbeat_region_disk, METH_VARARGS | METH_KEYWORDS},
+ {NULL, NULL}
+};
+
+static PyObject *
+cluster_nodes (Cluster *self, void *closure)
+{
+ char **nodes, **name;
+ errcode_t ret;
+ PyObject *list, *node;
+ int status;
+
+ CHECK_ERROR (o2cb_list_nodes (PyString_AS_STRING (self->name), &nodes));
+
+ list = PyList_New (0);
+ if (list == NULL)
+ goto cleanup;
+
+ for (name = nodes; *name != NULL; name++)
+ {
+ node = node_new (self, *name);
+ if (node == NULL)
+ goto err;
+
+ status = PyList_Append (list, node);
+ Py_DECREF (node);
+
+ if (status)
+ goto err;
+ }
+
+ goto cleanup;
+
+err:
+ Py_DECREF (list);
+
+cleanup:
+ o2cb_free_nodes_list (nodes);
+
+ return list;
+}
+
+static PyGetSetDef cluster_getsets[] = {
+ {"nodes", (getter)cluster_nodes, (setter)0},
+ {NULL}
+};
+
+static PyObject *
+cluster_repr (Cluster *self)
+{
+ return o2cb_object_repr (self, "Cluster");
+}
+
+static int
+cluster_init (Cluster *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ errcode_t ret;
+ const char *name;
+
+ static char *kwlist[] = { "name", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "s:o2cb.Cluster.__init__", kwlist,
+ &name))
+ return -1;
+
+ self->name = PyString_FromString (name);
+ if (self->name == NULL)
+ return -1;
+
+ ret = o2cb_create_cluster (name);
+
+ if (ret)
+ {
+ Py_DECREF (self->name);
+ PyErr_SetString (o2cb_error, error_message (ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyTypeObject Cluster_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "o2cb.Cluster", /* tp_name */
+ sizeof(Cluster), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)o2cb_object_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)cluster_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ cluster_methods, /* tp_methods */
+ o2cb_object_members, /* tp_members */
+ cluster_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)cluster_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+static PyObject *
+cluster_new (const char *name)
+{
+ Cluster *self;
+
+ self = PyObject_NEW (Cluster, &Cluster_Type);
+
+ return o2cb_object_new (self, name);
+}
+
+static PyObject *
+list_clusters (PyObject *self)
+{
+ char **clusters, **name;
+ errcode_t ret;
+ PyObject *list, *cluster;
+ int status;
+
+ CHECK_ERROR (o2cb_list_clusters (&clusters));
+
+ list = PyList_New (0);
+ if (list == NULL)
+ goto cleanup;
+
+ for (name = clusters; *name != NULL; name++)
+ {
+ cluster = cluster_new (*name);
+ if (cluster == NULL)
+ goto err;
+
+ status = PyList_Append (list, cluster);
+ Py_DECREF (cluster);
+
+ if (status)
+ goto err;
+ }
+
+ goto cleanup;
+
+err:
+ Py_DECREF (list);
+
+cleanup:
+ o2cb_free_cluster_list (clusters);
+
+ return list;
+}
+
+static PyObject *
+create_heartbeat_region_disk (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ const char *cluster_name, *region_name, *device_name;
+ int block_bytes;
+ uint64_t start_block, blocks;
+ errcode_t ret;
+
+ static char *kwlist[] = { "cluster_name", "region_name", "device_name",
+ "block_bytes", "start_block", "blocks",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "zssiKK:create_heartbeat_region_disk",
+ kwlist,
+ &cluster_name, ®ion_name, &device_name,
+ &block_bytes, &start_block, &blocks))
+ return NULL;
+
+ CHECK_ERROR
+ (o2cb_create_heartbeat_region_disk (cluster_name, region_name, device_name,
+ block_bytes, start_block, blocks));
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static PyObject *
+remove_heartbeat_region_disk (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ const char *cluster_name, *region_name;
+ errcode_t ret;
+
+ static char *kwlist[] = { "cluster_name", "region_name", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "zs:remove_heartbeat_region_disk", kwlist,
+ &cluster_name, ®ion_name))
+ return NULL;
+
+ CHECK_ERROR (o2cb_remove_heartbeat_region_disk (cluster_name, region_name));
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static PyMethodDef o2cb_methods[] = {
+ {"list_clusters", (PyCFunction)list_clusters, METH_NOARGS},
+ {"create_heartbeat_region_disk", (PyCFunction)create_heartbeat_region_disk, METH_VARARGS | METH_KEYWORDS},
+ {"remove_heartbeat_region_disk", (PyCFunction)remove_heartbeat_region_disk, METH_VARARGS | METH_KEYWORDS},
+ {NULL, NULL} /* sentinel */
+};
+
+static void
+add_constants (PyObject *m)
+{
+ PyModule_AddStringConstant (m, "CONFIGFS_PATH", CONFIGFS_PATH);
+
+#define ADD_STR_CONSTANT(name) \
+ PyModule_AddStringConstant (m, "FORMAT_" #name, O2CB_FORMAT_ ## name)
+
+ ADD_STR_CONSTANT (CLUSTER_DIR);
+ ADD_STR_CONSTANT (CLUSTER);
+ ADD_STR_CONSTANT (NODE_DIR);
+ ADD_STR_CONSTANT (NODE);
+ ADD_STR_CONSTANT (NODE_ATTR);
+ ADD_STR_CONSTANT (HEARTBEAT_DIR);
+ ADD_STR_CONSTANT (HEARTBEAT_REGION);
+ ADD_STR_CONSTANT (HEARTBEAT_REGION_ATTR);
+
+#undef ADD_STR_CONSTANT
+}
+
+void
+inito2cb (void)
+{
+ PyObject *m;
+
+ Node_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&Node_Type) < 0)
+ return;
+
+ Cluster_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&Cluster_Type) < 0)
+ return;
+
+ initialize_o2cb_error_table ();
+
+ m = Py_InitModule ("o2cb", o2cb_methods);
+
+ o2cb_error = PyErr_NewException ("o2cb.error", PyExc_RuntimeError, NULL);
+
+ if (o2cb_error)
+ {
+ Py_INCREF (o2cb_error);
+ PyModule_AddObject (m, "error", o2cb_error);
+ }
+
+ Py_INCREF (&Cluster_Type);
+ PyModule_AddObject (m, "Cluster", (PyObject *) &Cluster_Type);
+
+ add_constants (m);
+
+ if (PyErr_Occurred ())
+ Py_FatalError ("can't initialize module o2cb");
+}
Modified: trunk/ocfs2console/ocfs2interface/ocfs2module.c
===================================================================
--- trunk/ocfs2console/ocfs2interface/ocfs2module.c 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/ocfs2module.c 2005-04-13 02:02:31 UTC (rev 799)
@@ -23,299 +23,1169 @@
* Boston, MA 021110-1307, USA.
*/
-#include "Python.h"
-#include "structseq.h"
+#include <Python.h>
+#include <structmember.h>
-#include <glib.h>
+#include <inttypes.h>
+#include <uuid/uuid.h>
+
#include "ocfs2.h"
-#include "ocfsplist.h"
+#define Filesystem_Check(op) PyObject_TypeCheck(op, &Filesystem_Type)
+#define DInode_Check(op) PyObject_TypeCheck(op, &DInode_Type)
+#define DirEntry_Check(op) PyObject_TypeCheck(op, &DirEntry_Type)
+#define SuperBlock_Check(op) PyObject_TypeCheck(op, &SuperBlock_Type)
+#define DirScanIter_Check(op) PyObject_TypeCheck(op, &DirScanIter_Type)
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *device;
+ ocfs2_filesys *fs;
+} Filesystem;
+
+typedef struct {
+ PyObject_HEAD
+ Filesystem *fs_obj;
+ ocfs2_dinode dinode;
+} DInode;
+
+typedef struct {
+ PyObject_HEAD
+ Filesystem *fs_obj;
+ struct ocfs2_dir_entry dentry;
+} DirEntry;
+
+typedef struct {
+ PyObject_HEAD
+ Filesystem *fs_obj;
+ ocfs2_super_block super;
+} SuperBlock;
+
+typedef struct {
+ PyObject_HEAD
+ Filesystem *fs_obj;
+ ocfs2_dir_scan *scan;
+} DirScanIter;
+
+
static PyObject *ocfs2_error;
-typedef struct
+#define CHECK_ERROR(call) do { \
+ ret = call; \
+ if (ret) \
+ { \
+ PyErr_SetString (ocfs2_error, error_message (ret)); \
+ return NULL; \
+ } \
+} while (0)
+
+
+#define DINODE_U64_GETTER(name) \
+ static PyObject * \
+ dinode_ ## name (DInode *self, void *closure) \
+ { \
+ return PyLong_FromUnsignedLongLong (self->dinode.i_ ## name); \
+ }
+
+#define DINODE_GETTER_ENTRY(name) \
+ {"i_" #name, (getter)dinode_ ## name, (setter)0}
+
+DINODE_U64_GETTER(size)
+DINODE_U64_GETTER(atime)
+DINODE_U64_GETTER(ctime)
+DINODE_U64_GETTER(mtime)
+DINODE_U64_GETTER(dtime)
+DINODE_U64_GETTER(blkno)
+DINODE_U64_GETTER(last_eb_blk)
+
+static PyObject *
+dinode_rdev (DInode *self, void *closure)
{
- PyObject *func;
- PyObject *data;
-} ProxyData;
+ return PyLong_FromUnsignedLongLong (self->dinode.id1.dev1.i_rdev);
+}
+static PyObject *
+dinode_jflags (DInode *self, void *closure)
+{
+ return PyInt_FromLong (self->dinode.id1.journal1.ij_flags);
+}
+
+static PyGetSetDef dinode_getsets[] = {
+ DINODE_GETTER_ENTRY (size),
+ DINODE_GETTER_ENTRY (atime),
+ DINODE_GETTER_ENTRY (ctime),
+ DINODE_GETTER_ENTRY (mtime),
+ DINODE_GETTER_ENTRY (dtime),
+ DINODE_GETTER_ENTRY (blkno),
+ DINODE_GETTER_ENTRY (last_eb_blk),
+ DINODE_GETTER_ENTRY (rdev),
+ {"ij_flags", (getter)dinode_jflags, (setter)0},
+ {NULL}
+};
+
+#undef DINODE_U64_GETTER
+#undef DINODE_GETTER_ENTRY
+
+#define DINODE_STR_MEMBER(name) \
+ {"i_" #name, T_STRING_INPLACE, offsetof (DInode, dinode.i_ ## name), RO}
+#define DINODE_S16_MEMBER(name) \
+ {"i_" #name, T_SHORT, offsetof (DInode, dinode.i_ ## name), RO}
+#define DINODE_U16_MEMBER(name) \
+ {"i_" #name, T_USHORT, offsetof (DInode, dinode.i_ ## name), RO}
+#define DINODE_U32_MEMBER(name) \
+ {"i_" #name, T_UINT, offsetof (DInode, dinode.i_ ## name), RO}
+#define DINODE_BITMAP_MEMBER(name) \
+ {"i_" #name, T_UINT, offsetof (DInode, dinode.id1.bitmap1.i_ ## name), RO}
+
+static PyMemberDef dinode_members[] = {
+ DINODE_STR_MEMBER (signature),
+ DINODE_U32_MEMBER (generation),
+ DINODE_S16_MEMBER (suballoc_node),
+ DINODE_U16_MEMBER (suballoc_bit),
+ DINODE_U32_MEMBER (clusters),
+ DINODE_U32_MEMBER (uid),
+ DINODE_U32_MEMBER (gid),
+ DINODE_U16_MEMBER (mode),
+ DINODE_U16_MEMBER (links_count),
+ DINODE_U32_MEMBER (flags),
+ DINODE_U32_MEMBER (fs_generation),
+ DINODE_BITMAP_MEMBER (used),
+ DINODE_BITMAP_MEMBER (total),
+ {"fs", T_OBJECT, offsetof (DInode, fs_obj), RO},
+ {0}
+};
+
+#undef DINODE_STR_MEMBER
+#undef DINODE_S16_MEMBER
+#undef DINODE_U16_MEMBER
+#undef DINODE_U32_MEMBER
+#undef DINODE_BITMAP_MEMBER
+
static void
-proxy_partition_func (OcfsPartitionInfo *info,
- gpointer pdata)
+dinode_dealloc (DInode *self)
{
- ProxyData *data = pdata;
+ Py_DECREF (self->fs_obj);
+ PyObject_DEL (self);
+}
- PyObject_CallFunction (data->func, "sss",
- info->device, info->mountpoint, info->fstype);
+static PyObject *
+dinode_repr (DInode *self)
+{
+ char blkno[32];
+
+ snprintf (blkno, sizeof (blkno), "%"PRIu64, self->dinode.i_blkno);
+ return PyString_FromFormat ("<ocfs2.DInode %s on %s>", blkno,
+ PyString_AS_STRING (self->fs_obj->device));
}
-static void
-proxy_partition_func_data (OcfsPartitionInfo *info,
- gpointer pdata)
+static PyTypeObject DInode_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "ocfs2.DInode", /* tp_name */
+ sizeof(DInode), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)dinode_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)dinode_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ dinode_members, /* tp_members */
+ dinode_getsets, /* tp_getset */
+};
+
+static PyObject *
+dinode_new (Filesystem *fs_obj,
+ ocfs2_dinode *dinode)
{
- ProxyData *data = pdata;
+ DInode *self;
- PyObject_CallFunction (data->func, "sssO",
- info->device, info->mountpoint, info->fstype,
- data->data);
+ self = PyObject_NEW (DInode, &DInode_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ Py_INCREF (fs_obj);
+ self->fs_obj = fs_obj;
+
+ memcpy (&self->dinode, dinode, sizeof (*dinode));
+
+ return (PyObject *) self;
}
+static PyObject *
+dir_entry_name (DirEntry *self, void *closure)
+{
+ return PyString_FromStringAndSize (self->dentry.name, self->dentry.name_len);
+}
+
+static PyObject *
+dir_entry_inode (DirEntry *self, void *closure)
+{
+ return PyLong_FromUnsignedLongLong (self->dentry.inode);
+}
+
+static PyGetSetDef dir_entry_getsets[] = {
+ {"name", (getter)dir_entry_name, (setter)0},
+ {"inode", (getter)dir_entry_inode, (setter)0},
+ {NULL}
+};
+
+static PyMemberDef dir_entry_members[] = {
+ {"rec_len", T_USHORT, offsetof (DirEntry, dentry.rec_len), RO},
+ {"file_type", T_UBYTE, offsetof (DirEntry, dentry.file_type), RO},
+ {"fs", T_OBJECT, offsetof (DirEntry, fs_obj), RO},
+ {0}
+};
+
static void
-proxy_unmounted_func (OcfsPartitionInfo *info,
- gpointer pdata)
+dir_entry_dealloc (DirEntry *self)
{
- ProxyData *data = pdata;
+ PyObject_DEL (self);
+}
- PyObject_CallFunction (data->func, "ss", info->device, info->fstype);
+static PyObject *
+dir_entry_repr (DirEntry *self)
+{
+ char name[OCFS2_MAX_FILENAME_LEN + 1];
+
+ strncpy (name, self->dentry.name, self->dentry.name_len);
+ name[self->dentry.name_len] = '\0';
+
+ return PyString_FromFormat ("<ocfs2.DirEntry '%s' on %s>", name,
+ PyString_AS_STRING (self->fs_obj->device));
}
+static PyTypeObject DirEntry_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "ocfs2.DirEntry", /* tp_name */
+ sizeof(DirEntry), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)dir_entry_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)dir_entry_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ dir_entry_members, /* tp_members */
+ dir_entry_getsets, /* tp_getset */
+};
+
+static PyObject *
+dir_entry_new (Filesystem *fs_obj,
+ struct ocfs2_dir_entry *dentry)
+{
+ DirEntry *self;
+
+ self = PyObject_NEW (DirEntry, &DirEntry_Type);
+
+ if (self == NULL)
+ return NULL;
+
+ Py_INCREF (fs_obj);
+ self->fs_obj = fs_obj;
+
+ memcpy (&self->dentry, dentry, sizeof (*dentry));
+
+ return (PyObject *) self;
+}
+
+#define SUPER_U64_GETTER(name) \
+ static PyObject * \
+ super_ ## name (SuperBlock *self, void *closure) \
+ { \
+ return PyLong_FromUnsignedLongLong (self->super.s_ ## name); \
+ }
+
+#define SUPER_GETTER_ENTRY(name) \
+ {"s_" #name, (getter)super_ ## name, (setter)0}
+
+SUPER_U64_GETTER (lastcheck)
+SUPER_U64_GETTER (root_blkno)
+SUPER_U64_GETTER (system_dir_blkno)
+SUPER_U64_GETTER (first_cluster_group)
+
+static PyObject *
+super_uuid (SuperBlock *self, void *closure)
+{
+ return PyString_FromStringAndSize (self->super.s_uuid,
+ sizeof (self->super.s_uuid));
+}
+
+static PyObject *
+super_uuid_unparsed (SuperBlock *self, void *closure)
+{
+ char buf[40];
+
+ uuid_unparse (self->super.s_uuid, buf);
+ return PyString_FromString (buf);
+}
+
+static PyGetSetDef super_getsets[] = {
+ SUPER_GETTER_ENTRY (lastcheck),
+ SUPER_GETTER_ENTRY (root_blkno),
+ SUPER_GETTER_ENTRY (system_dir_blkno),
+ SUPER_GETTER_ENTRY (first_cluster_group),
+ SUPER_GETTER_ENTRY (uuid),
+ {"uuid_unparsed", (getter)super_uuid_unparsed, (setter)0},
+ {NULL}
+};
+
+#undef SUPER_U64_GETTER
+#undef SUPER_GETTER_ENTRY
+
+#define SUPER_U16_MEMBER(name) \
+ {"s_" #name, T_USHORT, offsetof (SuperBlock, super.s_ ## name), RO}
+#define SUPER_U32_MEMBER(name) \
+ {"s_" #name, T_UINT, offsetof (SuperBlock, super.s_ ## name), RO}
+
+static PyMemberDef super_members[] = {
+ SUPER_U16_MEMBER (major_rev_level),
+ SUPER_U16_MEMBER (minor_rev_level),
+ SUPER_U16_MEMBER (mnt_count),
+ SUPER_U16_MEMBER (state),
+ SUPER_U16_MEMBER (errors),
+ SUPER_U32_MEMBER (checkinterval),
+ SUPER_U32_MEMBER (creator_os),
+ SUPER_U32_MEMBER (feature_compat),
+ SUPER_U32_MEMBER (feature_incompat),
+ SUPER_U32_MEMBER (feature_ro_compat),
+ SUPER_U32_MEMBER (blocksize_bits),
+ SUPER_U32_MEMBER (clustersize_bits),
+ SUPER_U16_MEMBER (max_nodes),
+ {"s_label", T_STRING_INPLACE, offsetof (SuperBlock, super.s_label), RO},
+ {"fs", T_OBJECT, offsetof (SuperBlock, fs_obj), RO},
+ {0}
+};
+
+#undef SUPER_U16_MEMBER
+#undef SUPER_U32_MEMBER
+
static void
-proxy_unmounted_func_data (OcfsPartitionInfo *info,
- gpointer pdata)
+super_dealloc (SuperBlock *self)
{
- ProxyData *data = pdata;
+ Py_DECREF (self->fs_obj);
+ PyObject_DEL (self);
+}
- PyObject_CallFunction (data->func, "ssO", info->device, info->fstype,
- data->data);
+static PyObject *
+super_repr (SuperBlock *self)
+{
+ return PyString_FromFormat ("<ocfs2.SuperBlock on %s>",
+ PyString_AS_STRING (self->fs_obj->device));
}
+static PyTypeObject SuperBlock_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "ocfs2.SuperBlock", /* tp_name */
+ sizeof(SuperBlock), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)super_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)super_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ super_members, /* tp_members */
+ super_getsets, /* tp_getset */
+};
static PyObject *
-partition_list (PyObject *self,
- PyObject *args,
- PyObject *kwargs)
+super_new (Filesystem *fs_obj,
+ ocfs2_dinode *fs_super)
{
- ProxyData proxy_data;
- OcfsPartitionListFunc func;
- PyObject *py_func, *py_data = NULL;
- gchar *filter = NULL, *fstype = NULL;
- gboolean unmounted = FALSE, async = FALSE;
+ SuperBlock *self;
- static gchar *kwlist[] = {
- "callback", "data",
- "filter", "fstype", "unmounted", "async",
- NULL
- };
+ self = PyObject_NEW (SuperBlock, &SuperBlock_Type);
- if (!PyArg_ParseTupleAndKeywords (args, kwargs,
- "O|Ozzii:partition_list", kwlist,
- &py_func, &py_data,
- &filter, &fstype, &unmounted, &async))
+ if (self == NULL)
return NULL;
- if (!PyCallable_Check (py_func))
+ Py_INCREF (fs_obj);
+ self->fs_obj = fs_obj;
+
+ memcpy (&self->super, &fs_super->id2.i_super, sizeof (self->super));
+
+ return (PyObject *) self;
+}
+
+static void
+dir_scan_iter_dealloc (DirScanIter *self)
+{
+ if (self->scan)
+ ocfs2_close_dir_scan (self->scan);
+
+ Py_XDECREF (self->fs_obj);
+ PyObject_DEL (self);
+}
+
+static PyObject *
+dir_scan_iter_getiter (DirScanIter *self)
+{
+ Py_INCREF (self);
+ return (PyObject *) self;
+}
+
+static PyObject *
+dir_scan_iter_next (DirScanIter *self)
+{
+ errcode_t ret;
+ struct ocfs2_dir_entry dirent;
+
+ if (self->scan == NULL)
{
- PyErr_SetString (PyExc_TypeError, "callback must be a callable object");
+ PyErr_SetNone (PyExc_StopIteration);
return NULL;
}
- proxy_data.func = py_func;
+ CHECK_ERROR (ocfs2_get_next_dir_entry (self->scan, &dirent));
- if (py_data)
+ if (dirent.rec_len == 0)
{
- proxy_data.data = py_data;
+ ocfs2_close_dir_scan (self->scan);
+ self->scan = NULL;
- if (unmounted)
- func = proxy_unmounted_func_data;
- else
- func = proxy_partition_func_data;
+ Py_DECREF (self->fs_obj);
+ self->fs_obj = NULL;
+
+ PyErr_SetNone (PyExc_StopIteration);
+ return NULL;
}
- else
+
+ return dir_entry_new (self->fs_obj, &dirent);
+}
+
+static PyTypeObject DirScanIter_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "ocfs2.DirScanIter", /* tp_name */
+ sizeof(DirScanIter), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)dir_scan_iter_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_ITER, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ (getiterfunc)dir_scan_iter_getiter, /* tp_iter */
+ (iternextfunc)dir_scan_iter_next, /* tp_iternext */
+};
+
+static PyObject *
+dir_scan_iter_new (Filesystem *fs_obj,
+ ocfs2_dir_scan *scan)
+{
+ DirScanIter *self;
+
+ self = PyObject_NEW (DirScanIter, &DirScanIter_Type);
+
+ if (self == NULL)
{
- if (unmounted)
- func = proxy_unmounted_func;
- else
- func = proxy_partition_func;
+ ocfs2_close_dir_scan (scan);
+ return NULL;
}
- ocfs_partition_list (func, &proxy_data, filter, fstype, unmounted, async);
+ Py_INCREF (fs_obj);
+ self->fs_obj = fs_obj;
- Py_INCREF (Py_None);
+ self->scan = scan;
+
+ return (PyObject *) self;
+}
+
+static PyObject *
+fs_flush (Filesystem *self)
+{
+ errcode_t ret;
+
+ CHECK_ERROR (ocfs2_flush (self->fs));
+
+ Py_INCREF(Py_None);
return Py_None;
}
-static PyStructSequence_Field struct_ocfs2_super_fields[] = {
- {"s_major_rev_level", "major revision level"},
- {"s_minor_rev_level", "minor revision level"},
- {"s_blocksize_bits", "blocksize bits"},
- {"s_clustersize_bits", "cluster size bits"},
- {"s_max_nodes", "maximum nodes"},
- {"s_label", "volume label"},
- {"s_uuid", "UUID"},
- {0}
-};
+static PyObject *
+fs_clusters_to_blocks (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ unsigned int clusters;
+ uint64_t blocks;
-struct PyStructSequence_Desc struct_ocfs2_super_desc = {
- "ocfs2.struct_ocfs2_super",
- NULL,
- struct_ocfs2_super_fields,
- 7,
-};
+ static char *kwlist[] = { "clusters", NULL };
-static PyTypeObject StructOcfs2SuperType;
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "I:clusters_to_blocks", kwlist,
+ &clusters))
+ return NULL;
+ blocks = ocfs2_clusters_to_blocks (self->fs, clusters);
+
+ return PyLong_FromUnsignedLongLong (blocks);
+}
+
static PyObject *
-get_super (PyObject *self,
- PyObject *args)
+fs_blocks_to_clusters (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
{
- gchar *device;
- errcode_t ret;
- ocfs2_filesys *fs;
- PyObject *v;
- gint index = 0;
- GString *uuid;
- gint i;
+ unsigned long long blocks;
+ uint32_t clusters;
- static gchar *fmt[] = { "%02x", "%02x", "%02x", "%02x",
- "-%02x", "%02x", "-%02x", "%02x", "-%02x", "%02x",
- "-%02x", "%02x", "%02x", "%02x", "%02x", "%02x" };
+ static char *kwlist[] = { "blocks", NULL };
- if (!PyArg_ParseTuple (args, "s:get_super", &device))
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "K:blocks_to_clusters", kwlist,
+ &blocks))
return NULL;
- ret = ocfs2_open (device, OCFS2_FLAG_RO, 0, 0, &fs);
- if (ret)
- {
- PyErr_SetString (ocfs2_error, error_message (ret));
- return NULL;
- }
+ clusters = ocfs2_clusters_to_blocks (self->fs, blocks);
- v = PyStructSequence_New (&StructOcfs2SuperType);
- if (v == NULL)
+ return PyInt_FromLong (clusters);
+}
+
+static PyObject *
+fs_blocks_in_bytes (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ unsigned long long bytes;
+ uint64_t blocks;
+
+ static char *kwlist[] = { "bytes", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "K:blocks_in_bytes", kwlist,
+ &bytes))
return NULL;
-#define SET(m) \
- PyStructSequence_SET_ITEM (v, index++, PyInt_FromLong \
- (OCFS2_RAW_SB (fs->fs_super)->m));
+ blocks = ocfs2_blocks_in_bytes (self->fs, bytes);
- SET (s_major_rev_level);
- SET (s_minor_rev_level);
- SET (s_blocksize_bits);
- SET (s_clustersize_bits);
- SET (s_max_nodes);
+ return PyLong_FromUnsignedLongLong (blocks);
+}
-#undef SET
-#define SET(m) \
- PyStructSequence_SET_ITEM \
- (v, index++, PyString_FromString (OCFS2_RAW_SB (fs->fs_super)->m));
+static PyObject *
+fs_clusters_in_blocks (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ unsigned long long blocks;
+ uint32_t clusters;
- PyStructSequence_SET_ITEM
- (v, index++, PyString_FromString (OCFS2_RAW_SB (fs->fs_super)->s_label));
+ static char *kwlist[] = { "blocks", NULL };
-#undef SET
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "K:clusters_in_blocks", kwlist,
+ &blocks))
+ return NULL;
- uuid = g_string_sized_new (32);
+ clusters = ocfs2_clusters_in_blocks (self->fs, blocks);
- for (i = 0; i < 16; i++)
- g_string_append_printf (uuid, fmt[i],
- OCFS2_RAW_SB (fs->fs_super)->s_uuid[i]);
+ return PyInt_FromLong (clusters);
+}
- PyStructSequence_SET_ITEM (v, index++, PyString_FromString (uuid->str));
+static PyObject *
+fs_block_out_of_range (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ unsigned long long block;
+ int ret;
- g_string_free (uuid, TRUE);
+ static char *kwlist[] = { "block", NULL };
- ocfs2_close (fs);
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "K:block_out_of_range", kwlist,
+ &block))
+ return NULL;
- if (PyErr_Occurred())
+ ret = ocfs2_block_out_of_range(self->fs, block);
+
+ return PyBool_FromLong (ret);
+}
+
+static PyObject *
+fs_lookup_system_inode (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ errcode_t ret;
+ int type, node_num = -1;
+ uint64_t blkno;
+
+ static char *kwlist[] = { "type", "node_num", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "i|i:lookup_system_inode", kwlist,
+ &type, &node_num))
+ return NULL;
+
+ CHECK_ERROR (ocfs2_lookup_system_inode(self->fs, type, node_num, &blkno));
+
+ return PyLong_FromUnsignedLongLong (blkno);
+}
+
+static PyObject *
+fs_read_cached_inode (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ errcode_t ret;
+ unsigned long long blkno;
+ ocfs2_cached_inode *cinode;
+ PyObject *dinode;
+
+ static char *kwlist[] = { "blkno", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "K:read_cached_inode", kwlist,
+ &blkno))
+ return NULL;
+
+ CHECK_ERROR (ocfs2_read_cached_inode (self->fs, blkno, &cinode));
+
+ dinode = dinode_new (self, cinode->ci_inode);
+
+ /* XXX: error check */
+ ocfs2_free_cached_inode (self->fs, cinode);
+
+ return dinode;
+}
+
+typedef struct
+{
+ PyObject *func;
+ PyObject *data;
+ Filesystem *fs;
+} WalkData;
+
+static int
+walk_dirs (struct ocfs2_dir_entry *dirent,
+ int offset,
+ int blocksize,
+ char *buf,
+ void *priv_data)
+{
+ PyObject *de;
+ WalkData *data = priv_data;
+
+ de = dir_entry_new (data->fs, dirent);
+
+ if (de == NULL)
+ return OCFS2_DIRENT_ERROR;
+
+ /* XXX: handle errors */
+ if (data->data)
+ PyObject_CallFunction (data->func, "OiiO", de, offset, blocksize,
+ data->data);
+ else
+ PyObject_CallFunction (data->func, "Oii", de, offset, blocksize);
+
+ Py_DECREF (de);
+
+ return 0;
+}
+
+static PyObject *
+fs_dir_iterate (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ errcode_t ret;
+ WalkData wdata;
+ PyObject *py_func, *py_data = NULL, *py_dir = NULL;
+ uint64_t dir;
+ int flags = OCFS2_DIRENT_FLAG_EXCLUDE_DOTS;
+
+ static char *kwlist[] = { "callback", "data", "dir", "flags", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "O|OOi:dir_iterate", kwlist,
+ &py_func, &py_data, &py_dir, &flags))
+ return NULL;
+
+ if (!PyCallable_Check (py_func))
{
- Py_DECREF (v);
+ PyErr_SetString (PyExc_TypeError, "callback must be a callable object");
return NULL;
}
- return v;
+ if (py_dir == NULL || py_dir == Py_None)
+ dir = self->fs->fs_root_blkno;
+ else if (DirEntry_Check (py_dir))
+ dir = ((DirEntry *) py_dir)->dentry.inode;
+ else if (PyInt_Check (py_dir))
+ dir = PyInt_AsUnsignedLongMask (py_dir);
+ else if (PyLong_Check (py_dir))
+ dir = PyLong_AsUnsignedLongLongMask (py_dir);
+ else
+ {
+ PyErr_SetString (PyExc_TypeError, "dir must be DirEntry or integer");
+ return NULL;
+ }
+
+ Py_INCREF (py_func);
+ wdata.func = py_func;
+
+ Py_XINCREF (py_data);
+ wdata.data = py_data;
+
+ wdata.fs = self;
+
+ /* XXX: handle errors */
+ ret = ocfs2_dir_iterate (self->fs, dir, flags, NULL, walk_dirs, &wdata);
+
+ Py_DECREF (py_func);
+ Py_XDECREF (py_data);
+
+ Py_INCREF (Py_None);
+ return Py_None;
}
static PyObject *
-get_space_usage (PyObject *self,
- PyObject *args)
+fs_dir_scan (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
{
- gchar *device;
- errcode_t ret;
- PyObject *v = NULL;
- ocfs2_filesys *fs = NULL;
- uint64_t blkno;
- ocfs2_cached_inode *cinode = NULL;
- ocfs2_dinode *bm;
- uint32_t numbits, freebits;
+ errcode_t ret;
+ PyObject *py_dir = NULL;
+ uint64_t dir;
+ int flags = OCFS2_DIR_SCAN_FLAG_EXCLUDE_DOTS;
+ ocfs2_dir_scan *scan;
- if (!PyArg_ParseTuple (args, "s:get_super", &device))
+ static char *kwlist[] = { "dir", "flags", NULL };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "|Oi:dir_scan", kwlist,
+ &py_dir, &flags))
return NULL;
-#define CHECK_ERROR(call) G_STMT_START { \
- ret = call; \
- if (ret) \
- { \
- PyErr_SetString (ocfs2_error, error_message (ret)); \
- goto bail; \
- } \
-} G_STMT_END
-
- CHECK_ERROR (ocfs2_open (device, OCFS2_FLAG_RO, 0, 0, &fs));
- CHECK_ERROR (ocfs2_lookup_system_inode(fs, GLOBAL_BITMAP_SYSTEM_INODE, -1,
- &blkno));
- CHECK_ERROR (ocfs2_read_cached_inode(fs, blkno, &cinode));
+ if (py_dir == NULL || py_dir == Py_None)
+ dir = self->fs->fs_root_blkno;
+ else if (DirEntry_Check (py_dir))
+ dir = ((DirEntry *) py_dir)->dentry.inode;
+ else if (PyInt_Check (py_dir))
+ dir = PyInt_AsUnsignedLongMask (py_dir);
+ else if (PyLong_Check (py_dir))
+ dir = PyLong_AsUnsignedLongLongMask (py_dir);
+ else
+ {
+ PyErr_SetString (PyExc_TypeError, "dir must be DirEntry or integer");
+ return NULL;
+ }
-#undef CHECK_ERROR
+ CHECK_ERROR (ocfs2_open_dir_scan (self->fs, dir, flags, &scan));
- bm = cinode->ci_inode;
+ return dir_scan_iter_new (self, scan);
+}
- numbits = le32_to_cpu (bm->id1.bitmap1.i_total);
- freebits = numbits - le32_to_cpu (bm->id1.bitmap1.i_used);
+static PyMethodDef fs_methods[] = {
+ {"flush", (PyCFunction)fs_flush, METH_NOARGS},
+ {"clusters_to_blocks", (PyCFunction)fs_clusters_to_blocks, METH_VARARGS | METH_KEYWORDS},
+ {"blocks_to_clusters", (PyCFunction)fs_blocks_to_clusters, METH_VARARGS | METH_KEYWORDS},
+ {"blocks_in_bytes", (PyCFunction)fs_blocks_in_bytes, METH_VARARGS | METH_KEYWORDS},
+ {"clusters_in_blocks", (PyCFunction)fs_clusters_in_blocks, METH_VARARGS | METH_KEYWORDS},
+ {"block_out_of_range", (PyCFunction)fs_block_out_of_range, METH_VARARGS | METH_KEYWORDS},
+ {"lookup_system_inode", (PyCFunction)fs_lookup_system_inode, METH_VARARGS | METH_KEYWORDS},
+ {"read_cached_inode", (PyCFunction)fs_read_cached_inode, METH_VARARGS | METH_KEYWORDS},
+ {"dir_iterate", (PyCFunction)fs_dir_iterate, METH_VARARGS | METH_KEYWORDS},
+ {"iterdir", (PyCFunction)fs_dir_scan, METH_VARARGS | METH_KEYWORDS},
+ {NULL, NULL}
+};
- v = PyTuple_New (2);
+static PyObject *
+fs_super (Filesystem *self, void *closure)
+{
+ return super_new (self, self->fs->fs_super);
+}
- PyTuple_SetItem(v, 0, PyInt_FromLong (numbits));
- PyTuple_SetItem(v, 1, PyInt_FromLong (freebits));
+static PyObject *
+fs_orig_super (Filesystem *self, void *closure)
+{
+ return super_new (self, self->fs->fs_orig_super);
+}
-bail:
- if (cinode)
- ocfs2_free_cached_inode(fs, cinode);
+static PyObject *
+fs_uuid_str (Filesystem *self, void *closure)
+{
+ return PyString_FromString (self->fs->uuid_str);
+}
- if (fs)
- ocfs2_close (fs);
+#define FS_U32_GETTER(name) \
+ static PyObject * \
+ fs_ ## name (Filesystem *self, void *closure) \
+ { \
+ return PyInt_FromLong (self->fs->fs_ ## name); \
+ }
- return v;
+#define FS_UINT_GETTER FS_U32_GETTER
+
+#define FS_U64_GETTER(name) \
+ static PyObject * \
+ fs_ ## name (Filesystem *self, void *closure) \
+ { \
+ return PyLong_FromUnsignedLongLong (self->fs->fs_ ## name); \
+ }
+
+#define FS_GETTER_ENTRY(name) \
+ {"fs_" #name, (getter)fs_ ## name, (setter)0}
+
+FS_U32_GETTER (flags)
+FS_UINT_GETTER (blocksize)
+FS_UINT_GETTER (clustersize)
+FS_U32_GETTER (clusters)
+FS_U64_GETTER (blocks)
+FS_U32_GETTER (umask)
+FS_U64_GETTER (root_blkno)
+FS_U64_GETTER (sysdir_blkno)
+FS_U64_GETTER (first_cg_blkno)
+
+static PyGetSetDef fs_getsets[] = {
+ FS_GETTER_ENTRY (flags),
+ FS_GETTER_ENTRY (super),
+ FS_GETTER_ENTRY (orig_super),
+ FS_GETTER_ENTRY (blocksize),
+ FS_GETTER_ENTRY (clustersize),
+ FS_GETTER_ENTRY (clusters),
+ FS_GETTER_ENTRY (blocks),
+ FS_GETTER_ENTRY (umask),
+ FS_GETTER_ENTRY (root_blkno),
+ FS_GETTER_ENTRY (sysdir_blkno),
+ FS_GETTER_ENTRY (first_cg_blkno),
+ {"uuid_str", (getter)fs_uuid_str, (setter)0},
+ {NULL}
+};
+
+#undef FS_UINT_GETTER
+#undef FS_U32_GETTER
+#undef FS_U64_GETTER
+#undef FS_GETTER_ENTRY
+
+static PyMemberDef fs_members[] = {
+ {"device", T_OBJECT, offsetof (Filesystem, device), RO},
+ {"fs_devname", T_OBJECT, offsetof (Filesystem, device), RO},
+ {0}
+};
+
+static void
+fs_dealloc (Filesystem *self)
+{
+ if (self->fs)
+ ocfs2_close (self->fs);
+
+ Py_XDECREF (self->device);
+ PyObject_DEL (self);
}
+static PyObject *
+fs_repr (Filesystem *self)
+{
+ return PyString_FromFormat("<ocfs2.Filesystem on %s>",
+ PyString_AS_STRING (self->device));
+}
+
+static int
+fs_init (Filesystem *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ errcode_t ret;
+ char *device;
+ int flags = OCFS2_FLAG_RO | OCFS2_FLAG_BUFFERED;
+ unsigned int superblock = 0, blksize = 0;
+
+ static char *kwlist[] = { "device", "flags", "superblock", "blocksize",
+ NULL };
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs,
+ "s|iII:ocfs2.Filesystem.__init__", kwlist,
+ &device, &flags, &superblock, &blksize))
+ return -1;
+
+ self->fs = NULL;
+ self->device = PyString_FromString (device);
+
+ if (self->device == NULL)
+ return -1;
+
+ ret = ocfs2_open (device, flags, superblock, blksize, &self->fs);
+
+ if (ret)
+ {
+ Py_DECREF (self->device);
+ PyErr_SetString (ocfs2_error, error_message (ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+static PyTypeObject Filesystem_Type = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "ocfs2.Filesystem", /* tp_name */
+ sizeof(Filesystem), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)fs_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ (reprfunc)fs_repr, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ NULL, /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ fs_methods, /* tp_methods */
+ fs_members, /* tp_members */
+ fs_getsets, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)fs_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
static PyMethodDef ocfs2_methods[] = {
- {"partition_list", (PyCFunction)partition_list, METH_VARARGS | METH_KEYWORDS},
- {"get_super", (PyCFunction)get_super, METH_VARARGS},
- {"get_space_usage", (PyCFunction)get_space_usage, METH_VARARGS},
{NULL, NULL} /* sentinel */
};
+static void
+add_constants (PyObject *m)
+{
+#define ADD_INT_CONSTANT(name) \
+ PyModule_AddIntConstant (m, #name, OCFS2_ ## name)
+#define ADD_STR_CONSTANT(name) \
+ PyModule_AddStringConstant (m, #name, OCFS2_ ## name)
+
+ ADD_INT_CONSTANT (SUPER_BLOCK_BLKNO);
+
+ ADD_INT_CONSTANT (MIN_CLUSTERSIZE);
+ ADD_INT_CONSTANT (MAX_CLUSTERSIZE);
+
+ ADD_INT_CONSTANT (MIN_BLOCKSIZE);
+ ADD_INT_CONSTANT (MAX_BLOCKSIZE);
+
+ ADD_INT_CONSTANT (SUPER_MAGIC);
+
+ ADD_STR_CONSTANT (SUPER_BLOCK_SIGNATURE);
+ ADD_STR_CONSTANT (INODE_SIGNATURE);
+ ADD_STR_CONSTANT (EXTENT_BLOCK_SIGNATURE);
+ ADD_STR_CONSTANT (GROUP_DESC_SIGNATURE);
+
+ ADD_INT_CONSTANT (VALID_FL);
+ ADD_INT_CONSTANT (ORPHANED_FL);
+
+ ADD_INT_CONSTANT (SYSTEM_FL);
+ ADD_INT_CONSTANT (SUPER_BLOCK_FL);
+ ADD_INT_CONSTANT (LOCAL_ALLOC_FL);
+ ADD_INT_CONSTANT (BITMAP_FL);
+ ADD_INT_CONSTANT (JOURNAL_FL);
+ ADD_INT_CONSTANT (HEARTBEAT_FL);
+ ADD_INT_CONSTANT (CHAIN_FL);
+
+ ADD_INT_CONSTANT (JOURNAL_DIRTY_FL);
+
+ ADD_INT_CONSTANT (ERROR_FS);
+
+ ADD_INT_CONSTANT (MAX_FILENAME_LEN);
+
+ ADD_INT_CONSTANT (MAX_NODES);
+
+ ADD_INT_CONSTANT (VOL_UUID_LEN);
+ ADD_INT_CONSTANT (MAX_VOL_LABEL_LEN);
+
+ ADD_INT_CONSTANT (MAX_CLUSTER_NAME_LEN);
+
+ ADD_INT_CONSTANT (MIN_JOURNAL_SIZE);
+ ADD_INT_CONSTANT (MAX_JOURNAL_SIZE);
+
+ ADD_INT_CONSTANT (FIRST_ONLINE_SYSTEM_INODE);
+ ADD_INT_CONSTANT (LAST_GLOBAL_SYSTEM_INODE);
+
+ ADD_INT_CONSTANT (FT_UNKNOWN);
+ ADD_INT_CONSTANT (FT_REG_FILE);
+ ADD_INT_CONSTANT (FT_DIR);
+ ADD_INT_CONSTANT (FT_CHRDEV);
+ ADD_INT_CONSTANT (FT_BLKDEV);
+ ADD_INT_CONSTANT (FT_FIFO);
+ ADD_INT_CONSTANT (FT_SOCK);
+ ADD_INT_CONSTANT (FT_SYMLINK);
+ ADD_INT_CONSTANT (FT_MAX);
+
+ ADD_INT_CONSTANT (LINK_MAX);
+
+ ADD_INT_CONSTANT (FLAG_RO);
+ ADD_INT_CONSTANT (FLAG_RW);
+ ADD_INT_CONSTANT (FLAG_CHANGED);
+ ADD_INT_CONSTANT (FLAG_DIRTY);
+ ADD_INT_CONSTANT (FLAG_SWAP_BYTES);
+ ADD_INT_CONSTANT (FLAG_BUFFERED);
+ ADD_INT_CONSTANT (FLAG_NO_REV_CHECK);
+
+ ADD_INT_CONSTANT (DIRENT_CHANGED);
+ ADD_INT_CONSTANT (DIRENT_ABORT);
+ ADD_INT_CONSTANT (DIRENT_ERROR);
+
+ ADD_INT_CONSTANT (DIRENT_FLAG_INCLUDE_EMPTY);
+ ADD_INT_CONSTANT (DIRENT_FLAG_INCLUDE_REMOVED);
+ ADD_INT_CONSTANT (DIRENT_FLAG_EXCLUDE_DOTS);
+
+#undef ADD_INT_CONSTANT
+#undef ADD_STR_CONSTANT
+
+#define ADD_INT_CONSTANT(name) \
+ PyModule_AddIntConstant (m, #name, name)
+
+ ADD_INT_CONSTANT (BAD_BLOCK_SYSTEM_INODE);
+ ADD_INT_CONSTANT (GLOBAL_INODE_ALLOC_SYSTEM_INODE);
+ ADD_INT_CONSTANT (SLOT_MAP_SYSTEM_INODE);
+ ADD_INT_CONSTANT (HEARTBEAT_SYSTEM_INODE);
+ ADD_INT_CONSTANT (GLOBAL_BITMAP_SYSTEM_INODE);
+ ADD_INT_CONSTANT (ORPHAN_DIR_SYSTEM_INODE);
+ ADD_INT_CONSTANT (EXTENT_ALLOC_SYSTEM_INODE);
+ ADD_INT_CONSTANT (INODE_ALLOC_SYSTEM_INODE);
+ ADD_INT_CONSTANT (JOURNAL_SYSTEM_INODE);
+ ADD_INT_CONSTANT (LOCAL_ALLOC_SYSTEM_INODE);
+ ADD_INT_CONSTANT (NUM_SYSTEM_INODES);
+
+ //ADD_INT_CONSTANT (MAX_NODE_NAME_LEN);
+
+#undef ADD_INT_CONSTANT
+}
+
void
initocfs2 (void)
{
PyObject *m;
+ DInode_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&DInode_Type) < 0)
+ return;
+
+ DirEntry_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&DirEntry_Type) < 0)
+ return;
+
+ SuperBlock_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&SuperBlock_Type) < 0)
+ return;
+
+ DirScanIter_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&DirScanIter_Type) < 0)
+ return;
+
+ Filesystem_Type.tp_new = PyType_GenericNew;
+ if (PyType_Ready (&Filesystem_Type) < 0)
+ return;
+
initialize_ocfs_error_table ();
m = Py_InitModule ("ocfs2", ocfs2_methods);
- PyStructSequence_InitType (&StructOcfs2SuperType, &struct_ocfs2_super_desc);
- Py_INCREF (&StructOcfs2SuperType);
- PyModule_AddObject (m, "struct_ocfs2_super",
- (PyObject *) &StructOcfs2SuperType);
+ ocfs2_error = PyErr_NewException ("ocfs2.error", PyExc_RuntimeError, NULL);
- ocfs2_error = PyErr_NewException ("ocfs2.error", PyExc_RuntimeError, NULL);
if (ocfs2_error)
{
Py_INCREF (ocfs2_error);
PyModule_AddObject (m, "error", ocfs2_error);
}
- PyModule_AddIntConstant (m, "MAX_VOL_LABEL_LEN", OCFS2_MAX_VOL_LABEL_LEN);
- PyModule_AddIntConstant (m, "MAX_NODES", OCFS2_MAX_NODES);
+ Py_INCREF (&Filesystem_Type);
+ PyModule_AddObject (m, "Filesystem", (PyObject *) &Filesystem_Type);
- PyModule_AddIntConstant (m, "MIN_BLOCKSIZE", OCFS2_MIN_BLOCKSIZE);
- PyModule_AddIntConstant (m, "MAX_BLOCKSIZE", OCFS2_MAX_BLOCKSIZE);
+ add_constants (m);
- PyModule_AddIntConstant (m, "MIN_CLUSTERSIZE", OCFS2_MIN_CLUSTERSIZE);
- PyModule_AddIntConstant (m, "MAX_CLUSTERSIZE", OCFS2_MAX_CLUSTERSIZE);
-
if (PyErr_Occurred ())
Py_FatalError ("can't initialize module ocfs2");
}
Modified: trunk/ocfs2console/ocfs2interface/partitionview.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/partitionview.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/partitionview.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -17,7 +17,7 @@
import gtk
-import ocfs2
+from plist import partition_list
COLUMN_DEVICE, COLUMN_MOUNTPOINT = range(2)
@@ -80,7 +80,7 @@
if frame.child:
frame.child.destroy()
- frame.add(info(device).widget)
+ frame.add(info(device))
frame.show_all()
def select_device(self, device):
@@ -122,8 +122,8 @@
store.set_sort_func(COLUMN_DEVICE, list_compare)
store.set_sort_column_id(COLUMN_DEVICE, gtk.SORT_ASCENDING)
- ocfs2.partition_list(self.add_partition, data=old_device,
- filter=filter, fstype='ocfs2', async=True)
+ partition_list(self.add_partition, old_device,
+ filter=filter, fstype='ocfs2', async=True)
if len(store):
if not self.selected:
Added: trunk/ocfs2console/ocfs2interface/plistmodule.c
===================================================================
--- trunk/ocfs2console/ocfs2interface/plistmodule.c 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/plistmodule.c 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,156 @@
+/*
+ * plistmodule.c
+ *
+ * Partition list python binding.
+ *
+ * Copyright (C) 2004, 2005 Oracle. All rights reserved.
+ *
+ * Author: Manish Singh <manish.singh at oracle.com>
+ *
+ * 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 recieved a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <Python.h>
+
+#include <glib.h>
+
+#include "ocfsplist.h"
+
+typedef struct
+{
+ PyObject *func;
+ PyObject *data;
+
+ gboolean mountpoint;
+ gboolean seen_error;
+} ProxyData;
+
+
+static void
+proxy (OcfsPartitionInfo *info,
+ gpointer pdata)
+{
+ ProxyData *data = pdata;
+ PyObject *tuple, *val, *ret;
+ gint len = 2, pos = 0;
+
+ if (data->seen_error)
+ return;
+
+ if (data->mountpoint) len++;
+ if (data->data) len++;
+
+ tuple = PyTuple_New (len);
+
+ PyTuple_SET_ITEM (tuple, pos, PyString_FromString (info->device));
+ pos++;
+
+ if (data->mountpoint)
+ {
+ if (info->mountpoint == NULL)
+ {
+ Py_INCREF (Py_None);
+ val = Py_None;
+ }
+ else
+ val = PyString_FromString (info->mountpoint);
+
+ PyTuple_SET_ITEM (tuple, pos, val);
+ pos++;
+ }
+
+ PyTuple_SET_ITEM (tuple, pos, PyString_FromString (info->fstype));
+ pos++;
+
+ if (data->data)
+ {
+ Py_INCREF (data->data);
+ PyTuple_SET_ITEM (tuple, pos, data->data);
+ pos++;
+ }
+
+ ret = PyObject_CallObject (data->func, tuple);
+
+ if (ret == NULL)
+ {
+ PyErr_Print();
+ data->seen_error = TRUE;
+ }
+
+ Py_DECREF (tuple);
+}
+
+static PyObject *
+partition_list (PyObject *self,
+ PyObject *args,
+ PyObject *kwargs)
+{
+ ProxyData pdata;
+ PyObject *py_func, *py_data = NULL;
+ gchar *filter = NULL, *fstype = NULL;
+ gboolean unmounted = FALSE, async = FALSE;
+
+ static gchar *kwlist[] = {
+ "callback", "data",
+ "filter", "fstype", "unmounted", "async",
+ NULL
+ };
+
+ if (!PyArg_ParseTupleAndKeywords (args, kwargs,
+ "O|Ozzii:partition_list", kwlist,
+ &py_func, &py_data,
+ &filter, &fstype, &unmounted, &async))
+ return NULL;
+
+ if (!PyCallable_Check (py_func))
+ {
+ PyErr_SetString (PyExc_TypeError, "callback must be a callable object");
+ return NULL;
+ }
+
+ Py_INCREF (py_func);
+ pdata.func = py_func;
+
+ Py_XINCREF (py_data);
+ pdata.data = py_data;
+
+ pdata.mountpoint = !unmounted;
+ pdata.seen_error = FALSE;
+
+ ocfs_partition_list (proxy, &pdata, filter, fstype, unmounted, async);
+
+ Py_DECREF (py_func);
+ Py_XDECREF (py_data);
+
+ Py_INCREF (Py_None);
+ return Py_None;
+}
+
+static PyMethodDef plist_methods[] = {
+ {"partition_list", (PyCFunction)partition_list, METH_VARARGS | METH_KEYWORDS},
+ {NULL, NULL} /* sentinel */
+};
+
+void
+initplist (void)
+{
+ PyObject *m;
+
+ m = Py_InitModule ("plist", plist_methods);
+
+ if (PyErr_Occurred ())
+ Py_FatalError ("can't initialize module plist");
+}
Added: trunk/ocfs2console/ocfs2interface/pushconfig.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/pushconfig.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/pushconfig.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -0,0 +1,83 @@
+# OCFS2Console - GUI frontend for OCFS2 management and debugging
+# Copyright (C) 2005 Oracle. 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
+
+import gobject
+
+from terminal import TerminalDialog, terminal_ok as push_config_ok
+
+CONFIG_FILE = '/etc/ocfs2/cluster.conf'
+
+def push_config(parent):
+ commands = generate_commands(hosts)
+
+ title = 'Propagate Cluster Configuration'
+
+ dialog = TerminalDialog(parent=parent, title=title)
+ terminal = dialog.terminal
+
+ terminal.connect('child-exited', child_exited, dialog)
+
+ command = None
+ gobject.idle_add(start_command, terminal, command, dialog)
+
+ dialog.show_all()
+
+ while 1:
+ dialog.run()
+
+ if dialog.finished:
+ break
+
+ msg = ('Cluster propagation is still running. You should not close '
+ 'this window until it is finished')
+
+ info = gtk.MessageDialog(parent=dialog,
+ flags=gtk.DIALOG_DESTROY_WITH_PARENT,
+ type=gtk.MESSAGE_WARNING,
+ buttons=gtk.BUTTONS_CLOSE,
+ message_format=msg)
+ info.run()
+ info.destroy()
+
+ dialog.destroy()
+
+def start_command(terminal, command, dialog):
+ terminal.fork_command(command=command[0], argv=command)
+ return False
+
+def child_exited(terminal, dialog):
+ dialog.finished = True
+
+def fsck_command(device, check):
+ command = list(base_command)
+
+ if check:
+ command.append('-n')
+ else:
+ command.append('-y')
+
+ command.append("'%s'" % device)
+
+ realcommand = '%s; sleep 1' % ' '.join(command)
+
+ return ['/bin/sh', '-c', realcommand]
+
+def main():
+ push_config(None)
+
+if __name__ == '__main__':
+ main()
Modified: trunk/ocfs2console/ocfs2interface/tune.py
===================================================================
--- trunk/ocfs2console/ocfs2interface/tune.py 2005-04-13 02:00:52 UTC (rev 798)
+++ trunk/ocfs2console/ocfs2interface/tune.py 2005-04-13 02:02:31 UTC (rev 799)
@@ -30,12 +30,11 @@
def __init__(self, device=None):
VolumeLabel.__init__(self)
- if device:
- try:
- super = ocfs2.get_super(device)
- self.set_text(super.s_label)
- except ocfs2.error:
- pass
+ try:
+ fs = ocfs2.Filesystem(device)
+ self.set_text(fs.fs_super.s_label)
+ except ocfs2.error:
+ pass
title = 'Changing Label'
action = 'Changing label'
@@ -46,9 +45,8 @@
def __init__(self, device=None):
NumNodes.__init__(self)
- if device:
- super = ocfs2.get_super(device)
- self.set_range(super.s_max_nodes, ocfs2.MAX_NODES)
+ fs = ocfs2.Filesystem(device)
+ self.set_range(fs.fs_super.s_max_nodes, ocfs2.MAX_NODES)
title = 'Edit Node Count'
action = 'Changing node count'
@@ -59,8 +57,10 @@
try:
widget = widget_type(device)
except ocfs2.error:
- error_box(parent, 'Could not get current %s for device $s' %
- (widget_type.label.lower(), device))
+ desc = widget_type.label.replace('_', '')
+ desc = desc.lower()
+ error_box(parent, 'Could not get current %s for device %s' %
+ (desc, device))
return False
dialog = Dialog(parent=parent, title=widget_type.title,
More information about the Ocfs2-tools-commits
mailing list