Java import certificate from website

April 9th, 2015 No comments

Making calls to a server with a self signed certificate might give you the following error:

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

To fix this we need to import the certificate of this website into our local keystore.

Default pw for the keystore is ‘changeit’.

openssl s_client -showcerts -connect www.example.com:443 < /dev/null | openssl x509 -outform DER > www.example.com.der
keytool -importcert -trustcacerts -alias www.example.com -file www.example.com.der -keystore <path_to_keystore>
Categories: Uncategorized Tags:

Maven 3, deploy file with scp

March 7th, 2014 No comments

By default maven 3 will only allow you to upload files by means of http.

This mean that deploying through scp will not work. My settings.xml contains the servers to which I want to upload through scp.

Settings.xml

<settings>
    <servers>
        <server>
            <id>sample-server-id</id>
            <username>myUsername</username>
            <password>myPassword</password>
        </server>
    </servers>
    <profiles>
	<profile>
            <id>default-profile</id>
            <activation>
                <activeByDefault>true</activeByDefault>
            </activation>
	    <repositories>
		<repository>
			<id>sample-server-id</id>
			<name>A sample repository</name>
			<url>scp://builds.example.org/maven</url>
		</repository>
	    </repositories>
	</profile>
    </profiles>
</settings>

Deploying the file with mvn deploy:deploy-file will give an error when using scp as the protocol.

mvn deploy:deploy-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.4 -DrepositoryId=sample-server-id -Dfile=ojdbc6.jar -Durl=scp://builds.example.org/maven
No connector available to access repository

To fix this we need to create a dummy pom.xml. The most important part is to add the ssh wagon to enable scp.

<project> 
	<modelVersion>4.0.0</modelVersion> 
	<groupId>com.oracle</groupId> 
	<artifactId>jdbc-driver</artifactId> 
	<version>11.2.0.4</version> 
	<build>
		<extensions>
			<extension>
				<groupId>org.apache.maven.wagon</groupId>
				<artifactId>wagon-ssh</artifactId>
				<version>2.6</version>
			</extension>
		</extensions>
	</build>
</project>

Now rerun the command:

mvn deploy:deploy-file -DgroupId=com.oracle -DartifactId=ojdbc6 -Dversion=11.2.0.4 -DrepositoryId=sample-server-id -Dfile=ojdbc6.jar -Durl=scp://builds.example.org/maven

Hopefully it will now show:

[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
Categories: Uncategorized Tags:

AngularJS Clearable Input Directive

March 2nd, 2014 No comments

I wanted a clearable input field. It is supposed to show a close icon when input is typed into the input field. It was inspired by the following discussion on stackoverflow.

It consists of three parts:

1) The image for the close icon. Just take any one you like. I used this one. cross
2) The required CSS.

.clearable {
    background: url(/images/icons/cross.png) no-repeat right 5px center;
}
 
.clearable.onX {
    cursor: pointer;
}

3) The required AngularJS directive

app.directive('clearable', function($parse) {
    var link = function link(scope, element, attrs) {
        element.on('click', function() {
            if (element.hasClass("onX")) {
                scope.$apply(function(scope) {
                    $parse(attrs.clearable).assign(scope, null);
                });
            }
        });
 
        scope.$watch(attrs.clearable, function(val) {
            //console.log("Value is now: " + val);
            if (val) {
                element
                    .addClass('clearable')
                    .on('mousemove.clearable', function(event) {
                        if (this.offsetWidth - 18 < event.clientX - this.getBoundingClientRect().left) {
                            element.addClass('onX');
                        } else {
                            element.removeClass('onX');
                        }
                    });
            } else {
                element
                    .removeClass('clearable')
                    .off('mousemove.clearable');
            }
        });
    };
 
    return {
        restrict: "A",
        replace: false,
        transclude: false,
        link: link
    };
});

Use it by adding the following attribute to an input element:

<input type="text" ng-model="valueToObserve" clearable="valueToObserve" />

It will look like this.
clearable_input

Categories: Uncategorized Tags:

Maven and Grails

January 27th, 2014 No comments

I needed to push the generated Grails war into a maven repository. There are several ways to do this. I used the grails create-pom command (2.3.1) to create a pom.xml file. This seemed most logical to me.

Then I tried to do a mvn clean install from there to have it put in my local repo. This failed hard.

Fatal error forking Grails JVM: java.lang.reflect.InvocationTargetException

I changed the grails-maven-plugin to not fork to get a less cryptic description of the problem.

<plugin>
	<groupId>org.grails</groupId>
	<artifactId>grails-maven-plugin</artifactId>
	<version>${grails.version}</version>
	<configuration>
		<!-- Whether for Fork a JVM to run Grails commands -->
		<fork>false</fork>
	</configuration>
	<extensions>true</extensions>
</plugin>

This got me the actual error description:

Unable to start Grails: java.lang.reflect.InvocationTargetException: Provider org.apache.xerces.jaxp.SAXParserFactoryImpl not found

The dreaded xerces error.

I apparently had some unwanted dependencies. I executed a mvn dependency:tree to see if any of these were in use.
DynamicJasper seemed to be the culprit here. It contained a runtime dependency on xml-apis.

[INFO] +- ar.com.fdvs:DynamicJasper:jar:4.0.3:runtime
[INFO] |  \- net.sf.jasperreports:jasperreports:jar:4.1.1:runtime
[INFO] |     +- commons-digester:commons-digester:jar:1.7:runtime
[INFO] |     +- com.lowagie:itext:jar:2.1.7:runtime
[INFO] |     |  \- org.bouncycastle:bctsp-jdk14:jar:1.38:runtime
[INFO] |     |     +- org.bouncycastle:bcprov-jdk14:jar:1.38:runtime
[INFO] |     |     \- org.bouncycastle:bcmail-jdk14:jar:1.38:runtime
[INFO] |     +- jfree:jcommon:jar:1.0.15:runtime
[INFO] |     +- jfree:jfreechart:jar:1.0.12:runtime
[INFO] |     +- xml-apis:xml-apis:jar:1.3.02:runtime
[INFO] |     +- eclipse:jdtcore:jar:3.1.0:runtime
[INFO] |     +- org.codehaus.castor:castor:jar:1.2:runtime
[INFO] |     \- org.apache.poi:poi-ooxml:jar:3.6:runtime
[INFO] |        +- org.apache.poi:poi:jar:3.6:runtime
[INFO] |        \- org.apache.poi:poi-ooxml-schemas:jar:3.6:runtime
[INFO] |           +- org.apache.xmlbeans:xmlbeans:jar:2.3.0:runtime
[INFO] |           \- org.apache.geronimo.specs:geronimo-stax-api_1.0_spec:jar:1.0:runtime

