Skip to content

Commit 251f598

Browse files
committed
Add a loader using libdl.so.2
1 parent d4d7a69 commit 251f598

File tree

5 files changed

+232
-8
lines changed

5 files changed

+232
-8
lines changed

PamSharp.sln.DotSettings

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
55
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=TTY/@EntryIndexedValue">TTY</s:String>
66
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UTF/@EntryIndexedValue">UTF</s:String>
7+
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="PAM_" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
78
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="" Suffix="" Style="AA_BB" /&gt;&lt;/Policy&gt;</s:String>
89
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb"&gt;&lt;ExtraRule Prefix="_" Suffix="" Style="aaBb" /&gt;&lt;/Policy&gt;</s:String>
910
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>

src/FubarDev.PamSharp/Interop/PamInteropFactory.cs

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
// </copyright>
44

55
using System;
6+
using System.Collections.Generic;
67
using System.Reflection;
8+
using System.Runtime.InteropServices;
9+
10+
using FubarDev.PamSharp.Interop.UnixDl2;
711

812
using Platform.Invoke;
913

@@ -27,14 +31,8 @@ public static IPamInterop Create()
2731
{
2832
if (_interop == null)
2933
{
30-
var libraryLoader = LibraryLoaderFactory.Create();
31-
var library = MapAndLoad("pam", typeof(IPamInterop).Assembly, libraryLoader);
32-
if (library == null)
33-
{
34-
throw new NotSupportedException("Unsupported operating system, no viable library loader or library not found");
35-
}
36-
37-
_interop = LibraryInterfaceFactory.Implement<IPamInterop>(library);
34+
_interop = CreatePamInterop() ?? throw new NotSupportedException(
35+
"Unsupported operating system, no viable library loader or library not found");
3836
}
3937

4038
return _interop;
@@ -64,5 +62,35 @@ public static IPamInterop Create()
6462

6563
return null;
6664
}
65+
66+
private static IPamInterop? CreatePamInterop()
67+
{
68+
foreach (var libraryLoader in GetLibraryLoaders())
69+
{
70+
try
71+
{
72+
var library = MapAndLoad("pam", typeof(IPamInterop).Assembly, libraryLoader);
73+
if (library != null)
74+
{
75+
return LibraryInterfaceFactory.Implement<IPamInterop>(library);
76+
}
77+
}
78+
catch
79+
{
80+
// Ignore
81+
}
82+
}
83+
84+
return null;
85+
}
86+
87+
private static IEnumerable<ILibraryLoader> GetLibraryLoaders()
88+
{
89+
yield return LibraryLoaderFactory.Create();
90+
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
91+
{
92+
yield return new UnixDl2LibraryLoader();
93+
}
94+
}
6795
}
6896
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// <copyright file="UnixDl2Library.cs" company="Fubar Development Junker">
2+
// Copyright (c) Fubar Development Junker. All rights reserved.
3+
// </copyright>
4+
5+
using System;
6+
using System.Diagnostics;
7+
8+
using Platform.Invoke;
9+
10+
namespace FubarDev.PamSharp.Interop.UnixDl2
11+
{
12+
/// <summary>
13+
/// Implements library function loading using libdl.
14+
/// </summary>
15+
[DebuggerDisplay("so({" + nameof(Name) + "})")]
16+
public sealed class UnixDl2Library : LibraryBase
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="UnixDl2Library"/> class.
20+
/// </summary>
21+
/// <param name="moduleHandle">Handle to the loaded module returned by dlopen(3).</param>
22+
/// <param name="libraryName">Name of the loaded library.</param>
23+
public UnixDl2Library(IntPtr moduleHandle, string libraryName)
24+
: base(moduleHandle, new UnixDl2LibraryProcProvider(), libraryName)
25+
{
26+
}
27+
}
28+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// <copyright file="UnixDl2LibraryLoader.cs" company="Fubar Development Junker">
2+
// Copyright (c) Fubar Development Junker. All rights reserved.
3+
// </copyright>
4+
5+
using System;
6+
using System.Runtime.InteropServices;
7+
8+
using Platform.Invoke;
9+
using Platform.Invoke.Unix;
10+
11+
namespace FubarDev.PamSharp.Interop.UnixDl2
12+
{
13+
/// <summary>
14+
/// Library loading support for Unix operating systems (including OS X).
15+
/// </summary>
16+
public sealed class UnixDl2LibraryLoader : LibraryLoaderBase
17+
{
18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="UnixDl2LibraryLoader"/> class.
20+
/// </summary>
21+
public UnixDl2LibraryLoader()
22+
: base(s => dlopen(s, Flags.Lazy | Flags.Local))
23+
{
24+
}
25+
26+
/// <summary>
27+
/// Defines flags used by dlopen.
28+
/// </summary>
29+
[Flags]
30+
private enum Flags
31+
{
32+
/// <summary>
33+
/// Perform lazy binding. Only resolve symbols as the code that references them is executed.
34+
/// If the symbol is never referenced, then it is never resolved. (Lazy binding is only
35+
/// performed for function references; references to variables are always immediately bound
36+
/// when the library is loaded.)
37+
/// </summary>
38+
Lazy = 0x00001,
39+
40+
/// <summary>
41+
/// If this value is specified, or the environment variable LD_BIND_NOW is set to a nonempty
42+
/// string, all undefined symbols in the library are resolved before dlopen() returns.
43+
/// If this cannot be done, an error is returned.
44+
/// </summary>
45+
Now = 0x00002,
46+
47+
/// <summary>
48+
/// The symbols defined by this library will be made available for symbol resolution of
49+
/// subsequently loaded libraries.
50+
/// </summary>
51+
Global = 0x00100,
52+
53+
/// <summary>
54+
/// This is the converse of <see cref="Global"/>, and the default if neither flag is specified.
55+
/// Symbols defined in this library are not made available to resolve references in subsequently
56+
/// loaded libraries.
57+
/// </summary>
58+
Local = 0,
59+
60+
/// <summary>
61+
/// Do not unload the library during dlclose(). Consequently, the library's static variables are
62+
/// not reinitialized if the library is reloaded with dlopen() at a later time. This flag is not
63+
/// specified in POSIX.1-2001.
64+
/// </summary>
65+
NoDelete = 0x01000,
66+
}
67+
68+
/// <summary>
69+
/// Returns the created library for the specified handle and library name.
70+
/// </summary>
71+
/// <param name="handle">Operating system provided library handle.</param>
72+
/// <param name="libraryName">Name fo the loaded library.</param>
73+
/// <returns><see cref="ILibrary"/> interface for the specified library.</returns>
74+
protected override ILibrary CreateLibrary(IntPtr handle, string libraryName)
75+
{
76+
return new UnixLibrary(handle, libraryName);
77+
}
78+
79+
/// <summary>
80+
/// Unix library loader function.
81+
/// </summary>
82+
/// <param name="filename">Filename to load,</param>
83+
/// <param name="flags">Loader flags. Typically RTLD_LAZY.</param>
84+
/// <returns>Handle to the library.</returns>
85+
[DllImport("libdl.so.2")]
86+
#pragma warning disable SA1300 // Element should begin with upper-case letter
87+
private static extern IntPtr dlopen([In]string filename, Flags flags);
88+
#pragma warning restore SA1300 // Element should begin with upper-case letter
89+
}
90+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// <copyright file="UnixDl2LibraryProcProvider.cs" company="Fubar Development Junker">
2+
// Copyright (c) Fubar Development Junker. All rights reserved.
3+
// </copyright>
4+
5+
using System;
6+
using System.ComponentModel;
7+
using System.Diagnostics.Contracts;
8+
using System.Runtime.InteropServices;
9+
10+
using Platform.Invoke;
11+
12+
namespace FubarDev.PamSharp.Interop.UnixDl2
13+
{
14+
/// <summary>
15+
/// Implements function loading and library handling for Unix operating systems.
16+
/// </summary>
17+
[ImmutableObject(true)]
18+
public sealed class UnixDl2LibraryProcProvider : ILibraryProcProvider
19+
{
20+
/// <summary>
21+
/// Free this library.
22+
/// </summary>
23+
/// <param name="module">Module to free.</param>
24+
/// <returns><see langword="true"/> when freeing the library was successful.</returns>
25+
public bool Free(IntPtr module)
26+
{
27+
return dlclose(module) == 0;
28+
}
29+
30+
/// <summary>
31+
/// Retrieves a pointer to the specified function.
32+
/// </summary>
33+
/// <param name="module">Operating system provided library handle.</param>
34+
/// <param name="procName">Library function name.</param>
35+
/// <returns>Pointer to the loaded function. Null if procedure could not be located.</returns>
36+
[Pure]
37+
public IntPtr GetProc(IntPtr module, string procName)
38+
{
39+
return dlsym(module, procName);
40+
}
41+
42+
/// <summary>
43+
/// Gets a delegate for the specified function pointer.
44+
/// </summary>
45+
/// <param name="functionPointer">Function pointer retrieved using <see cref="GetProc"/>.</param>
46+
/// <param name="delegateType">Type of delegate to return.</param>
47+
/// <returns><see cref="Delegate"/> fro the specified function pointer.</returns>
48+
/// <exception cref="ArgumentNullException">Thrown if <see paramref="functionPointer"/> or <see paramref="delegateType"/> is null.</exception>
49+
/// <exception cref="ArgumentException">Thrown if <see paramref="delegateType"/> is not null.</exception>
50+
[Pure]
51+
public Delegate GetDelegateFromFunctionPointer(IntPtr functionPointer, Type delegateType)
52+
{
53+
return Marshal.GetDelegateForFunctionPointer(functionPointer, delegateType);
54+
}
55+
56+
/// <summary>
57+
/// Gets a symbol pointer from the specified module.
58+
/// </summary>
59+
/// <param name="handle">Operating system handle to a library.</param>
60+
/// <param name="symbolName">Name of symbol to locate.</param>
61+
/// <returns>an error code.</returns>
62+
[DllImport("libdl.so.2")]
63+
#pragma warning disable SA1300 // Element should begin with upper-case letter
64+
private static extern IntPtr dlsym(IntPtr handle, [In]string symbolName);
65+
#pragma warning restore SA1300 // Element should begin with upper-case letter
66+
67+
/// <summary>
68+
/// Closes a library.
69+
/// </summary>
70+
/// <param name="handle">The library handle.</param>
71+
/// <returns>the error code.</returns>
72+
[DllImport("libdl.so.2")]
73+
#pragma warning disable SA1300 // Element should begin with upper-case letter
74+
private static extern int dlclose(IntPtr handle);
75+
#pragma warning restore SA1300 // Element should begin with upper-case letter
76+
}
77+
}

0 commit comments

Comments
 (0)