I then dropped the dependency in my pom.xml:

<dependency>
	<groupId>ar.com.fdvs</groupId>
	<artifactId>DynamicJasper</artifactId>
	<version>4.0.3</version>
	<scope>runtime</scope>
	<exclusions>
		<exclusion>
			<groupId>xml-apis</groupId>
			<artifactId>xml-apis</artifactId>
		</exclusion>
	</exclusions>
</dependency>

After this I could install/deploy the artifact.

Categories: Grails Tags:

Blank screen during install

November 30th, 2013 No comments

I had some problems while installing Ubuntu/Linux Mint on a laptop. The screen went blank.
After some investigation it turned out that the backlight was turned off. (Intel GMA 4500m chipset)
To fix this I found two options that worked (default brightness buttons on laptop were not working)

Add the following boot options:

acpi_osi=Linux

This option allows me to use the brightness controls on the laptop and thus restore the brightness to a viewable state.
If that doesn’t work you could also turn off i915. That will allow you to pass the setup at first. Maybe install an OpenSSH server and then go in to output a acceptable value into the backlight.

i915.modeset=0

After this I created a init.d script called backlight to set the backlight to a valid value at boot.

First I got the current value:

cat /sys/class/backlight/intel_backlight/actual_brightness
72250

Use that in the backlight script.

#!/bin/sh
echo 72250 > /sys/class/backlight/intel_backlight/brightness

This will probably only work when acpi_osi=Linux during boot. You can add that option to grub later on.
Edit (/etc/default/grub) add the rule to GRUB_CMDLINE_LINUX_DEFAULT, GRUB_CMDLINE_LINUX or GRUB_CMDLINE_DEFAULT and run update-grub2 afterwards.

Make it executable.

chmod +x backlight

Make it run at different runlevels.

update-rc.d backlight defaults 00

That should restore the backlight at some point during boot. Not an ideal solution, but at least a working one.

Categories: Linux, Ubuntu Tags: , , ,

JPA with UUID

June 12th, 2013 2 comments

I wanted to have a data package containing only JPA annotations.

I created a base class specifying the keytype (I use UUID and Long based Entities):

package com.famvdploeg.data;
 
import java.io.Serializable;
 
/**
 * Absolute base class for persistable classes.
 * Contract forces get and set methods for id.
 * @author wytze
 * @param <KeyType>
 */
public abstract class Persistable<KeyType extends Serializable> {
	public abstract KeyType getId();
 
	public abstract void setId(KeyType id);
}
package com.famvdploeg.data;
 
import java.util.UUID;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
 
@MappedSuperclass
public abstract class UuidBasedEntity extends Persistable<UUID> {
 
	@Id
	private UUID id;
 
	@Override
	public UUID getId() {
		return id;
	}
 
	@Override
	public void setId(UUID id) {
		this.id = id;
	}
}

Sample entity:

package com.famvdploeg.data;
 
import java.io.Serializable;
import java.util.UUID;
import javax.persistence.Entity;
 
@Entity
public class Sample extends UuidBasedEntity implements Serializable {
 
	private String someExampleProperty;
 
        /* ... getters and setters */
}

All these entities go in one separate jar.

Next I create another package using the entity jar.

package com.famvdploeg.dao;
 
import com.famvdploeg.data.Persistable;
import java.io.Serializable;
 
public interface GenericRepository<Entity extends Persistable> {
	public void persist(Entity e);
	public Entity findById(Serializable id);
	public void merge(Entity t);
	public void remove(Serializable id);
	public Entity saveOrUpdate(Entity entity);
}

And a generic implementation of this dao: (Spring is used to inject the persistencecontext)

package com.famvdploeg.dao.jpa;
 
import java.io.Serializable;
import com.famvdploeg.dao.GenericRepository;
import com.famvdploeg.data.Persistable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
 
public class GenericJpaRepository<Entity extends Persistable> implements GenericRepository<Entity> {
 
	@PersistenceContext
	protected EntityManager em;
 
	@Override
	public void persist(Entity e) {
		em.persist(e);
	}
 
	@Override
	public Entity findById(Serializable id) {
		return em.find(returnEntityClass(), id);
	}
 
	@Override
	public void merge(Entity e) {
		em.merge(e);
	}
 
	@Override
	public void remove(Serializable id) {
		em.remove(findById(id));
	}
 
	@Override
	public void flush() {
		em.flush();
	}
 
	@Override
	public Entity saveOrUpdate(Entity entity) {
		if (entity.getId() == null) {
			em.persist(entity);
			return entity;
		} else {
			return em.merge(entity);
		}
	}
 
	protected List<Entity> findAll() {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Entity> cq = cb.createQuery(returnEntityClass());
 
		return em.createQuery(cq).getResultList();
	}
 
	protected Entity findByProperty(String property, Object value) {
		try {
			return em.createQuery(createQueryByProperty(property, value)).getSingleResult();
		} catch (NoResultException ex) {
			return null;
		}
	}
 
	protected List<Entity> findAllByProperty(String property, Object value) {
		return em.createQuery(createQueryByProperty(property, value)).getResultList();
	}
 
	protected Entity findByProperties(Map<String, Object> properties) {
		try {
			return em.createQuery(createQueryByProperties(properties)).getSingleResult();
		} catch (NoResultException ex) {
			return null;
		}
	}
 
	protected List<Entity> findAllByProperties(Map<String, Object> properties) {
		return em.createQuery(createQueryByProperties(properties)).getResultList();
	}
 
	public Class<Entity> returnEntityClass() {
		ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
		return (Class<Entity>) genericSuperclass.getActualTypeArguments()[0];
	}
 
	private CriteriaQuery<Entity> createQueryByProperty(String property, Object value) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Entity> cq = cb.createQuery(returnEntityClass());
		Root<Entity> root = cq.from(returnEntityClass());
		cq = cq.where(cb.equal(root.get(property), value));
		return cq;
	}
 
	private CriteriaQuery<Entity> createQueryByProperties(Map<String, Object> properties) {
		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<Entity> cq = cb.createQuery(returnEntityClass());
		Root<Entity> root = cq.from(returnEntityClass());
		for (Entry<String, Object> entry : properties.entrySet()) {
			cq = cq.where(cb.equal(root.get(entry.getKey()), entry.getValue()));
		}
		return cq;
	}
}

Now I want to use hibernate to map my UUID’s as PostgreSQL uuid type. We will add a mapping to do so.

(location: com/famvdploeg/data/CustomTypes.hbm.xml, place in DAO/Repository jar)

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<!--
		http://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/types.html
		Section 6.5 covers type registry and registerTypeOverride method on the Configuration object,
		typedefs are the preferred way of registering custom types
	-->
    <typedef name="java.util.UUID" class="org.hibernate.type.UUIDCharType" />
 
    <!-- 
        I want to store clob values as text and not as materialized clobs so we override that here.
        Otherwise the database will show long values when using an SQL tool to query the database.
    -->
    <typedef name="materialized_clob" class="org.hibernate.type.TextType" />
	<!-- Possible values:
	<typedef name="java.util.UUID" class="org.hibernate.type.UUIDBinaryTypee" />
	<typedef name="java.util.UUID" class="org.hibernate.type.UUIDCharType" />
	<typedef name="java.util.UUID" class="org.hibernate.type.PostgresUUIDType" />
	-->
</hibernate-mapping>

Next we fill the persistence.xml

(location: META-INF/persistence.xml)

<?xml version="1.0" encoding="UTF-8"?>
<persistence
	xmlns='http://java.sun.com/xml/ns/persistence'
	xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
	xsi:schemaLocation='http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd'
	version="2.0">
 
	<persistence-unit name="jpa-example-postgres" transaction-type="RESOURCE_LOCAL">
		<provider>org.hibernate.ejb.HibernatePersistence</provider>
 
		<class>com.famvdploeg.data.Sample</class>
 
		<properties>
			<!--<property name="hibernate.archive.autodetection" value="class, hbm"/>-->
			<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQL82Dialect" />
                        <!-- Use this only for testing!
			<property name="hibernate.hbm2ddl.auto" value="create-drop" />
                        -->
                        <!-- Nicer naming of tables with underscores fooName -> foo_name -->
			<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy" />
 
			<!-- Connection properties, moved to datasource (@see applicationContext.xml)
			<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/jpa_example" />
			<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
			<property name="hibernate.connection.username" value="example" />
			<property name="hibernate.connection.password" value="example" />
			-->
 
			<!-- c3p0 connection pooling, setup when creating datasource (@see com.mchange.v2.c3p0.ComboPooledDataSource)
			<property name="hibernate.c3p0.min_size">5</property>
			<property name="hibernate.c3p0.max_size">20</property>
			<property name="hibernate.c3p0.timeout">300</property>
			<property name="hibernate.c3p0.max_statements">50</property>
			<property name="hibernate.c3p0.idle_test_period">3000</property>
			-->
		</properties>
 
                <!-- The specific mapping for UUID's is added here -->
		<mapping-file>com/famvdploeg/data/CustomTypes.hbm.xml</mapping-file>
	</persistence-unit>
</persistence>

And for completeness the applicationContext.xml for Spring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:task="http://www.springframework.org/schema/task"
 
	xsi:schemaLocation="
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
       		http://www.springframework.org/schema/tx
       		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       		http://www.springframework.org/schema/aop
       		http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
			http://www.springframework.org/schema/task
			http://www.springframework.org/schema/task/spring-task-3.0.xsd">
 
	<!-- In production: <bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"> -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<!-- Test properties. Should be filled from Context.xml in production -->
		<property name="properties">
			<props>
				<!--
				<prop key="jpa-example-jdbc-url">jdbc:h2:mem:jpa_example</prop>
				<prop key="jpa-example-jdbc-username">sa</prop>
				<prop key="jpa-example-jdbc-password">sa</prop>
				<prop key="jpa-example-jdbc-driver">org.h2.Driver</prop>
				-->
				<prop key="jpa-example-jdbc-url">jdbc:postgresql://localhost:5432/jpa_example</prop>
				<prop key="jpa-example-jdbc-username">example</prop>
				<prop key="jpa-example-jdbc-password">example</prop>
				<prop key="jpa-example-jdbc-driver">org.postgresql.Driver</prop>
			</props>
		</property>
	</bean>
 
	<!-- Use pooled in production, @see com.mchange.v2.c3p0.ComboPooledDataSource -->
	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="url" value="${jpa-example-jdbc-url}" />
		<property name="username" value="${jpa-example-jdbc-username}" />
		<property name="password" value="${jpa-example-jdbc-password}" />
		<property name="driverClassName" value="${jpa-example-jdbc-driver}" />
	</bean>
 
	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="jpa-example-postgres" />
		<property name="dataSource" ref="dataSource" />
	</bean>
 
	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>
 
	<tx:annotation-driven transaction-manager="transactionManager" />
 
	<context:annotation-config />
</beans>

It is also possible to store the UUID as a char(36) to do this we need to change the type in the CustomTypes.hbm.xml to org.hibernate.type.UUIDCharType.
We can then modify the mapping from the data jar through adding an orm.xml to the META-INF folder. It will normally create a varchar(255) column but that is useless. We want to specify the use of an char(36) column as UUID’s are stored as Strings of a fixed length of 36 characters.

<?xml version="1.0" encoding="UTF-8"?>
 
<entity-mappings
  xmlns="http://java.sun.com/xml/ns/persistence/orm"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
  version="2.0">
 
	<package>com.famvdploeg.data</package>
 
	<mapped-superclass class="UuidBasedEntity" metadata-complete="false">
		<attributes>
			<id name="id">
				<column column-definition="char(36)" />
			</id>
		</attributes>
	</mapped-superclass>
</entity-mappings>

That’s it! Awesome! Clean separation of JPA and Hibernate.

Categories: Java Tags:

Grails easy JSON DTO’s

May 25th, 2013 No comments

Some JSON is only used in specific places. For these occurrences I use extension methods / meta methods to easily convert my classes into the required JSON without the need for a specific mapping/dto class. To do this I declare a Markup interface (called Mappable) on which the method can be invoked.

I put the following interface in src/groovy:

package com.example.json
 
/**
 * Markup interface so we can add extension methods to convert objects to maps.
 * @see MetaMethods.groovy
 */
interface Mappable {}

I then add the following to my MetaMethods class in src/groovy:

package com.example.json;
 
class MetaMethods {
    static void register() {
        Mappable.metaClass.toMap { whitelist, blacklist ->
            /* metaClass, class */
            def map = [:];
 
            /* id seems to be a special case */
            if (("id" in whitelist) || (!"id" in blacklist)) {
                map["id"] = delegate["id"];
            }
 
            if (whitelist) {
                whitelist.each {
                    map[it] = delegate[it]
                }
            } else if (blacklist) {
                delegate.properties.each { prop, val ->
                    if (!(prop in blacklist)) {
                        map[prop] = val;
                    }
                }
            }
            return map;
        }
    }
}

I register the metamethods in my Bootstrap.groovy

class BootStrap {
    def init = { servletContext ->
 
        /* Register our own Meta Methods/Extension Methods */
        MetaMethods.register();
    }
}

Now we can create easy JSON dto’s based on our domain (don’t forget to add the Mappable interface to your domain classes).

Usage example:

        def jsonMap = myDomainClass.toMap(["id", "propertyX", "propertyZ"], []); // 1st level properties
        jsonMap["customer"] = myDomainClass.customer ? myDomainClass.customer.toMap(["id", "fullName", "firstName", "insertion", "lastName"], []) : null; // 2nd level properties
        render jsonMap as JSON; // or as XML

Happy Grailing!

Setting up an OrientDB server on Ubuntu

January 19th, 2013 13 comments

Go to the directory you want to install OrientDB.

cd /opt

Download one of the two flavors of OrientDB (standard or graph edition). (If you don’t know which to take, pick the Graph Ed.)

sudo wget https://s3.amazonaws.com/orientdb/releases/orientdb-1.3.0.tar.gz
#sudo wget https://s3.amazonaws.com/orientdb/releases/orientdb-graphed-1.3.0.tar.gz

Unpack the file

sudo tar -zxvf orientdb-1.3.0.tar.gz

I usually remove the tar.gz file and add a symlink

sudo rm orientdb-1.3.0.tar.gz
sudo ln -s orientdb-1.3.0/ orientdb

Configure the default orientdb password. (I use vi, you use your own favorite editor ;))

sudo vi orientdb/config/orientdb-server-config.xml

Go to the section [orient-server > storages > storage] in the xml, change the default username and password and save the file

<!-- Default in-memory storage. Data are not saved permanently. -->
<storage path="memory:temp" name="temp" userName="yourUsername" userPassword="yourPassword" loaded-at-startup="true" />

Get the root password for later use or/and add your own preferred account in [orient-server > users]:
(I prefer to remove the root account and add a new one)

<user name="yourUsername" password="yourPassword" resources="*"/>

As the file is holding passwords it might be a good idea to remove the read permission for other users.

sudo chmod 640 /opt/orientdb/config/orientdb-server-config.xml

Create a user that will run the server:

# -d, --home-dir HOME_DIR       home directory of the new account
# -M, --no-create-home          do not create the user's home directory
# -r, --system                  create a system account
# -s, --shell SHELL             login shell of the new account (/bin/false =  no login)
# -U, --user-group              create a group with the same name as the user
sudo useradd -d /opt/orientdb -M -r -s /bin/false -U orientdb

Change ownership of orientdb directory/links:

sudo chown -R orientdb.orientdb orientdb*

Modify the user group rights so that users in the orientdb group can invoke shell scripts.

sudo chmod 775 /opt/orientdb/bin
sudo chmod g+x /opt/orientdb/bin/*.sh
sudo usermod -a -G orientdb yourUsername

Copy the init.d script:

sudo cp orientdb/bin/orientdb.sh /etc/init.d/

Update the init.d script with this sed script or just edit the file. (The copied one)

sudo sed -i "s|YOUR_ORIENTDB_INSTALLATION_PATH|/opt/orientdb|;s|USER_YOU_WANT_ORIENTDB_RUN_WITH|orientdb|" /etc/init.d/orientdb.sh

And change the following lines, we use sudo because our system account does not have a login shell.

# You have to SET the OrientDB installation directory here (if not already done so)
ORIENTDB_DIR="/opt/orientdb"
ORIENTDB_USER="orientdb"
 
#su -c "cd \"$ORIENTDB_DIR/bin\"; /usr/bin/nohup ./server.sh 1>../log/orientdb.log 2>../log/orientdb.err &" - $ORIENTDB_USER
sudo -u $ORIENTDB_USER sh -c "cd \"$ORIENTDB_DIR/bin\"; /usr/bin/nohup ./server.sh 1>../log/orientdb.log 2>../log/orientdb.err &"
 
#su -c "cd \"$ORIENTDB_DIR/bin\"; /usr/bin/nohup ./shutdown.sh 1>>../log/orientdb.log 2>>../log/orientdb.err &" - $ORIENTDB_USER
sudo -u $ORIENTDB_USER sh -c "cd \"$ORIENTDB_DIR/bin\"; /usr/bin/nohup ./shutdown.sh 1>>../log/orientdb.log 2>>../log/orientdb.err &"

Update the rc.d dirs

cd /etc/init.d
sudo update-rc.d orientdb.sh defaults

The server will now start and stop on startup/shutdown. For now we start it by hand.

sudo /etc/init.d/orientdb.sh start

Verify that it is running by opening the studio (e.g. http://localhost:2480/) or run ‘sudo /etc/init.d/orientdb.sh status’.

Now we can log in and create a new database,
Start the console:

/opt/orientdb/bin/console.sh

Create a new database:

create database remote:/yourDatabaseName yourUsername yourPassword local

Done. Grab a beer, you’ve earned it. 😉

PS3 Bluetooth Remote with XBMC on Linux

January 14th, 2013 No comments

SONY DSC
 
 
 
 
 
I used my PS3 bluetooth remote for a while to control my XBMC. But not all keys were mapped because by default the device is mapped as a HID device with only several buttons mapped to actual keys. I found this great howto to be able to use and program all buttons on the remote. Follow the basic steps there to build and install the bdremote driver.

I needed to modify several scripts a bit and added an extra script to be able to log the battery level. (And maybe in the future send some sort of notification when it is almost empty)
 
 
 
 
 
I modified the rc.local script a bit:
(Make sure you set your ID correctly, eg: 00:00:00:00:00:00)

#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
 
service bluetooth stop
sleep 1
/usr/local/bin/bdremoteng -a 00:00:00:00:00:00 -p 8888 -t 600 -b /home/yourusername/scripts/battery_change.sh &
sleep 1
mkdir /var/run/lirc
/usr/sbin/lircd -H null --connect 127.0.0.1:8888
sleep 1
service bluetooth start
ln -s /var/run/lirc/lircd /dev/lircd
exit 0

Used the default Lircmap.xml (~/.xbmc/userdata/Lircmap.xml):

<lircmap>
  <remote device="SonyBDRemote">
        <obc101>1</obc101>
        <obc102>2</obc102>
        <obc103>3</obc103>
        <obc104>4</obc104>
        <obc105>5</obc105>
        <obc106>6</obc106>
        <obc107>7</obc107>
        <obc108>8</obc108>
        <obc109>9</obc109>
        <obc110>0</obc110>
        <obc111>enter</obc111>
        <obc112>up</obc112>
        <obc113>right</obc113>
        <obc114>down</obc114>
        <obc115>left</obc115>
        <obc116>circle</obc116>
        <obc117>stop</obc117>
        <obc118>pause</obc118>
        <obc119>ps</obc119>
        <obc120>prev</obc120>
        <obc121>next</obc121>
        <obc122>play</obc122>
        <obc123>scanrev</obc123>
        <obc124>scanfwd</obc124>
        <obc125>cross</obc125>
        <obc126>eject</obc126>
        <obc127>select</obc127>
        <obc128>l3</obc128>
        <obc129>r3</obc129>
        <obc130>start</obc130>
        <obc131>l2</obc131>
        <obc132>r2</obc132>
        <obc133>l1</obc133>
        <obc134>r1</obc134>
        <obc135>triangle</obc135>
        <obc136>topmenu</obc136>
        <obc137>time</obc137>
        <obc138>square</obc138>
        <obc139>return</obc139>
        <obc140>clear</obc140>
        <obc141>popup</obc141>
        <obc142>steprev</obc142>
        <obc143>stepfwd</obc143>
        <obc144>subtitle</obc144>
        <obc145>audio</obc145>
        <obc146>angle</obc146>
        <obc147>display</obc147>
        <obc148>blue</obc148>
        <obc149>red</obc149>
        <obc150>green</obc150>
        <obc151>yellow</obc151>
  </remote>
</lircmap>

And I modified the keymap (~/.xbmc/userdata/keymaps/remote.xml) a bit:

<keymap>
 
  <global>
    <universalremote>
        <obc101>Number1</obc101>
        <obc102>Number2</obc102>
        <obc103>Number3</obc103>
        <obc104>Number4</obc104>
        <obc105>Number5</obc105>
        <obc106>Number6</obc106>
        <obc107>Number7</obc107>
        <obc108>Number8</obc108>
        <obc109>Number9</obc109>
        <obc110>Number0</obc110>
        <obc111>Select</obc111>
        <obc112>Up</obc112>
        <obc113>Right</obc113>
        <obc114>Down</obc114>
        <obc115>Left</obc115>
        <obc116>PreviousMenu</obc116>
        <obc117>Stop</obc117>
        <obc118>Pause</obc118>
        <obc119>XBMC.ActivateWindow(ShutDownMenu)</obc119>
        <obc120>SkipPrevious</obc120>
        <obc121>SkipNext</obc121>
        <obc122>Play</obc122>
        <obc123>Rewind</obc123>
        <obc124>FastForward</obc124>
        <obc125>Info</obc125>
        <obc126>XBMC.EjectTray()</obc126>
        <obc127>Playlist</obc127>
        <obc128>XBMC.updatelibrary(video)</obc128>
        <obc129>XBMC.updatelibrary(music)</obc129>
        <obc130>Queue</obc130>
        <obc131>VolumeDown</obc131>
        <obc132>VolumeUp</obc132>
        <obc133>PageUp</obc133>
        <obc134>PageDown</obc134>
        <obc135>ContextMenu</obc135>
        <obc136>ShowVideoMenu</obc136>
        <obc137>XBMC.ActivateWindow(settings)</obc137>
        <obc139>PreviousMenu</obc139>
        <obc140>BackSpace</obc140>
        <obc141>ContextMenu</obc141>
        <obc142>StepBack</obc142>
        <obc143>StepForward</obc143>
        <obc144>xbmc.activatewindow(pictures)</obc144>
        <obc145>xbmc.activatewindow(music)</obc145>
        <obc146>xbmc.activatewindow(video)</obc146>
        <obc147>FullScreen</obc147>
        <obc148>XBMC.ActivateWindow(favourites)</obc148>
        <obc149>ToggleWatched</obc149>
        <obc150>DecreaseRating</obc150>
        <obc151>IncreaseRating</obc151>
    </universalremote>
  </global>
 
  <fullscreenvideo>
    <universalremote>
        <obc135>XBMC.ActivateWindow(videoosd)</obc135>
        <obc138>CodecInfo</obc138>
        <obc111>AspectRatio</obc111>
        <obc116>FullScreen</obc116>
        <obc139>FullScreen</obc139>
        <obc144>NextSubtitle</obc144>
        <obc137>ShowTime</obc137>
        <obc145>AudioNextLanguage</obc145>
        <obc146>XBMC.ActivateWindow(OSDVideoSettings)</obc146>
        <obc151>XBMC.ActivateWindow(VideoBookmarks)</obc151>
        <obc112>BigStepForward</obc112>
        <obc113>StepForward</obc113>
        <obc114>BigStepBack</obc114>
        <obc115>StepBack</obc115>
    </universalremote>
  </fullscreenvideo>
 
  <visualisation>
    <universalremote>
        <obc135>XBMC.ActivateWindow(musicosd)</obc135>
        <obc138>CodecInfo</obc138>
        <obc139>FullScreen</obc139>
        <obc116>FullScreen</obc116>
        <obc137>Info</obc137>
        <obc145>XBMC.ActivateWindow(OSDAudioSettings)</obc145>
        <obc146>XBMC.ActivateWindow(visualisationsettings)</obc146>
        <obc144>XBMC.ActivateWindow(visualisationpresetlist)</obc144>
    </universalremote>
  </visualisation>
 
  <videoosd>
    <universalremote>
        <obc135>PreviousMenu</obc135>
        <obc137>ShowTime</obc137>
        <obc144>ShowSubtitles</obc144>
        <obc145>XBMC.ActivateWindow(OSDAudioSettings)</obc145>
        <obc146>XBMC.ActivateWindow(OSDVideoSettings)</obc146>
        <obc151>XBMC.ActivateWindow(VideoBookmarks)</obc151>
    </universalremote>
  </videoosd>
 
  <musicosd>
    <universalremote>
        <obc135>PreviousMenu</obc135>
        <obc137>Info</obc137>
        <obc145>XBMC.ActivateWindow(OSDAudioSettings)</obc145>
        <obc146>XBMC.ActivateWindow(visualisationsettings)</obc146>
        <obc144>XBMC.ActivateWindow(visualisationpresetlist)</obc144>
    </universalremote>
  </musicosd>
 
  <OSDVideoSettings>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
    </universalremote>
  </OSDVideoSettings>
 
  <VideoBookmarks>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
        <obc151>PreviousMenu</obc151>
    </universalremote>
  </VideoBookmarks>
 
  <OSDAudioSettings>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
    </universalremote>
  </OSDAudioSettings>
 
  <visualisationsettings>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
    </universalremote>
  </visualisationsettings>
 
  <visualisationpresetlist>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
    </universalremote>
  </visualisationpresetlist>
 
  <favourites>
    <universalremote>
        <obc137>PreviousMenu</obc137>
        <obc144>PreviousMenu</obc144>
        <obc145>PreviousMenu</obc145>
        <obc146>PreviousMenu</obc146>
        <obc148>PreviousMenu</obc148>
    </universalremote>
  </favourites>
 
  <videolibrary>
    <universalremote>
        <obc139>ParentDir</obc139>
        <obc138>ReplaceWindow(videofiles)</obc138>
    </universalremote>
  </videolibrary>
 
  <videofiles>
    <universalremote>
        <obc139>ParentDir</obc139>
        <obc138>ReplaceWindow(videolibrary)</obc138>
    </universalremote>
  </videofiles>
 
  <musiclibrary>
    <universalremote>
        <obc139>ParentDir</obc139>
        <obc138>ReplaceWindow(musicfiles)</obc138>
        <!--
        <obc102>FilterSMS2</obc102>
        <obc103>FilterSMS3</obc103>
        <obc104>FilterSMS4</obc104>
        <obc105>FilterSMS5</obc105>
        <obc106>FilterSMS6</obc106>
        <obc107>FilterSMS7</obc107>
        <obc108>FilterSMS8</obc108>
        <obc109>FilterSMS9</obc109>
        -->
    </universalremote>
  </musiclibrary>
 
  <musicfiles>
    <universalremote>
        <obc139>ParentDir</obc139>
        <obc138>ReplaceWindow(musiclibrary)</obc138>
        <!-- <obc102>FilterSMS2</obc102>
        <obc103>FilterSMS3</obc103>
        <obc104>FilterSMS4</obc104>
        <obc105>FilterSMS5</obc105>
        <obc106>FilterSMS6</obc106>
        <obc107>FilterSMS7</obc107>
        <obc108>FilterSMS8</obc108>
        <obc109>FilterSMS9</obc109>
        -->
    </universalremote>
  </musicfiles>
 
  <fullscreeninfo>
    <universalremote>
        <obc125>PreviousMenu</obc125>
        <obc137>PreviousMenu</obc137>
    </universalremote>
  </fullscreeninfo>
 
  <filemanager>
    <universalremote>
        <obc139>ParentDir</obc139>
        <!-- <obc102>FilterSMS2</obc102>
        <obc103>FilterSMS3</obc103>
        <obc104>FilterSMS4</obc104>
        <obc105>FilterSMS5</obc105>
        <obc106>FilterSMS6</obc106>
        <obc107>FilterSMS7</obc107>
        <obc108>FilterSMS8</obc108>
        <obc109>FilterSMS9</obc109>
        -->
    </universalremote>
  </filemanager>
 
  <pictures>
    <universalremote>
        <obc139>ParentDir</obc139>
    </universalremote>
  </pictures>
 
  <slideshow>
    <universalremote>
        <obc101>ZoomLevel1</obc101>
        <obc102>ZoomLevel2</obc102>
        <obc103>ZoomLevel3</obc103>
        <obc104>ZoomLevel4</obc104>
        <obc105>ZoomLevel5</obc105>
        <obc106>ZoomLevel6</obc106>
        <obc107>ZoomLevel7</obc107>
        <obc108>ZoomLevel8</obc108>
        <obc109>ZoomLevel9</obc109>
        <obc110>ZoomNormal</obc110>
    </universalremote>
  </slideshow>
 
  <virtualkeyboard>
      <universalremote>
        <obc139>BackSpace</obc139>
    </universalremote>
  </virtualkeyboard>
 
  <shutdownmenu>
    <universalremote>
        <obc119>PreviousMenu</obc119>
    </universalremote>
  </shutdownmenu>
 
  <home>
    <universalremote>
        <obc116>FullScreen</obc116>
        <obc139>FullScreen</obc139>
    </universalremote>
  </home>
 
</keymap>

And the battery_change.sh script:

#!/bin/sh
echo "Current battery level is: $2" > /home/yourusername/battery_level.txt

Happy XBMC-ing! 🙂

Categories: Linux Tags: , , , , ,

Raspberry Pi with Arch Linux

November 26th, 2012 1 comment

Installation on SD-card

Installed Arch Linux on my raspberry pi. I didn’t want any gui schmui and this image seemed like a pretty clean option to me.

Downloaded the image, checked the sha1sum and dd’ed the file onto an sd card. (Determined the /dev/yoursddevice name by doing an fdisk -l)

sudo dd bs=4M if=/path/to/your/image/arch-linux.img of=/dev/yoursddevice

Waiting a few minutes, drinking some beer. Done.

Expanding the root partition

My card was 4GB and the downloaded img is only 2GB. This would result in some unused space and I wanted to use it. Add another partition or resize the current. Now is a good time as the device is not in use.

sudo fdisk -uc /dev/mmcblk0
 
Command (m for help): p
 
Disk /dev/mmcblk0: 3904 MB, 3904897024 bytes
64 heads, 32 sectors/track, 3724 cylinders, total 7626752 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x0004f23a
 
        Device Boot      Start         End      Blocks   Id  System
/dev/mmcblk0p1   *        2048      186367       92160    c  W95 FAT32 (LBA)
/dev/mmcblk0p2          186368     3667967     1740800   83  Linux
 
Command (m for help): d
Partition number (1-4): 2
 
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4): 2
 
# !!! Make sure next value is the same as the start of the deleted partition !!!
First sector (186368-7626751, default 186368): 186368 <-- That value! Same in this case, but can be different.
Last sector, +sectors or +size{K,M,G} (186368-7626751, default 7626751): 
Using default value 7626751
 
Command (m for help): w
The partition table has been altered!
 
Calling ioctl() to re-read partition table.
Syncing disks.

Wanted to run resize2fs but it prompted me to run e2fsck first.

sudo e2fsck -f /dev/mmcblk0p2

Resize the partition. (-p shows progress bar)

sudo resize2fs -p /dev/mmcblk0p2

Awesome, full SD-card will be available now. Unmount and put it in the rpi.
(I used a microSDHC (4GB, class 4) card from kingston with adapter which didn’t work. So I bought a set of regular 4GB class 4 SDHC cards from kingston)

Wireless

In my first installations I just used the HDMI interface and an ethernet cable. Later I decided that it would be nice to have wifi as well. So I picked up an Edimax EW-7811Un Wireless USB Adapter.

You can set up your wireless interface in advance by mounting the new partition after writing the downloaded image with dd. Paths mentioned after this are of course relative to /mnt/sdcard

sudo mkdir /mnt/sdcard
sudo mount /dev/mmcblk0p2 /mnt/sdcard

To use it with the rpi I edited the /etc/conf.d/netcfg file and added ‘wireless-wlan0‘ to the networks array. I also added a DHCP_TIMEOUT=30 to allow for a bit more time for the wireless interface to get an IP-address.

# Enable these netcfg profiles at boot time.
#   - prefix an entry with a '@' to background its startup
#   - set to 'last' to restore the profiles running at the last shutdown
#   - set to 'menu' to present a menu (requires the dialog package)
# Network profiles are found in /etc/network.d
NETWORKS=(ethernet-eth0 wireless-wlan0)
 
# Specify the name of your wired interface for net-auto-wired
WIRED_INTERFACE="eth0"
 
# Specify the name of your wireless interface for net-auto-wireless
WIRELESS_INTERFACE="wlan0"
 
# Array of profiles that may be started by net-auto-wireless.
# When not specified, all wireless profiles are considered.
#AUTO_PROFILES=("profile1" "profile2")
 
DHCP_TIMEOUT=30

I then copied an example config:

cp /etc/network.d/examples/wireless-wpa /etc/network.d/wireless-wlan0

Originally it looks like this:

CONNECTION='wireless'
DESCRIPTION='A simple WPA encrypted wireless connection'
INTERFACE='wlan0'
SECURITY='wpa'
ESSID='MyNetwork'
## Uncomment if the supplied ESSID is hexadecimal
#ESSID_TYPE='hex'
KEY='WirelessKey'
IP='dhcp'
# Uncomment this if your ssid is hidden
#HIDDEN=yes

I only changed the ESSID and KEY values to match my wireless network settings. This is probably the most basic setup. For more advanced setups check out the netcfg and wireless sections in the arch wiki.

Reducing write cycles

I am not running any production-critical apps on my raspberry nor do I use any programs that require atime/relatime to be running. So I enabled the noatime option for the root partition and mounted /var/log as tmpfs as I don’t have any interest in these logs. (/tmp was already mounted as tmpfs)

My new /etc/fstab now looks like this:

#
# /etc/fstab: static file system information
#
# <file system>        <dir>         <type>    <options>          <dump> <pass>
/dev/mmcblk0p1  /boot           vfat    defaults        0       0
/dev/mmcblk0p2  /               ext4    defaults,noatime        0       0
tmpfs           /var/log        tmpfs   defaults,noatime,mode=0755,size=5%      0       0

Further installation

Inserting the sd-card into the Raspberry Pi. It booted okay. (If it is not check this list to see if your SD-card is compatible) Hostname was alarmpi at that moment so I just ssh-ed into it. You can scan with nmap if you don’t now which address your machine got. (Or check your router). Do this only when you have permission to scan the network. The command you could use looks something like this:

nmap -p 22 --open -sV 192.168.1.0/24 | less
# My raspberry was listed as:
# 22/tcp open  ssh     OpenSSH 6.1 (protocol 2.0)
# MAC Address: B8:27:EB:XX:XX:XX (Unknown)
ssh root@alarmpi
   #password = root, so you probably want to change that asap. :)
passwd
   #and then create a new user so you don't have to login with root
useradd -m yourUserName
passwd yourUserName

I then ran a system update to prevent unfound packages later on:

pacman -Syu

I then installed vim. As my favorite editor.

pacman -S vim
ln -s $(which vim) /usr/local/bin/vi
ln -s $(which vim) /usr/local/bin/view

Changed the hostname to something else. (jukepi in my case, I want to use this one as a jukebox)

vi /etc/hostname
    #alarmpi -> yourHostName

I then disabled root login with SSH. (After testing my new account worked)

vi /etc/ssh/sshd_config

Uncommented PermitRootLogin and changed to ‘no’

PermitRootLogin no

Save and restart sshd

systemctl restart sshd

Changed my timezone with tzselect

tzselect
    # Get the options

I modified /etc/timezone and added the outcome to the generic profile in /etc/profile

...
 
# Set our default path
PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin"
export PATH
 
# Set timezone
TZ="Europe/Amsterdam"
export TZ
 
# Load profiles from /etc/profile.d
...

Reloaded the profile

source /etc/profile

Modified the /etc/ntpd.conf by adding a few ntp server to sync with.

server 0.nl.pool.ntp.org
server 1.nl.pool.ntp.org
server 2.nl.pool.ntp.org
server 3.nl.pool.ntp.org

And restarted the ntpd daemon

systemctl restart openntpd

And checked if date was correct by running date.

date
#Mon Nov 26 22:46:14 CET 2012

Installed alsa-utils and mpg123 for sound

pacman -S alsa-utils mpg123

Make sound module to auto-load. (It isn’t by default)

vi /etc/modules-load.d/snd_bcm2835.conf
 
# Load Sound
snd_bcm2835

To play sound through jackplug: (Found this info here)

amixer cset numid=3 1

Or to play sound through HDMI:

amixer cset numid=3 2

Add your user to the audio group to have it play sounds.

usermod -G audio -a yourUserName

And test it if you like:

wget http://www.freespecialeffects.co.uk/soundfx/sirens/police_s.wav
aplay police_s.wav

If you get this error:

ALSA lib confmisc.c:768:(parse_card) cannot find card '0'
ALSA lib conf.c:4246:(_snd_config_evaluate) function snd_func_card_driver returned error: No such file or directory
ALSA lib confmisc.c:392:(snd_func_concat) error evaluating strings
ALSA lib conf.c:4246:(_snd_config_evaluate) function snd_func_concat returned error: No such file or directory
ALSA lib confmisc.c:1251:(snd_func_refer) error evaluating name
ALSA lib conf.c:4246:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory
ALSA lib conf.c:4725:(snd_config_expand) Evaluate error: No such file or directory
ALSA lib pcm.c:2217:(snd_pcm_open_noupdate) Unknown PCM default
aplay: main:696: audio open error: No such file or directory

Then you need to add your user to the audio group. 🙂

usermod -G audio -a yourUserName
 
# to apply the group directly, you can start a new login shell
# su -l yourUserName

VLC (As a service)

Because I couldn’t play every audio stream I decided to install vlc. (Which conveniently comes with a web interface)

pacman -S vlc

I got some 404 messages while installing for several packages so I looked them up on google and downloaded/installed them by hand. (Presumably because my install was not up-to-date atm. Run pacman -Syu to upgrade to latest version)

wget ftp://blablabla/missing-packagename-version.pkg.tar.armv6h.pkg.tar.gz
pacman -U missing-packagename-version.pkg.tar.armv6h.pkg.tar.gz
 
pacman -S vlc

After running cvlc I got some pulseaudio messages. Stating that it was missing. 🙂

pacman -S pulseaudio pulseaudio-alsa
 
# libao to make mpg123 work with pulse
pacman -S libao
# change /etc/libao.conf 'alsa' => 'pulse' to make it work with pulse

After that I rebooted to make sure everything was loaded/working ok. (And it did, used paplay police_s.wav to test)

I edited the vlc http .hosts file to allow access from my network:

vi /usr/share/vlc/lua/http/.hosts
 
# And added
192.168.1.0/24

To run vlc headless with http interface:

cvlc --intf http --http-host <yourIpHere> --http-port 8080 <fileName|streamUrl>

Running VLC + PulseAudio is lot heavier than just mpg123 (~40% for VLC + ~10% for Pulse vs ~10% mpg123) but I like the flexibility it gives me.

I want to create some kind of jukebox so the next thing to do is to create a systemd service to run vlc.
We will first create the script which we will place in /etc/rc.d

sudo vi /etc/rc.d/vlc
 
#!/bin/sh
 
case "$1" in
        start)
                echo "Starting VLC"
		su -l -c "/usr/bin/cvlc --intf http --http-port 8080 <fileName|streamUrl> &" <yourUsername>
                ;;
        stop)
                echo "Stopping VLC"
		killall vlc
		;;
        restart)
                $0 stop
                sleep 1
                $0 start
                ;;
        *)
                echo "usage: $0 {start|stop|restart}"
esac
exit 0

Now we will create a systemd service file.

vi /usr/lib/systemd/system/vlc.service
 
[Unit]
Description=VLC Daemon
Wants=iptables.service
After=iptables.service
 
[Service]
ExecStart=/etc/rc.d/vlc start
ExecReload=/etc/rc.d/vlc restart
ExecStop=/etc/rc.d/vlc stop
KillMode=process
 
[Install]
WantedBy=multi-user.target

The last step is enabling the service.

systemctl enable vlc.service

Google Go

The next one to install is Google Go. I wanted to be able to spend the rest of the cpu power as effectively as possible.
At the moment there is no (official) package available for Google Go so we will have to build it from source.
I used Dave Cheney’s excellent tutorial to install it but then for Arch Linux. (No need to install libc6-dev btw) I made symbolic links in /usr/bin to the compiled binaries go, godoc and gofmt.

Backup

After completing your setup it might be a good idea to create a backup which you can tuck away for a rainy day. My previous SD-card was unrecoverable after some ungrateful and ungraceful shutdowns. To be able to get the system up and running asap we will create a gzipped image. Shutdown your rpi gracefully and let’s create an image of the sd-card.

dd if=/dev/mmcblk0 conv=sync,noerror bs=1M | gzip -c  > /mnt/yourbackuplocation/rpi.img.gz

Restoring the file:

gunzip -c /mnt/yourbackuplocation/rpi.img.gz | dd of=/dev/mmcblk0 conv=sync,noerror bs=1M